1. 大模型三层架构到底在拆什么
1.1 从一个常见困惑说起
这两年做大模型应用开发的人,几乎都会经历一个相似的阶段:每隔几周就冒出一个新概念,今天是某个新的提示词框架,明天是某个新的智能体编排方案,后天又出来一个检索增强的变体。追着追着就发现,自己像在追一条永远追不上的尾巴,学了一堆名词,但真正落到项目里,还是不知道该怎么选、怎么搭。
我自己也踩过这个坑。最开始做对话类应用的时候,看到什么新方案都想往项目里塞,结果架构越堆越复杂,调试成本直线上升,最后发现真正决定效果的,根本不是那些花哨的编排层,而是两个最朴素的问题:你往模型里输入了什么,以及你拿到模型输出之后怎么处理。
把这句话再抽象一层,其实所有大模型应用,不管包装成什么形态,都可以拆成三层来看。这个拆法不是某个官方标准,而是我在多个项目里反复验证后总结出来的一套心智模型。它最大的价值在于:当你再看到一个新概念时,能立刻判断出它到底动的是哪一层,从而决定要不要跟、值不值得跟。
1.2 三层架构的整体轮廓
先把三层摆出来,后面再逐层展开。
| 层级 | 名称 | 核心职责 | 典型代表 |
|---|---|---|---|
| 第一层 | 输入层 | 决定模型看到什么 | 提示词、上下文拼接、检索结果、工具描述 |
| 第二层 | 模型层 | 决定模型怎么算 | 基座模型、微调权重、推理参数 |
| 第三层 | 输出层 | 决定结果怎么用 | 解析、校验、重试、格式化、后处理 |
很多人一上来就盯着第二层,觉得换个更强的模型就能解决一切。但实际项目里,第一层和第三层能撬动的效果,往往比换模型大得多,而且成本低、迭代快。原因很简单:模型层是别人训练好的,你能动的空间有限;而输入和输出这两层,完全掌握在你自己手里。
这个判断不是拍脑袋来的。我做过一个对比实验,同一个任务,固定模型不变,只优化输入层的上下文组织方式,准确率从六成出头提到了八成五以上;再叠加输出层的校验和重试机制,最终稳定在九成以上。整个过程没有动过一次模型权重,也没有换过基座。这就是三层拆解的实际意义——它告诉你力气该往哪儿使。
1.3 为什么这个拆法值得反复用
有人可能会问,市面上已经有那么多架构图了,为什么还要自己搞一套。我的体会是,大部分架构图是给“系统”画的,讲的是数据怎么流动、服务怎么部署;而三层拆解是给“效果”画的,讲的是模型行为怎么被影响。这两个视角不冲突,但解决的问题不一样。
当你遇到效果问题时,系统架构图帮不了你,因为它不会告诉你“为什么模型这次答偏了”。但三层拆解可以:先看输入层是不是给的信息不够或者有干扰,再看模型层是不是能力边界到了,最后看输出层是不是没做兜底。这个排查顺序,能帮你快速定位问题所在,而不是盲目地换模型、调参数。
所以这套拆法我用了两年多,从简单的文本分类到复杂的多轮工具调用,基本都能套进去。接下来就逐层拆开讲,每一层我会说清楚它管什么、怎么调、有哪些坑。
2. 输入层:决定模型看到什么
2.1 输入层的本质是信息筛选
输入层做的事情,说白了就一件:在模型有限的上下文窗口里,塞进最有用的信息,同时尽量不塞没用的。这件事听起来简单,做起来极难,因为“有用”和“没用”的边界,往往要试了才知道。
我见过太多项目,输入层就是简单地把用户问题往模板里一填就发出去了。这种做法的上限很低,因为模型拿到的信息量太少,只能靠自己的先验知识硬答。而先验知识是有边界的,一旦问题涉及私有数据、实时数据或者领域细节,模型就开始编。
输入层的优化空间,主要体现在三个维度上:信息的选择、信息的组织、信息的表达。这三个维度层层递进,每一层都能带来明显的效果提升。
2.2 信息选择:什么该放进去
信息选择是输入层的第一道关。核心原则是:只放和当前任务直接相关的信息,相关性越强越好,数量越少越好。
这里有个反直觉的点:很多人以为上下文给得越多,模型答得越准。实际恰恰相反。上下文过长会带来两个问题,一是稀释注意力,模型可能抓不住重点;二是引入噪声,无关信息会干扰判断。我做过测试,同一个问答任务,给模型三段相关文档和给十段文档(其中七段弱相关),前者的准确率反而更高。
那怎么判断相关性?常见做法是用检索。检索的本质就是信息选择,它帮你从海量数据里挑出最相关的那几条。但检索本身也有讲究,不是召回的越多越好。我的经验是,召回数量控制在三到五条,每条控制在几百字以内,这个区间在多数任务上表现最稳。超过这个量,边际收益急剧下降,甚至转负。
提示:检索的“相关”不等于“相似”。语义相似度高,不代表对回答有帮助。判断相关性时,最好结合任务目标来看,而不是只看向量距离。
2.3 信息组织:怎么摆放更有效
选好了信息,接下来是怎么摆。同样的几段内容,摆放顺序不同,模型的表现可能差出一大截。
一个被反复验证的规律是:把最关键的信息放在开头或结尾,中间放次要信息。这和人阅读长文档的习惯类似,开头和结尾的注意力最集中。模型虽然机制不同,但在长上下文里也表现出类似的“首尾偏好”。
另一个规律是结构化。把信息用清晰的分段、标题、列表组织起来,比一大段连续文本效果好。原因在于,结构化信息降低了模型解析的负担,它能更快定位到关键部分。我通常会用类似这样的组织方式:
【背景信息】 ...(相关事实) 【参考资料】 1. ...(第一条) 2. ...(第二条) 【当前问题】 ...(用户问题)这种分块方式,让模型一眼就能看出哪部分是事实、哪部分是问题,减少混淆。实测下来,比把所有内容揉成一段,准确率能高出十来个点。
2.4 信息表达:措辞的微妙影响
信息表达是输入层最容易被忽视、但影响很直接的一环。同样一个意思,换个说法,模型的表现可能完全不同。
最典型的是指令的明确程度。模糊的指令,比如“帮我看看这个”,模型只能猜;明确的指令,比如“判断下面这段话的情感是正面还是负面,只输出正面或负面”,模型就能精准执行。指令越具体,输出越可控,这是铁律。
还有一个技巧是给示例。在输入里放一两个输入输出示例,模型会模仿这个模式来回答。这在格式要求严格的任务上特别有用,比如要求输出特定结构的 JSON,给个示例比写一堆格式说明管用得多。
注意:示例要选有代表性的,别选边界情况。示例选偏了,模型会跟着偏。我一般会选最典型的一两个,而不是最难的。
2.5 输入层的常见误区
输入层最容易踩的坑,我总结下来有三个。
第一个是信息过载。前面说过,上下文不是越多越好。很多人怕模型信息不够,拼命往里塞,结果适得其反。判断标准很简单:如果一段信息删掉之后,模型回答不受影响,那它就是多余的。
第二个是指令和资料混在一起。把“你要做什么”和“这是参考资料”混在一段里,模型容易分不清哪些是指令、哪些是数据。分开写,用标记隔开,能避免这个问题。
第三个是忽视顺序。同样的信息,顺序不同效果不同,但很多人随手一拼就发出去了。花点时间调整顺序,把最重要的放首尾,收益很直接。
3. 模型层:决定模型怎么算
3.1 模型层能动的其实不多
模型层是三层里最“重”的一层,也是最难动的一层。对绝大多数应用开发者来说,基座模型是别人训练好的,你能做的只有选择和调用。所以这一层的核心问题不是“怎么训练”,而是“怎么选、怎么调”。
选模型这件事,很多人只看榜单排名,这其实是个误区。榜单测的是通用能力,而你的任务是具体的。一个在通用榜单上排第一的模型,在你的垂直任务上未必比排第十的好。选模型要看任务匹配度,而不是看排名。
我的做法是,先圈定几个候选模型,然后用自己任务的真实数据做小规模对比测试。测试集不用大,几十条有代表性的样本就够,重点看在自己任务上的表现,而不是看通用指标。这个测试花不了多少时间,但能避免选错模型带来的长期成本。
3.2 推理参数:几个真正有用的旋钮
选定模型后,能调的主要是推理参数。参数不少,但真正对效果有明显影响的,其实就那么几个。
温度是最常被提到的。它控制输出的随机性,温度低输出更确定,温度高输出更多样。我的经验是,需要准确、稳定的任务,温度调到接近零;需要创意、多样的任务,温度调到中等偏高。但要注意,温度不是越高越好,太高会导致输出发散、逻辑混乱。
最大输出长度也很关键。设得太短,回答会被截断;设得太长,模型可能啰嗦。根据任务类型来定,分类任务几十个 token 就够,长文生成则要留足空间。
重复惩罚在长文本生成时有用,能减少模型复读机式的重复。但惩罚系数别设太高,太高会让输出变得不自然。
| 参数 | 作用 | 推荐范围 | 适用场景 |
|---|---|---|---|
| 温度 | 控制随机性 | 0 到 1 | 准确任务取低,创意任务取中高 |
| 最大长度 | 限制输出长度 | 按任务定 | 分类取小,生成取大 |
| 重复惩罚 | 抑制重复 | 1.0 到 1.2 | 长文本生成 |
3.3 微调:什么时候值得做
微调是模型层里成本最高、门槛最高的操作,但也不是所有场景都值得做。我的判断标准是:当输入层和输出层都优化到极限,效果仍然不达标,且你有足够的高质量标注数据时,才考虑微调。
为什么把微调放这么后面?因为微调的成本不只是训练成本,还有数据标注成本、维护成本、迭代成本。而且微调后的模型,通用能力往往会下降,需要小心平衡。很多团队一上来就想微调,结果发现投入大量资源后,效果提升还不如把输入层优化一下。
微调真正适合的场景,是任务非常固定、格式要求非常严格、且通用模型怎么调都达不到要求的情况。比如特定的结构化抽取、特定风格的文本生成。这种场景下,微调能带来质变。
3.4 模型层的取舍逻辑
模型层的取舍,本质是在效果、成本、速度之间找平衡。更强的模型效果更好,但更贵、更慢;更小的模型更快、更便宜,但能力有限。
我的策略是分层使用。简单任务用小模型,复杂任务用大模型;或者先用小模型试,不行再升级到大模型。这种路由策略,能在保证效果的同时控制成本。实测下来,很多任务其实小模型就够用,没必要全都上大模型。
提示:模型选型别一次定死。业务在变,模型也在迭代,定期重新评估是必要的。我一般每季度会重新跑一次对比测试。
4. 输出层:决定结果怎么用
4.1 输出层是被低估的重灾区
如果说输入层是大家比较重视的,那输出层就是最容易被忽视的。很多人拿到模型输出,直接就用了,不做任何处理。这在 demo 阶段没问题,但一上生产就出问题。
模型输出有几个天然的不确定性:格式可能不对、内容可能有错、边界情况可能没覆盖。这些问题不处理,直接暴露给用户或下游系统,轻则体验差,重则出事故。输出层的价值,就是把这些不确定性兜住。
我见过一个项目,模型输出直接入库,结果某次模型多输出了一段解释文字,导致数据解析失败,整条链路卡住。如果输出层做了格式校验和清洗,这种问题根本不会发生。
4.2 解析:把输出变成可用的结构
解析是输出层的第一步。模型输出的是文本,但下游系统往往需要结构化数据。这一步要做的,就是把文本转成结构。
最常见的是 JSON 解析。让模型输出 JSON,然后解析成对象。但模型输出的 JSON 经常有问题,比如多了个逗号、少了引号、或者干脆包在 markdown 代码块里。所以解析不能直接json.loads,要先做清洗,去掉多余标记,再尝试解析,失败了要有兜底。
import json import re def parse_model_output(text): # 去掉 markdown 代码块标记 text = re.sub(r'```json|```', '', text).strip() try: return json.loads(text) except json.JSONDecodeError: # 尝试提取第一个 JSON 对象 match = re.search(r'\{.*\}', text, re.DOTALL) if match: try: return json.loads(match.group()) except json.JSONDecodeError: return None return None这段代码看着简单,但能挡掉大部分格式问题。关键是永远不要假设模型输出是完美的,一定要有兜底逻辑。
4.3 校验:把错误挡在门外
解析完之后是校验。校验分两层,一层是格式校验,一层是内容校验。
格式校验检查结构对不对,字段全不全,类型对不对。内容校验检查值合不合理,比如数值在不在范围内、枚举值在不在允许集合里。这两层校验做完,才能把数据交给下游。
校验失败怎么办?常见做法是重试。把校验失败的输出和错误信息一起塞回给模型,让它重新生成。重试一般设一到两次,太多会拖慢响应。如果重试还失败,就走兜底逻辑,比如返回默认值、转人工、或者给用户一个友好的提示。
注意:重试不是万能的。如果模型反复在同一个地方出错,说明输入层可能有问题,要回头检查输入,而不是无限重试。
4.4 后处理:让输出更自然
校验通过之后,还有一步后处理,目的是让输出更符合使用场景。后处理包括格式化、去重、补充、裁剪等。
比如模型输出了一段带 markdown 标记的文本,但你的展示场景不支持 markdown,就要去掉标记。再比如模型输出了重复的内容,要去重。这些处理看着琐碎,但直接影响用户体验。
还有一个重要的后处理是一致性检查。多轮对话里,模型这次说的和上次说的可能矛盾。后处理阶段可以做一致性校验,发现矛盾就标记出来,或者触发重新生成。这在需要连贯性的场景里很重要。
4.5 输出层的兜底设计
输出层最重要的设计原则是:永远假设模型会出错,并为此准备好兜底。
兜底分几个层次。第一层是重试,让模型自己修正。第二层是降级,用更保守的策略生成。第三层是兜底内容,比如返回一个默认回复。第四层是转人工,把处理不了的交给人工。
这四层兜底,能保证即使模型出问题,系统也不会崩。我做过统计,加了完整兜底之后,线上事故率下降了一个数量级。这个投入非常值得。
5. 三层联动:新花样到底新在哪
5.1 用三层框架识别新概念
回到开头的问题:怎么判断一个新概念值不值得跟。用三层框架一套,答案就清楚了。
如果它动的是输入层,比如新的提示词组织方式、新的检索策略,那大概率值得看,因为输入层优化成本低、见效快。如果它动的是输出层,比如新的解析校验方案、新的后处理流程,也值得看,因为输出层直接关系到稳定性。如果它动的是模型层,比如新的微调方法、新的推理技术,那要看你的资源和技术储备,门槛相对高。
这个判断方法,能帮你过滤掉大量噪音。很多所谓的新花样,拆开看不过是输入层或输出层的微调,核心思想早就有了,只是换了个包装。
5.2 三层之间的相互影响
三层不是孤立的,它们之间有相互影响。输入层给的信息变了,模型层的表现会变;输出层的处理方式变了,对输入层的要求也会变。
举个例子,如果你在输出层加了严格的结构校验,那输入层就要相应地把格式要求写得更清楚,减少模型出错的概率。反过来,如果输入层给了很清晰的示例,输出层的校验压力就小很多。这种联动关系,在优化时要一起考虑,不能只盯着一层改。
我的习惯是,每次优化都记录下改的是哪一层、效果变化多少。时间长了,就能积累出自己任务上的“敏感度地图”,知道哪一层的改动对自己任务影响最大。
5.3 一个完整的优化案例
说个具体的。之前做一个信息抽取任务,从非结构化文本里抽结构化字段。一开始效果很差,准确率不到六成。
按三层拆解排查:输入层,发现给的文本太长,关键信息被淹没,于是加了检索,只给相关段落;模型层,换了个更适合抽取任务的模型;输出层,加了字段校验和重试。
三步做完,准确率到了九成以上。其中贡献最大的是输入层的检索,其次是输出层的校验,模型层的贡献反而最小。这个结果再次印证了:输入和输出这两层,才是应用开发者真正的主战场。
5.4 三层框架的边界
这套框架也不是万能的。它主要适用于“用现成模型做应用”的场景。如果你是从零训练模型,那模型层就是主战场,框架的重心要调整。
另外,框架是帮你理清思路的工具,不是教条。实际项目里,三层往往要一起调,反复迭代。别指望一次就把三层都调到最优,那是理想情况。真实情况是,先调输入层,看效果;再调输出层,看稳定性;最后才考虑模型层。这个顺序,能让你用最小的成本拿到最大的收益。
6. 实操中的经验与避坑
6.1 输入层的三个实操技巧
第一个技巧是先做减法再做加法。很多人优化输入层,第一反应是加东西,加示例、加背景、加约束。但更有效的做法是先减,把没用的去掉,看效果是不是反而更好。我做过好几次,删掉一半上下文,效果不降反升。
第二个技巧是用真实数据测。别用自己编的例子测,用线上真实的数据测。真实数据里的边界情况、噪声、多样性,是编不出来的。只有用真实数据测,才能发现真正的问题。
第三个技巧是记录每次改动。输入层的改动很微妙,改了什么、效果变了多少,不记录的话很快就忘了。我一般会维护一个简单的表格,记录改动内容、测试结果、结论。这个习惯帮我避免了很多重复踩坑。
6.2 输出层的避坑清单
输出层有几个坑,我列出来,你对照检查。
| 坑 | 表现 | 解法 |
|---|---|---|
| 不做解析直接使用 | 格式错误导致下游崩溃 | 加解析和清洗 |
| 校验太松 | 错误数据流入下游 | 加格式和内容校验 |
| 重试无上限 | 响应变慢甚至死循环 | 设重试上限和超时 |
| 无兜底 | 模型出错时系统无响应 | 设计多层兜底 |
| 后处理缺失 | 输出不自然、不一致 | 加格式化和一致性检查 |
这张表里的每一条,都是我真金白银踩出来的。尤其是重试无上限这条,曾经导致过一个线上问题,排查了半天才发现是重试逻辑没设上限。
6.3 模型层的选型心得
模型选型,我的心得是别追新,追稳。新模型出来,先别急着换,等它稳定一段时间,看看社区反馈,再决定要不要上。追新带来的收益,往往抵不上不稳定带来的成本。
另外,多模型备份是必要的。别把宝押在一个模型上,万一它出问题或者涨价,你还有退路。我一般会保持两到三个候选模型,定期测试,随时可以切换。
6.4 三层优化的优先级
最后说说优先级。我的建议是:输入层 > 输出层 > 模型层。
输入层优化成本最低、见效最快,应该最先做。输出层优化能提升稳定性,是上生产的必要条件。模型层优化成本最高,放在最后,且只在前面两层都做到位之后才考虑。
这个优先级不是绝对的,但作为一个默认策略,能帮你把有限的精力花在刀刃上。很多项目效果不好,不是模型不行,而是输入和输出这两层没做好。把这两层做扎实,效果自然就上来了。
这套三层拆解,我用了很久,也教给过不少人。它最大的价值不是告诉你具体怎么做,而是给你一个思考的框架,让你在面对层出不穷的新概念时,能快速判断、理性选择。新花样会一直有,但底层逻辑就那么几条。抓住这几条,就不会被带着跑。