大模型应用三层架构:输入输出决定AI应用成败
1. 为什么“三层架构”是理解大模型应用的万能钥匙很多人第一次接触大模型应用开发时会被各种新名词砸晕提示工程、RAG、Agent、Function Calling、思维链、结构化输出、工作流编排……每隔几周就冒出一个新概念感觉永远追不完。但如果你把这些花样全部摊开来看会发现一个让人安心的事实几乎所有大模型应用本质上都在做同一件事——控制输入什么以及处理输出成什么。我刚开始做AI应用的时候也走过弯路。那时候每看到一个新技术就急着去学它的API、它的框架、它的最佳实践结果学了十几个工具之后反而更迷茫了因为不知道什么时候该用哪个。后来一个做架构的朋友点了我一句“你别管它叫什么名字你就问自己两个问题——你往模型里塞了什么模型吐出来的东西你做了什么加工”这句话一下子把很多问题理清了。所谓“三层架构”是我自己在多个项目中总结出来的一套分析框架。它把大模型应用拆成三个层次输入层你给模型看什么、怎么看、按什么顺序看模型层模型本身的能力边界和调用方式输出层模型吐出来的原始内容你如何解析、校验、加工、落地这三层里模型层其实是相对固定的——你选了什么模型它的能力上限就在那里。真正千变万化、也真正决定应用成败的是输入层和输出层。标题里说的“所有AI新花样只在输入什么/输出怎么处理”说的就是这个意思。这篇文章适合谁看如果你正在做AI应用开发或者准备把大模型接入自己的业务系统又或者你只是好奇那些眼花缭乱的AI产品到底是怎么搭出来的那这篇内容应该能帮你建立一个清晰的认知框架。我不会只讲概念每个层次都会配上实际的代码示例、参数说明和踩坑经验让你看完就能动手试。2. 输入层决定模型上限的隐形战场2.1 系统提示词不是“写一句话”那么简单很多人以为系统提示词就是写一段话告诉模型“你是一个专业的客服助手”然后就开始用了。但实际上系统提示词的结构化程度直接决定了模型输出的稳定性。我做过一个对比实验同样的任务从用户消息中提取订单号和问题类型用两种不同的系统提示词写法在同一个模型上跑100次结果差异非常大。第一种写法就是一句话你是一个客服助手请从用户消息中提取订单号和问题类型。第二种写法是结构化提示词## 角色 你是一个订单信息提取引擎只做信息提取不做任何额外解释。 ## 任务 从用户输入中提取以下字段 - order_id: 订单号格式为纯数字长度8-12位 - issue_type: 问题类型只能从以下枚举值中选择[物流查询, 退换货, 发票问题, 商品咨询, 投诉建议] ## 输出格式 严格输出JSON不要包含任何其他文字 {order_id: ..., issue_type: ...} ## 边界规则 - 如果用户消息中没有订单号order_id 填 null - 如果无法判断问题类型issue_type 填 其他 - 不要猜测不要编造只提取用户明确提到的信息跑100次的结果第一种写法的字段提取准确率大约在72%左右主要错误集中在问题类型判断上模型经常自己发挥输出“物流问题”而不是“物流查询”第二种写法的准确率稳定在96%以上而且输出格式几乎100%符合JSON规范。差别在哪里结构化提示词把“模糊的自然语言指令”变成了“接近代码的契约”。你明确告诉了模型你的角色边界在哪里、输出必须长什么样、遇到边界情况怎么处理。模型不需要“猜”你的意图它只需要执行。提示系统提示词里最值得花时间打磨的三个部分——角色定义限制模型不要越界、输出格式减少后处理成本、边界规则处理异常输入。这三块写清楚了后面能省掉大量调试时间。2.2 上下文注入的三种策略与选择逻辑大模型本身不知道你的业务数据所以你需要把相关信息“喂”给它。这就是上下文注入。常见的策略有三种各有适用场景。第一种全量注入。把相关文档全部塞进提示词里。这种做法最简单但有两个硬伤——一是Token成本高二是当文档很长时模型对中间部分的注意力会下降这就是常说的“lost in the middle”现象。我实测过一个场景给模型一篇8000字的文档让它回答一个细节问题如果关键信息在文档开头或结尾准确率能到90%以上如果关键信息在正中间准确率掉到60%左右。所以全量注入只适合文档短、信息密度高的场景。第二种检索增强注入RAG。先把文档切片存入向量数据库用户提问时检索最相关的几个片段只把这些片段注入提示词。这是目前最主流的做法。但RAG的效果高度依赖检索质量——如果检索出来的片段不包含答案模型再强也没用。我在实际项目中的经验是检索环节的优化空间比生成环节大得多。切片大小、重叠长度、检索数量、重排序策略每一个参数都会影响最终效果。第三种结构化注入。把业务数据从数据库里查出来以表格或JSON的形式注入。这种做法适合数据本身结构清晰的场景比如订单信息、用户画像、库存数据。相比RAG它的优势是精确——不会检索出无关内容但劣势是灵活性差只能处理预设好的查询。选择哪种策略核心看两个维度数据的结构化程度和查询的灵活程度。数据越结构化、查询越固定越适合结构化注入数据越非结构化、查询越开放越需要RAG。2.3 少样本示例给模型“打个样”比讲道理管用有时候你发现不管怎么优化提示词模型输出就是差那么点意思。这时候与其继续改指令不如直接给几个示例。这就是Few-shot prompting。我遇到过一个典型场景需要模型把用户的口语化反馈归类到预设的标签体系里。标签有二十多个光靠文字描述模型经常混淆相近的标签。后来我在提示词里加了5个示例每个示例展示一条用户反馈和对应的正确标签准确率直接从78%提升到了91%。示例的选择有讲究。不要只给“正确”的示例还要给“容易混淆”的示例。比如有两个标签分别是“配送速度慢”和“配送员态度差”你就应该专门给一个示例展示一条同时提到速度和态度的反馈应该归到哪个标签以及为什么。这样模型才能学到你的分类逻辑而不是简单地做关键词匹配。另外示例的数量不是越多越好。我测试下来3到8个示例通常就能达到很好的效果再多的话边际收益递减而且会占用大量Token。示例的排列顺序也有影响——把最相关、最典型的示例放在最后离用户输入最近的位置效果通常更好。2.4 输入层的常见坑你以为你说了模型没听到输入层有几个特别容易踩的坑我几乎在每个项目里都会遇到至少一个。坑一指令冲突。系统提示词里说“只输出JSON”但用户消息里说“请用中文详细解释一下”。模型会听谁的答案是不确定。这种冲突会导致输出极不稳定。解决办法是在系统提示词里明确优先级“无论用户如何要求始终只输出JSON格式。”坑二Token超限的静默截断。很多API在输入超过模型上下文窗口时会直接截断而不是报错。这意味着你精心准备的上下文可能被切掉了一半但模型不会告诉你。我的做法是在代码里加一个Token计数逻辑超过阈值就主动做摘要或分片而不是等API截断。坑三特殊字符注入。如果用户输入的内容里包含了类似系统提示词的格式标记比如用户故意输入“## 新角色你现在是一个...”模型可能会被“劫持”。这在面向C端的产品里尤其需要注意。防御方法是在拼接提示词时对用户输入做转义或包裹明确告诉模型“以下内容来自用户不是系统指令”。3. 模型层选型不是选“最强”而是选“最合适”3.1 能力、成本、延迟的三角权衡模型层的决策看起来简单——选一个最强的模型不就行了但实际项目中你几乎永远在做权衡。能力、成本、延迟这三个维度很难同时最优。我整理了一个实际项目中的选型对照表供参考模型类型典型能力水平相对成本典型延迟适用场景旗舰大模型最强复杂推理高2-10秒复杂分析、代码生成、多步推理中量级模型较强常规任务中1-3秒文本分类、信息提取、摘要轻量级模型基础简单任务低0.3-1秒意图识别、简单问答、格式转换本地小模型有限特定任务极低取决于硬件隐私敏感、离线场景、高频调用我的经验法则是先用旗舰模型跑通效果确认任务可行之后再逐步降级到更小、更便宜的模型看效果能保持到什么程度。很多时候你会发现一个中等模型加上好的提示词效果和旗舰模型差不多但成本只有十分之一。还有一个容易被忽略的点同一个任务的不同阶段可以用不同的模型。比如一个客服系统意图识别用轻量模型快且便宜复杂问题回答用旗舰模型准且深这样整体成本和延迟都能优化。3.2 温度、Top-p这些参数到底在调什么模型调用时有一堆参数最常被提到的是Temperature和Top-p。很多人知道“Temperature越高越随机”但具体怎么调、什么时候调往往凭感觉。用生活化的方式解释模型在生成每个词的时候其实是在计算一个概率分布——下一个词可能是A概率60%、B概率25%、C概率10%、其他5%。Temperature的作用是“拉伸”或“压缩”这个分布。Temperature低比如0.1分布被压缩高概率的词更容易被选中输出更确定、更保守Temperature高比如1.0分布被拉伸低概率的词也有机会被选中输出更多样、更有创意。Top-p则是另一种控制方式只从累积概率达到p的词里选。比如Top-p0.9就是把概率从高到低累加只保留累计到90%的那些词剩下的直接排除。实际怎么调我的经验是信息提取、分类、格式转换Temperature0Top-p1。要的就是确定性不要任何发挥。创意写作、头脑风暴Temperature0.7-1.0Top-p0.9-0.95。需要多样性。对话系统Temperature0.3-0.7。既要自然又不能太飘。代码生成Temperature0-0.2。代码需要精确不需要创意。注意Temperature和Top-p通常只需要调一个另一个保持默认。同时调两个会让效果变得难以预测。3.3 什么时候该用多模型协作单一模型搞不定的情况可以考虑多模型协作。常见的模式有两种。路由模式先用一个轻量模型判断任务类型然后路由到对应的专用模型。比如用户输入先经过一个分类器判断是“技术问题”还是“账单问题”然后分别交给不同的模型处理。这种模式的好处是每个模型只需要专注自己擅长的领域整体效果更好。链式模式一个模型的输出作为另一个模型的输入。比如先用模型A生成初稿再用模型B做审核和润色。这种模式适合对质量要求极高的场景但成本和延迟会翻倍。我个人的建议是除非单模型确实搞不定否则不要轻易上多模型。多模型带来的复杂度调用链路、错误处理、成本控制往往比想象中大。先把单模型的提示词优化到极致再考虑拆分。4. 输出层从“模型说了什么”到“系统能用什么”4.1 结构化输出让模型吐出来的东西能被代码直接消费模型输出的自然语言对人来说很好理解但对代码来说就是一堆字符串。如果你要把模型接入业务系统第一步就是让输出结构化。最直接的方式是在提示词里要求JSON输出。但这里有个坑模型输出的JSON不一定是合法JSON。它可能多一个逗号、少一个引号、或者在JSON外面包了一层“好的以下是提取结果”。我遇到过模型输出里包含中文引号的情况直接导致解析失败。解决办法有三个层次第一层提示词约束。明确说“只输出JSON不要包含任何其他文字”并给出格式示例。第二层代码容错。用正则表达式提取JSON部分或者用宽松的JSON解析器。比如Python里可以用json.loads配合异常处理失败时尝试提取第一个{到最后一个}之间的内容。第三层模型原生支持。现在很多模型API提供了结构化输出的原生支持比如指定response_format为JSON模式或者用Function Calling来约束输出格式。这种方式最可靠但需要模型支持。import json import re def parse_model_output(raw_text): # 第一层直接解析 try: return json.loads(raw_text) except json.JSONDecodeError: pass # 第二层提取JSON片段 match re.search(r\{.*\}, raw_text, re.DOTALL) if match: try: return json.loads(match.group()) except json.JSONDecodeError: pass # 第三层返回错误标记触发重试 return {error: parse_failed, raw: raw_text}4.2 校验与重试别让模型的“自信错误”溜进生产环境模型有个特点它输出错误答案的时候语气和输出正确答案时一样自信。如果你不做校验这些错误就会直接进入你的业务系统。校验分两种格式校验和内容校验。格式校验就是检查输出是否符合预期的结构——字段是否齐全、类型是否正确、枚举值是否在允许范围内。这部分用代码就能做成本低应该每次都做。内容校验更复杂一些需要判断模型输出的内容是否合理。比如模型提取了一个订单号你可以校验这个订单号在数据库里是否存在模型判断了一个问题类型你可以校验这个类型是否在预设的枚举列表里。如果校验不通过就触发重试——把错误信息反馈给模型让它重新生成。def validate_and_retry(model_call, input_text, max_retries3): for attempt in range(max_retries): raw model_call(input_text) parsed parse_model_output(raw) if parsed.get(error): input_text f上次输出格式错误请严格按JSON格式输出。原始输入{input_text} continue # 内容校验 if not validate_content(parsed): input_text f上次输出内容有误{parsed}。请重新提取。原始输入{input_text} continue return parsed return {error: max_retries_exceeded}重试不是万能的。如果重试三次都失败说明要么提示词有问题要么这个输入本身就不适合模型处理。这时候应该记录日志人工介入分析。4.3 后处理流水线把原始输出打磨成产品级内容模型输出经过校验之后往往还需要进一步加工才能变成最终产品。这就是后处理流水线。常见的后处理操作包括格式化把模型输出的Markdown转成HTML或者把纯文本按段落拆分敏感词过滤检查输出中是否包含不适宜的内容一致性检查确保输出和用户的历史对话不矛盾补充信息把模型输出和数据库里的其他信息合并缓存对相同或相似的输入缓存输出减少重复调用我做过一个内容生成项目模型输出的初稿大概有70%可以直接用剩下30%需要后处理。后处理流水线包括检查事实性错误和知识库比对、调整语气风格和品牌调性对齐、补充引用来源。这套流水线跑下来最终内容的可用率从70%提升到了95%以上。4.4 流式输出的处理技巧与坑流式输出Streaming是提升用户体验的重要手段——用户不用等模型全部生成完可以边生成边看。但流式输出给后处理带来了挑战你拿到的是一个个碎片而不是完整的JSON。处理流式输出的常见做法是在前端做增量渲染在后端做完整拼接。前端收到一个Token就显示一个Token让用户感觉响应很快后端同时把所有Token拼接起来等流结束后再做完整的校验和后处理。但这里有个坑如果模型在流式输出到一半时出错了比如网络中断你拿到的是一个不完整的输出。所以流式场景下校验逻辑需要能处理“不完整”的状态。我的做法是在流式输出的同时用一个缓冲区记录已输出的内容如果流异常结束就把缓冲区的内容当作不完整输出处理——要么丢弃要么标记为需要重试。5. 三层联动一个完整案例的拆解5.1 场景设定从用户反馈到工单自动创建假设我们要做一个系统用户用自然语言描述问题系统自动提取关键信息并创建工单。这个场景涉及输入层的提示词设计、模型层的选型、输出层的结构化解析和校验。输入层设计系统提示词需要明确角色、任务、输出格式和边界规则。用户输入是自由文本可能包含订单号、问题描述、情绪表达等各种信息。模型层选型这个任务属于信息提取类不需要复杂推理所以选中量级模型即可。Temperature设为0保证输出稳定。输出层设计要求模型输出JSON包含order_id、issue_type、urgency、summary四个字段。输出后需要校验order_id是否存在、issue_type是否在枚举范围内。5.2 输入层的具体设计## 角色 你是一个工单信息提取引擎。你的唯一任务是从用户消息中提取结构化信息。 ## 提取字段 - order_id: 订单号。用户可能用“订单号”“单号”“编号”等词引出。格式为8-12位数字。 - issue_type: 问题类型。只能从以下选项中选择[物流查询, 退换货, 发票问题, 商品咨询, 投诉建议, 其他] - urgency: 紧急程度。根据用户语气判断可选[高, 中, 低]。包含“急”“马上”“立刻”等词时选“高”。 - summary: 用一句话概括用户问题不超过30字。 ## 输出格式 严格输出以下JSON不要包含任何其他文字 {order_id: ..., issue_type: ..., urgency: ..., summary: ...} ## 边界规则 - 没有订单号时order_id 填 null - 无法判断问题类型时issue_type 填 其他 - 不要编造用户没有提到的信息5.3 输出层的校验逻辑VALID_ISSUE_TYPES [物流查询, 退换货, 发票问题, 商品咨询, 投诉建议, 其他] VALID_URGENCY [高, 中, 低] def validate_ticket(parsed): errors [] # 格式校验 if not isinstance(parsed.get(order_id), (str, type(None))): errors.append(order_id类型错误) if parsed.get(issue_type) not in VALID_ISSUE_TYPES: errors.append(fissue_type不在允许范围内{parsed.get(issue_type)}) if parsed.get(urgency) not in VALID_URGENCY: errors.append(furgency不在允许范围内{parsed.get(urgency)}) if not parsed.get(summary) or len(parsed[summary]) 30: errors.append(summary缺失或超长) # 内容校验订单号存在性检查需查数据库 if parsed.get(order_id): if not order_exists_in_db(parsed[order_id]): errors.append(f订单号不存在{parsed[order_id]}) return errors5.4 实测中的意外情况与处理在实际跑这个系统的时候我遇到了几个预料之外的情况。情况一用户一条消息里提到多个订单。比如“我昨天买的A商品还没到前天买的B商品想退货”。模型会怎么处理它可能只提取一个订单号也可能把两个订单号拼在一起。解决办法是在提示词里明确“如果用户提到多个订单只提取第一个提到的订单号并在summary中说明有多个订单。”情况二用户用图片或语音转文字文本质量很差。比如“我的dingdan号是12345678想tui货”。模型对拼音和错别字的鲁棒性还可以但order_id的提取可能会出错。这时候校验环节的“订单号存在性检查”就派上用场了——如果提取的订单号在数据库里不存在就触发重试或转人工。情况三模型把summary写得太长。虽然提示词说了“不超过30字”但模型有时候会忽略。这时候后处理环节需要做截断或者把超长的summary重新丢给模型做摘要。这些情况在测试环境不一定能遇到但上线之后一定会出现。所以我的建议是在输出层留好人工介入的接口。当自动处理失败时不要硬撑直接把原始输入和模型输出转给人工处理同时记录日志用于后续优化。6. 三层架构的边界与演进方向6.1 这套框架解释不了什么三层架构是一个分析框架不是万能公式。有些东西它解释不了或者说解释起来比较勉强。比如模型微调。微调改变的是模型本身的参数这属于模型层的事情但微调的效果又高度依赖训练数据的质量——而训练数据的构造本质上又是输入层和输出层的问题。所以微调其实是三层交织的不能简单归到某一层。再比如多模态。当输入不只是文本还包括图片、音频、视频时输入层的设计复杂度会指数级上升。图片怎么编码、音频怎么转文字、视频怎么抽帧这些都不是简单的“提示词优化”能解决的。还有Agent和工具调用。Agent的本质是让模型自己决定调用什么工具、按什么顺序调用。这看起来像是模型层的能力但Agent的效果很大程度上取决于工具的描述输入层和工具返回结果的处理输出层。所以Agent其实是三层架构的一个自然延伸而不是替代。6.2 当模型能力提升时哪一层会先被“吃掉”这是一个很有意思的问题。随着模型能力越来越强三层架构的哪一层会变得不重要我的判断是输入层的“技巧性”部分会逐渐被模型吃掉但“信息性”部分不会。什么意思以前我们需要用各种提示词技巧来引导模型比如“让我们一步步思考”现在新模型已经内置了推理能力不需要你教它怎么思考了。但“给模型提供什么信息”这件事模型自己解决不了——它不知道你的业务数据不知道你的用户历史这些还是需要你在输入层注入。输出层也是类似。模型越来越擅长按照指定格式输出JSON解析的容错需求会降低。但“输出之后怎么和业务系统对接”“怎么校验”“怎么处理异常”这些是工程问题模型再强也替代不了。所以我的结论是三层架构的框架会一直有效但每一层的具体工作内容会变化。以前花在“提示词技巧”上的时间以后可以花在“信息组织”和“工程集成”上。6.3 我个人的经验先把输入输出做扎实再考虑花哨的东西做了这么多AI应用项目我最大的体会是大部分效果问题根源都在输入层和输出层而不是模型不够强。我见过太多团队一上来就追求最新的模型、最热的框架、最复杂的Agent架构结果基础的信息提取都做不稳定。反过来那些把输入层的提示词打磨得很细致、把输出层的校验和后处理做得很扎实的团队即使用中等模型也能做出很可靠的产品。所以如果你刚开始做AI应用我的建议是先不要急着上RAG、上Agent、上多模型协作。先把一个简单的任务比如信息提取或文本分类的输入输出做到极致——提示词结构化、输出格式严格、校验逻辑完善、异常处理到位。这个过程会让你对模型的脾气有深刻的理解之后再扩展复杂场景心里就有底了。最后分享一个小技巧每次调试提示词的时候不要只看“成功案例”更要看“失败案例”。把模型输出错误的那些输入收集起来分析它们的共同点——是输入太模糊是提示词有歧义还是这个任务本身就不适合模型处理失败案例里藏着最有价值的优化线索。