首页 / 资讯中心 / 文章详情

大模型三层架构拆解:输入侧与输出侧的工程实践

大模型三层架构拆解:输入侧与输出侧的工程实践 ★ FEATURED ARTICLE
1. 从中间那层不可动说起三层架构的分工逻辑1.1 三层到底指哪三层我拆过不少大模型项目从最简单的聊天机器人到带RAG的文档助手再到跑工具调用的Agent最后发现一个特别朴素的规律不管前端炫成什么样模型服务的内部永远只有三层。第一层是输入层。模型本质上只认识一串离散的Token它看不到你的PDF、数据库、用户界面也感知不到你要它干什么。输入层干的事就是把你提供的原始信息从文件、文本、检索结果、图片、语音这些形态加工成模型能理解的一串Token序列。很多人以为输入层就是把prompt塞给模型太窄了。实际上RAG、系统提示词、上下文工程、多模态编码、Agent里的工具执行结果回填全都是输入层的活只是加工深度不一样。第二层是核心计算层。这是预训练阶段练出来的那一坨参数矩阵配合Transformer、注意力机制、KV Cache这些机制对输入Token做逐层计算输出下一个Token的概率分布。这一层说白了就是模型能力的底座你问什么它能答什么、懂多少知识、推理水平多高全看这一层。但这是最重的一层预训练成本高到普通人根本碰不了推理时也不可能在线改权重。第三层是输出层。模型计算层输出的东西本质上只是下一个Token的概率分布是一堆数字不是一个能直接在页面上展示的回答。输出层干的事就是从概率分布里采样出Token再把Token拼成文本、JSON、工具调用指令、图片描述最后送到应用侧去做校验、渲染、解析、执行。这三层的边界不用背概念你就记住一句话输入层解决模型能不能理解你要什么计算层解决模型本身懂不懂输出层解决模型的回答能不能被系统用起来。1.2 为什么产品创新几乎都发生在输入和输出两侧这两年AI圈子的热闹看起来每天都在出新东西。今天有人说RAG救了大模型幻觉明天有人说Agent才是未来后天又冒出来MCP这种工具协议。但如果你把每个新玩法往这三层框架里一放会发现一个很反直觉的事实几乎没有一个创新发生在中间的计算层。RAG改的是输入层它决定送进上下文窗口的材料是什么Function Calling改的是输出层它让模型从输出一段文字变成输出一个可执行的动作指令流式输出改的是输出层的传输形态提示词工程改的还是输入层Agent宏观上看是输入输出两层组成的循环回路。中间那层呢你还是用那个模型参数没变、注意力机制没变、知识上限也没变。这不是巧合而是成本结构决定的。中间层是沉没成本最高的地方一次预训练或者全参数微调要烧掉大量的算力和数据还得冒着模型能力倒退的风险。产品团队能做的就是在输入层想尽办法把任务包装得更精准、给更多上下文材料在输出层想尽办法把模型的原始输出转化成可用的系统行为。这就是为什么同一个模型在A团队手里是客服机器人在B团队手里是代码审查工具在C团队手里是数据分析Agent。模型一样三层架构没变变的只有输入和输出侧的加工方式。记住这个框架最大的价值在于以后看到任何一个AI项目你都不会再被花里胡哨的术语绕晕可以直接问一句它的输入层做了什么输出层做了什么。2. 输入侧不是花活而是把问题翻译成Token的艺术2.1 RAG把数据库塞进输入上下文RAG是输入层改造里最典型的例子。它的名字叫检索增强生成听起来很高端本质上就是在模型开口之前先帮它把相关的资料查好作为上下文的一部分喂进去。实操上RAG分两步。第一步是离线索引把你的知识库文档切块每块做向量化存进向量数据库。第二步是在线查询用户问一个问题先用同一个embedding模型把问题转成向量去向量库里做相似度检索取Top-K个片段然后把用户问题 检索出来的片段 系统提示词拼合成一个完整的输入序列交给模型。这里有个关键点很多人会忽略RAG的效果好与坏其实取决于输入层把检索材料整理得够不够干净。我见过不少项目向量库检索回来的片段互相对不上甚至有两个片段内容矛盾模型面对这样的输入输出自然就乱来了。所以做RAG不能只盯着要不要用RAG要盯着检索回来的内容值不值得被当作上下文。我在实际项目里总结了三个输入侧经验切块粒度不要盲目追求固定字数按语义边界切比如标题、段落、表格说清楚一块。检索结果里一定要带上文档标题、来源、页码这些元信息模型才能判断该信谁。如果检索回来的片段质量参差不齐宁可只塞两三条高置信度的也不要塞满整个上下文窗口。为什么RAG能有效因为它把模型从闭卷考试变成了开卷考试。模型参数里写死的知识可能过时、可能记错但你把准确资料摊在它面前它做的工作就从回忆变成了摘抄和组织。开卷考试永远比闭卷考试稳定这是输入层优化最核心的底层逻辑。2.2 提示词工程与上下文工程先管理好输入端的信息秩序提示词工程和上下文工程这两个词经常被混着用但它们的着力点其实不同。提示词工程管的是指令。系统提示词里写你是一个严谨的客服回答不得超过200字这是告诉模型用什么身份、什么语气、什么规则来回答。它解决的是怎么说话的问题。上下文工程管的是材料。你给模型塞一份长达几十页的日志、一个交互过的历史记录、一串用户画像这些都是上下文。它解决的是跟谁说话、基于什么说话的问题。我见过太多团队系统提示词写得像宪法一样长把各种规则、few-shot示例、格式要求全堆进去看起来是下了功夫。结果模型一上线就出问题。问题不在提示词写得不好而是提示词本身也是输入Token它会和上下文里的业务文本互相抢占注意力。尤其是上下文窗口长度有限的时候你把5000字的规则塞进去剩下的空间就没多少了模型还容易把规则里的琐碎细节误解成业务要求。实际操作中我的习惯是系统提示词控制在800字以内只保留角色、任务边界、输出格式这三类信息。业务知识、检索资料、历史对话放到用户消息侧去管理。两边分工明确输入侧的信息秩序就清楚了。有人会问上下文越长不是越好吗不是。上下文窗口有一个被低估的问题叫Lost in the Middle模型对开头和结尾的Token关注度高但对中间夹着的大量内容会视而不见。这意味着你把关键材料埋在几千Token的中间地带模型大概率会漏看。所以关键信息要么放在系统提示词末尾要么放在离用户问题最近的位置要么用明显的分隔符标出来。2.3 Agent把一个大任务拆成一连串的输入输出循环Agent是过去一年被讨论最多的概念放在三层框架里看它其实是输入层和输出层组成的一个循环机制。传统问答是单向的用户问一句话模型回一段文字结束。Agent则不一样它可以多轮调用工具。用户说帮我查一下这个订单的物流状态然后写一封催发货的邮件这时候模型先在输出层生成一个调用查询物流接口的指令系统拿到这个指令去执行接口再把接口返回的JSON结果作为新一轮的输入Token放回上下文模型看到物流数据后再次在输出层生成根据这些信息起草邮件的最终回答。你会发现Agent里的每一次工具调用结果本质上都是输入层的材料。模型并没有变聪明它只是在多轮循环里不停地看到新的上下文材料每一次看到的材料都是系统从外部世界帮它捞回来的。这就是为什么很多人问Agent和大模型推理有什么区别时我会说Agent不是新的推理模型它是一套输入输出管理机制让你能用同一个模型连续处理需要外部信息的任务。我在写Agent循环的时候会在输入层刻意把工具返回结果放在一个结构化的XML块或者JSON块里并在提示词里明确告诉模型下面是被调用工具返回的原始数据不是用户说的内容。这个小细节能大幅减少模型把工具结果误当成用户指令的问题。输入侧的加工手段也远不止这些。多模态输入图片、音频先要转成视觉、语音编码是输入层向量检索是输入层就连把用户的历史对话截断到最近10轮也是一种输入层裁剪策略。随便一个功能你只要能说清楚输入侧做了哪些处理基本就抓住了项目的一半。2.4 输入侧的常见翻车点输入侧出了问题表现是模型答非所问或者没有按规则做事。我列几个踩过的大坑第一上下文污染。比如用户历史对话里混进了一段系统报错信息模型分不清这是日志记录还是需要回答的内容跟着跑偏。解决办法是给不同类型的上下文加明确标记比如用system_log这种标签包起来让模型一眼认出这是外部数据。第二无效上下文占用窗口。业务里很常见的是把整个报表或者一整个数据库表结构全塞进去模型根本用不到反而把有用的信息挤出了注意力范围。解决思路是先做字段级裁剪只给模型跟当前意图相关的字段。第三检索结果的可信度问题。RAG的时候检索出来的片段可能来自权威资料也可能来自某篇质量很差的博客模型默认一视同仁。最好在输入侧把来源等级标注给模型比如以下内容来自公司官方文档优先级最高让模型心里有杆秤。第四多轮对话里的身份错乱。用户问一嘴天气又转去说业务需求模型可能把之前的天气内容也当成业务上下文。输入侧可以做意图分类分完再决定当前轮次向模型提供哪些历史上下文。输入层的核心原则用一句话概括不干净的信息不要给模型重要的信息不要埋在中间该标注身份的必须标清楚。3. 输出侧的核心命题从一句话到一个可被接管的系统3.1 结构化输出与JSON Mode很多人低估了输出层的复杂性。模型输出的是概率分布它并不知道你的系统需要什么。如果你的下游逻辑要拿模型的回答去更新数据库、调接口、渲染图表你首先需要的是一个稳定、可解析的结构化输出。最常用的手段是JSON Mode。你可以在系统提示词里要求模型只输出JSON格式也可以在API层开启JSON模式甚至可以用vLLM、llama.cpp等推理框架支持的guided decoding在解码阶段直接约束只能生成符合某个JSON Schema的Token序列从根本上杜绝格式错误。我实际用下来的经验是光靠提示词说输出JSON不够稳模型偶尔会输出Markdown代码块包着JSON或者在里面夹注释。用guided decoding把这些都卡死可靠性会好很多。如果所用的推理框架不支持约束解码那就在输出层加一道防线先用正则把Markdown代码块剥掉再用容错JSON解析器解析失败再重试一次并让模型修正。这里有个容易被忽略的细节结构化输出也会占用输出Token而且约束多了会影响回答的自然度和信息量。所以不是所有场景都要JSON。3.2 函数调用与工具调用让模型不只是说话而是发指令函数调用Function Calling或者说工具调用是我认为输出层最重要的创新。没有它模型永远只是一个善于说话的人有了它模型才能成为一个能干活的人。调用机制并不难理解。你在请求里声明一个工具清单每个工具描述清楚名字、功能、参数结构。模型在回答时生成的输出不是普通文本而是一个类似这样的结构{ tool_calls: [ { function: query_order_status, arguments: { order_id: A12345 } } ] }应用层解析这段输出提取tool_calls字段执行对应的函数再把返回结果作为输入回填给模型相当于跑完一次Agent循环。这相当于你把可控的操作空间暴露给了模型同时把可执行的动作边界卡在一个安全范围内。模型不能随便执行SQL或删除文件它只能调用你定义好的几个函数。这种设计很符合实际工程的需要安全性、可审计性都回来了。我在实际项目里会把工具调用参数解析当作一个专门的模块来处理。因为模型生成的参数偶尔会多一个逗号、少一个引号或者把字段名拼成大小写不一致。不要指望模型生成的结构永远标准输出层要做的是防御式解析失败了就让模型重新生成一次这通常比写一堆容错正则更省心。3.3 流式输出与中断控制聊天应用要做流式输出SSE这个不用多说。后端把模型生成过程产生的Token增量通过SSE持续推给前端前端一边接收一边渲染用户的体验才从干等几秒变成看着它打字。流式输出的实现要点有三个后端不能等到模型全部生成完才返回而是要拿到一个增量就直接推送给客户端。SSE协议格式要处理好每条消息以data:开头末尾空行分隔前端用EventSource或者fetch配ReadableStream来监听。要支持中断abort。如果用户在生成过程中点停止前端要发一个中断信号后端拿到信号后立即取消模型生成。这里要特别小心一个问题中断之后缓存里的内容还没写完不要把半截内容当作最终结果写入数据库。我见过有人把流式的中间态当成完整答案存了后面解析JSON怎么都失败排查了半天才发现是这个问题。流式输出的好处不只是体验它还让你有机会做边生成边处理比如模型输出JSON时前端收到{answer: ...这个片段就能先提取文本部分渲染出来等到完整JSON到达后再解析引用字段。这种组合拳很适合做RAG问答类的页面。3.4 输出侧的五类典型问题输出侧常见的坑我列一张表都是我真实遇到过的问题表现常见解法JSON截断输出到一半被max_tokens截断解析失败调大输出上限解析失败重试用guided decoding约束格式漂移时而JSON时而Markdown时而中文引号后处理器兜底输出schema约束内容虚构回答看起来合理但引用了不存在的来源输出侧做引用校验要求模型只引用输入材料拒绝回答因为安全规则太强合理问题也被拒调整系统提示词措辞输入侧做脱敏后再请求多次解析失败重试三次仍是坏JSON启动降温策略比如降低temperature重新采样你会发现这些问题的很多根源其实在输入层和计算层但修复的抓手几乎都在输出层。好的架构是输出层永远保持防御式心态默认模型会出错解析代码要稳失败就先重试而不是推翻整个流程。4. 一个实战拆解文档问答加Agent任务三层分别怎么落地4.1 场景一文档问答机器人的三层设计我最近在做的一个数据产品里需要让用户直接问自然语言来查报表数据。这个场景如果不拆层直接让大模型对着数据库表结构猜结果一定很惨。拆成三层就好办了。输入层做的事用户问题进来后先做一轮实体识别把上月华东区营收提取成时间上月、区域华东、指标营收然后根据识别结果去查询元数据表找到对应的数据表名和字段名最后拼成一个带有清晰限定条件的查询描述塞进上下文。计算层用一个中等规模的模型做语义理解它不需要记住业务表的长相只需要根据输入层已经加工好的材料和提示词生成对应的SQL语义描述或者直接生成一段对数据的总结。输出层要求模型输出一个JSON包含query_result_summary、sql、confidence三个字段。前端拿到结果后渲染成卡片同时把sql送去人工审计。整个链路里计算层几乎没花工夫所有产品体验的差异都来自输入层的实体识别与上下文组织以及输出层的结构化约束。4.2 场景二带工具调用的Agent循环另一个场景是订单客服Agent用户问我上周买的蓝牙耳机怎么还没发货。直接让模型回答它没有订单数据。用三层框架设计后的流程是这样的第一步输入层把用户ID和问题放进上下文同时注入工具清单描述包含query_order、create_refund_request这两个函数的定义。第二步模型在输出层决策是否需要调工具。这里模型生成的不再是普通文本而是一个tool_calls指令指向query_order参数是用户ID。第三步应用层执行工具拿到订单状态JSON然后作为新的输入层材料放回上下文。第四步模型看到工具返回结果后最终在输出层生成一段对用户的解释。如果用户要求退款模型还可以再走一轮create_refund_request调用。这个循环用代码写出来大概是这个意思messages [{role: system, content: SYSTEM_PROMPT_WITH_TOOLS}, {role: user, content: user_query}] while True: response chat_model(messages, toolsTOOLS) if response.get(tool_calls): tool_result execute_tool(response[tool_calls]) messages.append({role: assistant, content: response[content], tool_calls: response[tool_calls]}) messages.append({role: tool, content: tool_result}) continue # 没有tool_calls说明模型准备给最终答复 return response[content]这套写法的好处是Agent的所有行为都是可审计的。每一轮输入输出都留在Messages里出了问题可以直接追溯是模型选错工具、工具参数传错、还是工具返回数据有问题。4.3 三层视角带来的排查方法论项目跑起来之后一定会出各种奇奇怪怪的问题。三层框架最大的实用价值就是给你一张排查地图。我的做法是任何线上问题先按层分类定位现象优先查输入层优先查计算层优先查输出层答非所问是先看上下文是否污染、检索结果是否准确若输入没问题看模型是否吃透了指令输出侧一般不会导致答非所问回答内容错了但格式正常看材料是否过时、提示词是否有歧义看模型是否超出知识边界不用查解析失败、格式错误看提示词对格式约束是否明确极少查JSON解析、guided decoding、截断回答不动了、超时看是不是检索太慢看推理框架排队和显存看流式推送和abort逻辑这个表格不是我凭空画的是我被线上故障教育出来的。印象最深的一次用户一直反馈回答特别空泛我怎么看都以为是提示词不够清晰反复改了好几天没有任何效果。后来用三层框架一查才发现是上游数据源里某个字段权限没开RAG检索回来的核心材料全是空记录。问题根本不在模型而在输入层的材料供应链。排查顺序我固定是先查输入什么再查输出怎么处理最后才怀疑模型不行。因为输入和输出层的错误成本低、可修改性高而模型层的问题往往只能通过换模型、调参或者微调来解决代价大得多。5. 容易被误解的边界微调到底改的是哪一层5.1 微调、部署、上下文三个容易混淆的改动说到这肯定有人会问那微调呢微调不是改计算层吗不是可以提升大模型的能力吗这确实是个需要澄清的边界。微调确实会修改计算层的参数。但我们要看清楚微调的机制是在一个已经预训练好的模型基础上用一定数量的输入-输出对继续做有监督训练。它改变的是模型在特定任务上对特定输入模式的响应路径或者说它改变的是当输入长什么样时模型更倾向于输出什么。从三层架构的视角看微调介于两层之间它修改的是计算层的权重但它是通过大量构造输入-输出样本从输入和输出两端去影响计算层的分布。这也是为什么很多团队误以为微调可以解决所有问题实际上微调解决的核心问题通常是让模型更听话、更适应某种输入习惯、更符合某种输出风格但它并不能在计算层注入模型根本不知道的知识。举个例子你喂给模型十万条问答数据教它做历史考试题它能学会答题套路但当它遇到训练数据里没覆盖的新题目时该不会还是不会。因为新知识要靠预训练才能进入参数矩阵微调做不到无中生有。所以我的判断是能不动计算层就不动能把需求压到输入输出层解决就尽量在输入输出层解决。5.2 输入输出侧不是提示词的代名词还有一种常见的误读是既然创新集中在输入输出两侧那是不是只要把提示词写好别的都不用管了绝对不是。输入侧包含了提示词但不等于提示词。它还包括检索系统RAG的召回和精排上下文管理历史窗口、优先级、截断策略多模态预处理图像OCR、音频转写数据权限和安全过滤决定哪些材料能进上下文输出侧也不只是选一个解析器。它还包括结构化模式控制工具调用协议流式传输和中断后处理校验引用校验、敏感词检查、幻觉检测如果你把输入什么/输出怎么处理简单理解成把prompt写长一点、把response解析一下那就等于把三层架构这个工具的威力浪费了九成。5.3 边界认知带来的实际决策价值理解了边界做技术决策时思路会清晰不少。比如如果是用户反馈回答总是没有业务深度先别急着上大模型微调先检查输入侧有没有把业务材料、术语表、内部文档递给模型。数据都没喂进去指望模型靠参数里的常识回答业务细节不现实。如果是用户反馈回答总是不符合格式不要去调温度也不要去微调先优化输出侧的schema约束和解析兜底。如果是用户反馈同一个问题有时候对有时候错那大概率是输出侧采样随机性带来的波动可以考虑固定seed、降低temperature或者输出侧加一次自校验。如果是模型对某个专有领域的理解确实不行且你手里有大量高质量的问答数据再考虑用微调把领域范式固化下来。这套判断逻辑几乎适用于所有大模型落地方案。它让你不再被大模型很聪明这个幻觉牵着走而是回到工程视角去定位问题和优化。6. 最后再分享三个我自己常用的调试技巧6.1 技巧一用可控随机性区分知识问题和抽样问题遇到模型输出飘忽不定的时候先把temperature调成0把seed固定住然后连续跑三次。如果三次输出基本一致但还是错的那是知识或输入材料的问题去查输入层如果三次输出完全不一样那是采样随机性造成的去调输出层的解码参数或者加约束比换模型更有效。6.2 技巧二把完整输入打印出来看一遍绝大多数我看到的问题只要把真正送给模型的完整Messages打印出来瞬间就能找到答案。比如发现系统提示词后面跟了一大段检索出来的无关博客或者发现用户的历史对话里夹着上一轮的工具报错信息这种问题光靠改提示词是永远修不好的。我会在开发环境里加一个开关记录每一轮请求的完整输入Token内容排查问题时先看输入再看输出。这个习惯帮我省了一半以上的排查时间。6.3 技巧三输出侧永远留一条兜底路径不管前端还是后端都不要默认模型输出的结构是完美的。我的做法是每个输出处理模块都至少留两条路径一条正规路径按预期结构解析一条兜底路径解析失败时把原始文本原样展示给用户或者返回重新生成绝不让页面因为一个JSON解析异常直接崩掉。产品上线后兜底路径的使用率就是模型稳定性的一个量化指标比靠感觉判断靠谱得多。这三层架构的思维方式我用了很长时间才真正内化。它不解决某一个具体Bug但它能让所有AI相关的问题都有了一个归属地。我遇到任何新玩法的第一反应永远是先去拆它的输入层和输出层分别做了什么拆完了这个项目到底是什么水平心里基本就有数了。
阅读完成 · 觉得有帮助?
咨询建站