如果你最近两年一直在做 AI 相关的应用,大概率会遇到一个共同困惑:明明单个模型调用很简单,组合起来做产品却总觉得别扭。Prompt 加长了效果不稳定、多个 Agent 协作分叉失控、一次对话的时间从几秒涨到几十秒、账单月底一看翻了十倍——这些问题的根源往往不在模型本身,而在你压根没有完成"AI 应用架构"的思考。
不夸张地说,绝大多数 AI 项目的翻车现场,翻的不是模型,是架构。把 LLM 当成 API 裸调,和把 LLM 当成系统里一个具备"不确定性"的组件去设计,走的是完全不同的两条路。我接触过好几个从 Demo 到上线阶段崩溃的项目,死法惊人一致:没有把上下文管理当成独立模块、没有给模型调用设计降级与容错、没有可视化全局的数据流。而这三点,恰恰是 AI 应用架构设计的核心命题。
这篇文章想做的事,是抛开 PPT 式的抽象概念,直接拆解一套可落地的"图解 AI 应用架构"方法论。所谓图解,不是让你画几张漂亮的架构图交差,而是用可视化思维重新审视 AI 应用的每一层:从模型接入、上下文工程、Agent 编排、工具调用,再到可观测性和成本控制。我会把我画图时常用的视角、踩过的坑、以及最终验证有效的模式讲清楚,你可以直接照着画,也可以拿它当脚手架去设计自己的系统。
1. AI 应用架构的分水岭:确定性系统 vs 不确定性系统
很多人在设计 AI 应用时犯的第一个根本性错误,是仍然用传统软件的确定性思维去套 LLM。传统架构里,每个函数只要输入相同,输出就必相同;每个模块的错误码是可枚举的;调用链路的耗时是可控的。而 LLM 加入后,这套假设几乎全部崩塌。你面对的不再是一台可预测的机器,而是一个概率性的文本生成引擎。
1.1 为什么"API 裸调"模式撑不过第二周
我见过太多 MVP 的起点是"调一下 OpenAI 的 API 或国内大模型接口,拿 JSON 回来,解析一下,展示"。这种模式做 Demo 没问题,但撑不过第二周。原因有三:第一,模型返回的格式不稳定,你让模型输出 JSON,它偶尔会夹带 Markdown 代码块标记,或者在中途截断,前端解析直接崩溃;第二,你没有上下文管理策略,每一轮对话都把历史消息全部塞进去,Token 消耗线性膨胀,到月底账单吓人;第三,没有任何降级方案,模型服务一抖动,你的应用就跟着一块抖动。
这些问题的本质,是你把模型当成了整个应用的主干,而不是把它当成一个"可替换的推理组件"。在架构图上,API 裸调的数据流是:用户请求 → HTTP 调用 LLM → 返回 → 展示。没有中间层、没有缓存、没有上下文管理器、没有输出校验器。这不是架构,这是串联电路——一个灯泡坏了,整条线全灭。
1.2 把 LLM 当"黑盒推理引擎"来看待
正确的架构心智,是把 LLM 当成一个黑盒推理引擎,输出的是"概率上最合理的文本",而不是"正确的结果"。基于这个心智,你需要围绕它构建四个缓冲层:
- 输入缓冲:把用户请求转换成结构化的、可供模型稳定理解的消息序列,进行敏感词过滤、指令注入防护、用户意图预分类。
- 输出缓冲:对模型输出做结构化解析、合法性校验、安全过滤,必要时触发重试或修复机制。
- 状态缓冲:管理对话状态、临时记忆、长短期记忆的读写,避免每次请求都从零开始。
- 故障缓冲:超时重试、模型降级、缓存命中、静态兜底回复。
这些缓冲层在架构图上的样子,是 LLM 被夹在中间——所有的请求必须先经过预处理管线,所有的响应必须先经过后处理管线——模型本身不直接对接业务逻辑。一个合格的 AI 应用架构图,画出来以后 LLM 应该被画在"中间靠右"的位置,而不是最左边入口处。
1.3 图解的第一原则:先画数据流,再画模块
我之前指导团队画架构图,发现大家普遍有个习惯:先画系统有哪些模块(Agent、RAG、Prompt Manager),再用箭头连起来。这个顺序其实是反的。正确的顺序是先画数据流——用户输入从哪里进入、经过哪些处理步骤、在哪一步调用模型、结果回到哪里——数据流顺了,模块之间的边界自然就清楚了。
这就像你要画一张城市交通图,先要明确人流从哪个站进、经过哪些换乘点、最后目的地是哪,而不是先画商场和写字楼。一个反例是我见过有人把架构图画成了一个所有模块互连的"蜘蛛网",Agent 连向量库、向量库连缓存、缓存连模型、模型又连 Agent……看着很热闹,但没有任何一张图能说清楚数据到底怎么从头流到尾。后来我让他换了一种画法:每一步处理都用一个圆角矩形,箭头只表示数据流转方向,凡是没参与这条数据流的模块,一律扔到旁边标注为"支撑服务"。图立刻变清爽了,架构问题也暴露出来了。
2. 图解架构的核心模块:一张图看清 AI 应用的全链路
这里我给出一个经过实战检验的 AI 应用架构参考分层。它不是标准答案,但适合 80% 的对话式、Agent 式、RAG 式应用。你画图时可以参照这个分层来落位,每画一个模块,就问自己一个问题:这个模块到底是干什么的?如果答不上来,就说明它不应该在这个架构里。
2.1 交互层:不止是聊天窗口
交互层是用户直接接触的部分,但很多架构图对这一层的设计过于单薄——一个手机图标、一个网页图标就完了。实际上交互层在 AI 应用里承担的任务比传统 UI 多得多。
流式输出是这一层必须画进去的第一个关键组件。LLM 生成动辄几百个 Token,如果等完整生成完再一把推给用户,体验会非常差,等你把几百字的完整文本推给前端,用户早以为页面卡死了。所以说交互层和 LLM 之间的连接必须是流式的,你可能需要一个 SSE 通道或 WebSocket 来做 Token 级推送,而不是一个普通的 HTTP JSON 响应。
多模态输入也是交互层需要考虑的。用户可能上传图片、文档链接甚至语音,这些输入要在交互层完成类型识别和预处理,再决定是走文本模型、视觉模型还是先做文件解析。如果你在设计架构图,这里的箭头至少有三条:文本进文本模型、图片进视觉模型、文档进解析服务。
第二个容易被忽略的是"中间状态反馈"。用户发出一个复杂请求,系统需要经过"召回 → 推理 → 生成 → 验证"多个步骤,全程可能要 20 秒。如果界面上一片空白,用户大概率会再发一条消息,导致两个请求互相干扰。架构设计上必须预留一个状态上报通道,让处理管线里各个节点能把进度、中间结果发出来,由交互层渲染成"正在读取资料""正在分析文档"等可见状态。这段设计很容易被忽略,但它对用户体验影响极大。
2.2 模型接入层:叫"接入"但绝不只是 SDK 封装
很多人把模型接入层理解成一个统一的 API 封装,即 you 调 OpenAI 还是一个国内模型都走同一个 SDK,通过切换基地址来换模型。这个理解太浅了。模型接入层真正的价值在于"策略",而不是"封装"。
第一个策略是模型路由。不同的请求应该走不同的模型:一个简单的分类任务用快速廉价的小模型即可,复杂推理必须用参数量更大的模型。在架构图里,模型接入层向上对接的是一个"意图分类器"的输出,它在拿到请求复杂度评估后,决定将请求路由给哪个模型。比如内部我在做项目时,固定用一个 7B 级别的模型来把用户请求分成"闲聊、问答、任务型、复杂分析",只有"复杂分析"才进入大模型的完整推理链。这么做成本直接降了一半,响应速度也快了一截。
第二个策略是模型降级和灾备。没有一个模型服务商会承诺 100% 可用,所以模型接入层必须包含一个可用性状态判断:如果主模型连续超时超过 N 次,就自动把流量切换给备用模型或备用供应商。架构图上这里应该画一个"模型健康状态表"或配置中心,容量和故障转移规则的配置集中管理。
第三个策略是统一输入输出格式适配。不同厂商的 API,参数命名不同、上下文窗口不同、系统提示词支持的格式不同,但你的业务层不应当感知到这些差异。模型接入层应该负责把业务层传入的标准消息格式,转换为各家 API 需要的数据结构,再把各家 API 返回的无结构文本,标准化成带有消耗 Token 数、延迟、状态码的固定结构。这样即使你第二天把某个模型换掉,业务层代码一行都不用动。
这些都做到了,模型接入层在架构图上就不是一个简单的矩形,而是一个包含路由引擎、状态管理、适配器集群的"内聚模块",它是整个 AI 应用的"发动机舱"。
2.3 上下文管理层:AI 应用最容易失控的模块
上下文管理是 AI 应用架构和传统应用架构差异最大的一层。传统应用的"状态管理"是把用户数据存进数据库,然后查询出来,每次都是确定性的。但 AI 应用的上下文管理面对的是:"哪些内容应该进入模型的视野?哪些是历史对话?哪些是知识库召回片段?它们之间谁更重要?总量超过了模型窗口怎么办?"
这层设计的好坏直接决定应用智商的上限。我在实践中把上下文管理拆成三个子模块:
- 短期会话记录器:维护当前对话窗口内的消息队列,负责截断、压缩、优先级排序。
- 长期记忆仓库:把用户的历史偏好、关键事实抽取成结构化条目,存入向量库或 KV 存储,下次对话时按需检索注入。
- 上下文构建器:把短期消息、长期记忆、RAG 召回内容、工具返回结果拼装成最终发送给模型的 Prompt。
这里有一个关键设计决策:上下文构建器必须遵守"越靠近输入的地方越重要"的原则——最新用户的指令、系统级约束必须固定在 Prompt 的首部或尾部,中间才是可被压缩的历史内容。如果你把一段历史对话塞在中间不打散,模型很可能在长上下文中"迷失"。
另外,我在生产环境中强力建议做"上下文压缩"。当成千上万的对话历史累积到超出窗口时,不要简单粗暴地把最早的记录扔掉,而是用一个摘要模型把老对话改写成一两句话的记忆摘要。这个摘要会保留关键信息和意图倾向,比直接截断好得多。架构图画到这里,你需要标出"摘要模型"这个节点,它是上下文管理层的内部组件。
注意:上下文管理层的失败模式是"上下文污染"。当来自不同来源的内容(历史、知识库、工具结果)混杂无序地拼进一个 Prompt 时,模型会分不清优先级,回答质量急剧下滑。在架构设计阶段,就要明确标注每类上下文的"权重区间"和"插入位置"。
2.4 工具层与 Agent 编排层:从"生成文本"到"采取行动"
如果应用只是对话和问答,到上下文管理层就可以打住了。但真正的 AI 应用高级形态必然涉及工具调用和 Agent 行为。工具层和编排层的设计,决定了你的 AI 是"会聊天的聊天机器人"还是"能帮用户解决问题的智能体"。
工具层的本质是"把 AI 的决策转化为可执行的操作"。一个工具在架构上需要有:名称、用途描述、参数 Schema、执行端点、鉴权信息。在设计工具层时,我建议所有工具执行都应该通过一层统一的"工具网关"——它来做参数校验、权限控制、执行超时、错误映射。不要允许模型直接通过函数调用来执行任意代码或访问任意资源。网关的作用像机场安检,模型画了一张"我要去登机口"的牌,但能不能过闸机,得由安检系统做最终决定。
Agent 编排层的核心是决策与控制。这里出现了两个路线:单 Agent + 工具循环,和多 Agent 协作。单 Agent 模式里,编排器就是一个循环——模型根据当前状态决定调用哪个工具,工具返回结果再喂给模型,循环往复直到任务完成或达到最大轮次。这张循环图在架构图上是最简单也最清晰的:User Input → Agent 决策 → 工具调用 → 结果回填 → 再次决策。
多 Agent 协作的复杂度就高多了。你需要一个调度中心来决定子任务的拆分、哪个 Agent 负责哪段、结果如何汇总。图解多 Agent 架构时,最容易画成五六个 Agent 相互乱连的群聊图,这种图基本没法指导开发。我更推荐的画法是:以调度者为中心,所有子 Agent 通过调度者间接通信,不建立直接的 Agent 间通道。子 Agent 的输入输出都走统一的"消息总线",调度者负责任务路由和结果合并。从实现角度看,也不需要用黄仁勋式的那种不知道什么格式的"高级协议",一个简单的 JSON 消息队列,加上严格的任务状态定义,就够了。
2.5 RAG 管线:检索增强生成也有自己的瓶颈
RAG 是 AI 应用架构里讨论度最高的模块,我这里不赘述它是什么,重点说图解架构时容易忽略的三个节点。
*第一是文档解析与结构化节点。*一堆 PDF、Word、Excel 进来,不是直接切成文本块就完事了。你需要识别标题层级、表格结构、图片中的文字,为每个文本块打上与之关联的文档 ID、页码、章节等元数据。这些元数据在后续检索时会非常有用。
*第二是在线检索与重排序节点。*用向量相似度检索出的 Top-K 结果,往往混着噪音。一个独立的重排序(Rerank)节点,用交叉编码器重新计算检索结果与查询的相关性,能显著提升最终喂给模型的片段质量。很多架构图画到向量检索就停了,少了重排序这一步,RAG 的效果会打折。
*第三是引用溯源节点。*架构图上必须有"引用来源"的输出接口。用户在界面上看到回答时,应当能点开一个引用的文档原文。这不仅是体验问题,也是合规责任的底线。设计上,文本块在进入向量库时就要保留原始文档 ID 与片段位置,生成的回答里通过字符串匹配或元数据注入,把引用标记串联起来。
3. 图解的一手视角:一张 AI 应用架构图怎样才算"合格"
前面把模块讲全了,但很多读者真正关心的问题其实是:我这图要怎么画才像回事?我面试过不少候选人,也给别人做过代码评审,见了太多"不合格的架构图"。这里直接列出几条我判断"合格"的硬性标准。
3.1 自顶向下的层级感必须清晰
一张合格的 AI 应用架构图,首先层级感必须一目了然。通常从上到下是:交互接入层 → 应用服务层(业务逻辑、会话管理) → AI 能力层(上下文构建、Agent 编排、RAG 管线) → 模型接入层 → 基础设施(向量库、缓存、消息队列、对象存储)。每一层横向铺开,层与层之间用明确的箭头标注协议或数据类型,而不是一层一个色块摆在那里。
我在画图时有个习惯:每一层用一个统一的底色,层内的矩形是具体模块,外部依赖(如第三方 API、数据库)用不同颜色,并在图例里标明区别。这样即使一个完全没参与项目的人,拿过图来 30 秒内就能看出请求是从哪里进来的、流程走了哪些关键节点、外部依赖有哪些。
3.2 图中必须标注"关键信任边界"
AI 应用要面对一种与传统应用不同的威胁:模型注入。恶意用户可以通过精心构造的 Prompt,试图让模型忽略系统指令、泄露系统提示词、或者执行越权工具调用。架构图上必须明确画出"信任边界"——哪些输入被视为不可信,哪些模块是安全边界。
正常情况下,用户的输入始终是不可信的,交互层和数据进入内部环境之前,必须经过指令注入防护、内容过滤、参数校验。模型返回的内容同样不可信:模型可能在输出里包含恶意链接或编造的"事实",输出解析后过一层校验器才能进入业务逻辑。这条信任边界你在图上画出来了,等于在架构评审时把安全责任写在了明面上,实现时就不会漏。
3.3 每个箭头都要回答三个问题
我最烦的是架构图上密密麻麻全是箭头,但说不清每个箭头代表什么。建议画完图后自查,任意挑一根箭头,回答三个问题:它传递的是什么数据?数据格式是什么?这个传输是同步还是异步?如果三分钟答不上来,这个箭头就是画错了的,或者是多余的。
比如 Agent 编排层到工具网关的箭头,你要能说清楚:这是调用了什么工具、参数以什么结构传递、是 encode 请求还是异步任务下发;模型接入层到模型的箭头,你要能说清楚:这是用什么协议发的请求、载荷里包含什么、返回是流式还是非流式。这样做的好处是,架构图从"装饰图"变成了"实施蓝图的索引",开发人员不需要靠猜来补齐实现细节。
4. 实战拆解:三个典型 AI 应用场景的架构图解
讲完原则,我带你拆解三个真实场景的架构设计。这三个场景覆盖了大多数 AI 应用的需求:简单客服助手(单模型 + RAG)、需要写文案和做数据分析的复杂 Agent(多工具 + 多轮规划)、以及一个高并发的企业级知识问答系统(多模型路由 + 缓存 + 异步管线)。
我不用那种只有很抽象箭头的泛泛架构图,而是采用表格 + 步骤拆解的方式,把每个场景的关键链路、瓶颈和设计决策写清楚。
4.1 场景一:基于 RAG 的客服助手
这是最典型的新手项目,在架构上符合"主流模式",但做好的话也有不少细节。数据流大致是:用户提问 → 改写优化 → 向量检索 + 关键词检索 → 重排序 → 拼装上下文 → 调 LLM → 返回答案和引用。
这里最容易被新手忽略的是"检索改写"。直接用用户的原话去检索,效果往往不好,因为口语里带语气词、指代关系,比如"那个怎么弄来着"。所以在进入检索之前,用一个轻量模型做一次查询改写,把口语转换成适合检索的书面表述,检索准确率会提高一大截。
这套架构里还有一个容易出问题的环节——知识库更新。知识库里的文档不是永远不变的,产品文档更新后,旧的切片如果还留在向量库里,就会和新的切片产生语义冲突。所以架构图上必须画出一条"知识摄入更新管线":文档入库 → 解析 → 切片 → 向量化 → 入库 / 更新 / 删除。很多项目的 RAG 架构图里没有这条管线,导致上线后知识库越用越脏,回答质量一天不如一天。
4.2 场景二:多工具 + 多轮规划的智能 Agent
第二个场景是企业里一个"内容中台助手",它能根据用户的一句话,完成"调研资料 → 写大纲 → 生成 PPT 文案 → 配图建议"的完整任务。这类 Agent 的架构核心是"计划 → 执行 → 观察 → 再计划"的循环,但和简单的工具调用不同的是,它需要多轮规划,而且每一步都可能产生中间文件。
它的架构图解应该是这样的:用户指令进入一个"任务规划器",规划器把大任务拆解成子任务清单,生成一个依赖图;然后进入"执行调度器",调度器按依赖顺序(有并行就并行)把子任务分发到不同的执行器。执行器由工具网关调用具体工具:搜索引擎、文档库、内部画布 API、图像生成服务等。每个子任务执行完后,结果回传到调度器,更新任务状态。直到所有子任务完成,最终产出一份完整的输出。
这里面"任务状态管理"是体验的决定性因素。任务状态不能全部内存存——进程一重启就全没了,至少需要一个 Redis 或数据库表来存状态机。用户刷新页面后,能通过一个任务 ID 查询进度和中间结果。架构图上这一层要放在"应用服务层",用一个"任务状态存储"组件表示。
我在做这类项目中踩过的最大坑是:不要把"工具的选择权"完全交给模型。如果让模型每一步自由选工具,你会发现它经常在一个工具上反复调用,原因只是"它以为这个工具可能成功",结果浪费了大量 Token 和时间。后来通过调整 Prompt,把工具选择限为一个增量选项(比如在已完成步骤的上下文里添加候选工具清单),效果显著改善。架构设计上,这也意味着"工具路由"要由编排器的业务逻辑决定,而不是完全由模型自由发挥。
4.3 场景三:高并发的企业知识问答系统
第三个场景是从 4.1 升级到"高并发"级别:每天几十万次查询,需要支撑 2000 QPS。这个时候,架构设计走向完全变了,核心矛盾不再是"答案质量",而是"成本、延迟、可用性"的三元平衡。
技术方案核心是"三级缓存 + 异步召回 + 模型路由":
- 一级缓存:完全相同的用户问题,直接命中 Redis,返回历史答案,不消耗模型调用。适合 FAQ 类问题,设置较短过期时间。
- 二级缓存:把问题进行语义归一化,对相似问题做近似匹配,如果召回内容高度一致,直接复用答案,这能覆盖大量同义问题,但需要设置更高的相似度阈值来避免答非所问。
- 三级模式:缓存未命中时,进入异步 RAG 管线,请求先进入消息队列,后端 Worker 批量消费,调用检索 + 重排序 + 模型生成。这个模式的设计要点在于把同步的超时压力转化为异步的任务状态——前端轮询任务状态,后台异步返回结果。
图解这套架构时,最能体现水平的是"缓存旁路"与"一致性"的标注:知识库更新后,哪些缓存项需要失效,必须画出一条从更新管线到缓存层的失效链路。很多在这个场景栽跟头的人,问题就出在这里——知识库都更新了,用户还在拿到旧答案,然后客服被骂,技术团队花了一下午排查,找到原因是"缓存没刷新"。
模型路由的策略在高并发环境下也更精细:常见简单问题用轻量模型直接回答,成本约为大模型的十分之一;只有复杂问题才路由到更强的大模型。在图上标注模型的 Token 成本、平均延迟和并发上限,等于在架构评审时就把账算清楚了,上线以后不用等账单到了再吃惊。
5. 图解背后的不可见领域:可观测性、成本与安全设计
架构图上画得再完整,总有一批"不可见"的部分需要设计——它们不参与数据主链路,但决定了系统能跑多久、踩坑时能不能快速恢复。这些部分是 AI 应用架构的"护城河"。
5.1 可观测性设计:LLM 调用链路是新的调试难题
传统可观测性是日志 + 指标 + 链路追踪。但 AI 应用增加了一个新维度:Prompt 和模型的输入输出本身需要被观测。Prompt 是一段有逻辑的文本,某一个系统提示词的措辞变化,可能导致模型输出的偏移。你若没有保存 Prompt 现场的能力,出问题时你根本没法回溯。
我的做法是在模型接入层统一埋点,把每次调用的"完整请求(含 Prompt 拼装前的上下文片段)"和"完整响应(含 Token 用量、延迟)"记录到日志存储。这一层数据量巨大,所以要有采样策略,建议对低价值请求做 10% 采样,对报错请求 100% 全量保存,对高价值用户 100% 保存。
在用图上,画面的右下角一般会画一个"可观测性收集器",它从模型接入层、工具网关、上下文构建器三个点各拉一条虚线,代表日志采集,而不参与主流程。这个收集器最终汇总到一套可视化看板,看板里至少要有三张图:Token 消耗趋势图、各模型延迟分布图、错误类型分布图。
没有这套东西,你会经常经历这样的崩溃时刻:线上用户说"回答质量暴跌了",你却不知道是哪一天暴跌、是哪个模型变了参数、还是哪段 Prompt 被改了。有了可观测性数据和对应的架构链路分析,你可以三分钟内定位到"昨天把某个系统提示词里的条件从句改短后,分类召回权重变了"。在架构设计阶段就规划可观测性,比上线后再补要便宜十倍。
5.2 成本设计:Token 用量本身就是一种"系统资源"
传统架构里,CPU、内存、带宽是资源。在 AI 应用里,Token 是新的资源——它不是无限的,而且按量计费。架构设计里必须把 Token 当成"内存"来规划和监控。
成本控制从架构层面有很多抓手:第一是模型路由(简单问题走便宜模型),第二是上下文压缩(减少每次请求的 Token 量),第三是缓存复用,第四是 max_tokens 的显式限制——很多开发者的请求里根本不设置这个参数,结果模型无限制生成,账单惊到麻木。
我建议在架构图上明确标注一个"Token 预算管理器"组件,它负责给每一次请求分配 Token 预算,并在请求完成后把实际消耗上报给计量系统。当某个用户的 Token 消耗超过阈值,自动触发限流或预警。这么做的好处是成本问题不再是"事后看账单",而是"实时看仪表盘"。
安全设计这块还要再强调一次。AI 应用的攻击面分为两类:传统网络安全攻击(注入攻击、提权、DDoS)和 AI 特有攻击(提示注入、数据投毒、提示词泄露)。在架构图层面,至少要做三件事:对所有外部输入做输入过滤器;对所有模型输出做输出校验器;对所有工具调用做权限校验。这三件事的放置位置分别在交互层之后、模型接入层之后和工具网关内。没有这三道闸门,你的 AI 应用就像一条没有安检的机场跑道,早晚出事。
6. 从图到代码:架构落地时最容易忽略的工程细节
画完架构图,接下来就是落地。但"落地"这两个字,坑比画图多得多。这一小节我不展开代码,只挑几个架构图上不太容易看出来、但实际开发时几乎是生死关的工程问题。
6.1 流式输出的架构适配:不只是加一个 WebSocket
如果架构图上标了流式输出,那么从模型接入层开始,所有对模型调用的请求都要支持流式模式。这意味着你的内部接口不能设计成"传入一个请求,返回一个完整结果"的同步方法,而必须是一个回调驱动的异步接口。这个转变会影响上游的所有模块:Agent 编排器在订阅流式 Token 片段时,如何判断"这一轮生成什么时候算结束"、如何在生成结束前并发启动工具调用,都是新问题。
我推荐的做法是在内部定义一个统一的事件流接口,模型接入层将流式 Token 包成标准事件——token 事件、工具调用事件、完成事件、错误事件——由订阅方自行处理。开发时用异步迭代器或响应式流框架来接收,调试时能直观看到事件的先后顺序,问题定位会快很多。
6.2 幂等性和重试:LLM 调用不是天然幂等的
传统接口设计中,按 ID 查询是幂等的,用户用 POST 创建订单通常会做幂等处理。LLM 调用不具备天然的幂等性——同一个请求发两次,返回结果可能在语义上一致,但生成时间和消耗成本都会翻倍。在做重试时,如果不加控制,模型可能被同一请求打到十几次,既浪费钱又污染上下文。
我见过一个团队做模型调用失败重试,没有熔断逻辑,模型服务商限流五分钟,结果他们还在持续重试,最后不但限流没解除,还白白烧了一大笔钱。正确做法是加上指数退避和抖动,并设置最大重试次数;连续失败超过阈值后,启动熔断,直接返回降级兜底文案。
6.3 上下文窗口边界测试:你需要一个"压力测试用例集"
无论你选了哪个型号的模型,它都有上下文窗口上限,这是硬约束。很多人在架构上画了个"上下文构建器",但从来没定义过"当上下文字符数超出窗口上限时,应该按什么策略取舍"。结果上线某一天,用户历史对话特别长,拼接的 Prompt 直接超过了窗口限制,请求报错。错误信息里写得很清楚(超长),但业务方不懂,还以为系统崩溃。
建议在架构落地前期建一个"上下文压力测试用例集",包括超长历史对话、超大知识库召回、超多工具返回结果等边界输入。每个用例明确写出期望行为:是截断、压缩摘要,还是调整优先级丢弃部分片段。这些测试用例在架构评审时就应该制定出来,开发完后逐条跑通。做这件事只需要半天时间,但为你省下的线上排查时间可能是好几天。
把工程细节想清楚之后,架构图才真正变成可执行的东西。你会发现,画图的目的从来不是画图本身。它是让团队在动手写代码之前,就达成对系统结构的共识——模型在哪、数据往哪流、出问题时去哪查。这张图沉淀下来的判断力,会在你换模型、加功能、扛并发时反复给到回报。