1. 从一张画不明白的架构图说起
去年年初,我们团队接了一个AI应用项目,产品经理给的需求只有一句话:“做一个能帮客户查合同条款的智能助手”。当时人人都在谈AI应用架构设计,我们也没多想,直接拉了几个人开始做:后端同学用Python写了个服务,前端同事搭了个聊天界面,算法同学那边微调了一个开源大模型,数据库里头存了一份法规文档的切块。两周后,我们把东西串起来,结果连自己人都看不懂系统是怎么流转的:问题来了要先进哪个服务?向量库里的数据是哪里来的?为什么模型偶尔答非所问却查不到日志?我画了三版架构图,每一版都被人挑战“你这个框和线到底代表什么”。
那段时间我意识到一个很现实的问题:大部分AI应用不缺代码,缺的是能把系统讲清楚的架构设计。很多团队立项时只盯着“接入哪个大模型”,却忽略了应用本身的完整生命周期——从用户请求进来,到意图识别、上下文组装、知识检索、模型推理、结果校验、工具调用,再到最终回复,这中间每一条链路都要被显式地画出来、定下来。如果你说不清一条请求在系统里经历了什么,排查问题就只能是碰运气,优化性能就是拍脑袋。
这篇文章不是学院派的理论讲义,而是我基于真实项目的经验整理——从AI应用架构设计的核心模块拆解开始,讲清楚每一层为什么存在、怎么选型、怎么落地,再聊到架构图要怎么画才不会沦为“应付汇报的装饰品”,最后给出一个可直接参考的知识库问答Agent设计案例,以及我们在实际部署中踩过的坑。适合正在设计AI应用方案的后端工程师、AI应用开发者、产品和技术负责人,也适合刚入门AI应用开发、想建立整体视角的同学。
2. AI应用架构设计的核心模块拆解
2.1 先想清楚:这是“功能”还是“系统”
很多人架构设计做不好,根因是没分清做的是功能还是系统。功能是“能对话、能回答”,系统是“在什么输入条件下、经过哪些环节、在多大负载下、以什么质量稳定地输出结果”。AI应用架构设计的起点,不是选一个模型,而是把整个系统分成六个互相独立又能协同的模块,我沿用的分层方式是:接入层、理解与编排层、模型层、记忆与上下文层、知识增强层、执行与工具层。
接入层负责对外通信,统一处理HTTP请求、WebSocket长连接、消息队列,以及后端的鉴权、限流、计量。理解与编排层是大脑,承担意图识别、任务规划、工作流调度,决定当前请求应该走快速回答还是多步推理。模型层包括大语言模型本身和可能用到的多模态模型、向量模型、重排模型。记忆与上下文层管理短期对话状态、长期用户偏好、全局事实性知识。知识增强层是RAG落地的主战场,涵盖文档解析、切片、向量化、索引、召回、重排。执行与工具层让Agent真正“动手”,包括内置函数、外部API、代码解释器、数据库查询器等。
这六层不是每个系统都必须齐备,功能简单的问答机器人可能只有接入层、模型层和基础上下文,但你在设计架构时至少要走过一遍这六个问题域,再决定砍掉哪些。这个“先完整拆解、再按需裁剪”的过程,能避免最典型的设计失误——一上来就直扑模型层,等到需要加记忆、接知识库、调工具时,发现原来的胶水代码根本撑不住。
2.2 编排层是AI应用架构里最容易被低估的部分
我见过太多团队把“编排”等同于“调用模型”,这是架构设计里最大的误区。早期的AI应用确实往往就是一个HTTP接口包一层提示词,但进入Agent时代以后,编排层的复杂度已经超过很多传统后端系统。一个真实的Agent请求,可能包含:意图分类、必要的多轮澄清、检索触发条件判断、工具调用规划、工具结果解析、临时状态保存、多人协调等。
编排层的设计目标是把“模型的不确定性”和“业务逻辑的确定性”隔离开。业务规则,比如“客户等级为VIP时必须优先走人工复核”“金额超过阈值必须调用风控接口”,这些应该落在代码里,做硬编码规则;而“用户想表达什么、应该调用哪个工具、需要从哪份文档里找答案”,这些语义判断才交给模型去推理。如果反过来,把确定性的东西全塞进提示词,让模型用概率去保证,系统就会表现得飘忽不定。
在模块划分上,编排层里我习惯再拆成三个子组件:意图路由,负责把用户输入分类到不同的处理流程;任务分解器,把复杂任务拆成多步骤清单;状态控制器,维护当前任务执行到哪一步,下一步依赖哪些数据。三个人可以平行开发的组件,合起来就是一个可控的Agent工作流。架构图画到这里,才开始有了“可解释性”的雏形。
2.3 模型层的选型不是越大越好
模型层设计要回答的问题很直接:用哪个模型、部署在哪里、一次推理的成本是多少。大多数业务场景下,我们需要的不是一个无所不能的通用大模型,而是一个能在特定任务上稳定输出、成本可控的模型组合。
实操中我倾向于按任务难度分层选型:简单意图识别、文本分类、格式抽取,用轻量模型或直接调用速度快的小尺寸模型;复杂推理、长文本生成、高难度代码生成,才动用旗舰级模型。还有一类任务适合用多个模型协作,比如先让一个小模型做路由,判断请求该进快速通道还是深度通道,再把深度通道的请求交给大模型。这套设计在架构上并不复杂,但对成本和延迟的改善非常直接。
模型部署位置的选择同样关键。纯云端API方案的优势是维护成本为零、模型更新及时,短板在于数据私密性受限、单次调用延迟偏高;私有化部署能解决隐私和长尾成本问题,但需要GPU资源、运维能力和模型版本管理能力;混合方案则把敏感数据处理放在私有化模型,非敏感通用任务走云端。我给过一个客户的参考建议:如果每日请求量低于一万次,直接用云端API的性价比最高;过了这个量级,再认真核算私有化部署的边际成本。
3. 图解AI应用:架构图到底应该怎么画
3.1 四种必备视图,对应不同沟通场景
很多项目里的架构图只有一张“大杂烩”,把服务器、数据库、模型API、业务流程全塞在一个方框里,谁看都费劲。真正可用的AI应用架构设计图解,至少应该包括四种视图,每种视图服务不同的读者和决策场景。
第一种是系统上下文图,这是给产品经理、业务方、老板看的。整张图只需要一个核心系统方块,周边画上用户角色、外部依赖和数据源,目标是让非技术人员一眼看懂“这个AI应用处于什么位置,和谁打交道”。我在项目启动会上通常只展示这一张图,用来对齐范围,避免一开始就陷入技术细节。
第二种是容器图,给后端团队成员看。容器在这里指可独立部署的服务或进程,比如Web网关、Agent编排服务、向量数据库、模型推理服务。容器图要表达的是服务之间的调用关系和协议,比如通过HTTP还是gRPC、同步还是异步,这张图画清楚了,系统拆分和部署边界也就清楚了。
第三种是组件图,给核心开发人员看。在容器图的基础上,深入到每个容器内部的模块划分,比如编排服务里的意图路由模块、工具调度模块、状态管理模块是如何协作的。组件图是我们在做设计评审、代码走查时的主要参考资料。
第四种是部署图,给运维和SRE团队看。要标明每个容器的物理/云上部署形态、副本数量、GPU资源信息、网络策略等。部署图需要在架构设计早期就动笔,很多AI项目上线延迟,正是因为部署细节到开发尾声才被想起。
3.2 图解的关键约定:让框和线都有一致语义
架构图画多了,我总结出几条约定,能显著减少“图看不懂”的尴尬。方框只画实体,比如服务、数据库、外部系统;圆角矩形只画逻辑模块,比如组件、子功能;箭头表示控制流或调用流,实线代表同步调用,虚线代表异步消息。不要在图上用不同颜色表达含义,除非图例里写明了颜色规则,否则看图的人只能靠猜。
数据流的方向尽量统一,我习惯从左到右展开:用户入口在左侧,外部依赖在右侧,核心系统占据中间主视觉。如果一张图里数据流出现回头、交叉、绕圈,往往是系统设计本身存在循环依赖,这在架构层面就需要警惕。有一次我们画编排服务组件图,发现“调用工具→工具回调编排服务→编排服务再调用另一个工具”形成了跨服务循环,实际排查后发现确实存在同步阻塞风险。
还要强制给每个关键连接标注协议和数据类型,比如“HTTP/JSON”“gRPC/ProtoBuf”或“Kafka/事件”。标注的价值在于暴露隐式假设,AI系统里特别常见的问题是“模型输出后直接通过HTTP转发给下游”,没有明确数据格式约定,最后下游解析报错时谁都不知道问题出在哪。
3.3 架构图用什么工具画才能保持“活”
静态画图工具画的架构图,最致命的问题是“画完即过期”。两周后代码改了,架构图还停留在旧版本,没有人愿意维护它,最后这张图彻底变成摆设。
对于AI应用这种迭代速度极快的系统,我的建议是把架构图“代码化”,用文本生成图的方式管理。PlantUML、Graphviz这类工具都支持用文本描述方框和箭头,改动架构时改几个字符就能重新生成,能放进Git仓库里做版本管理。文本化的另一个好处是可以做架构评审的差异对比,我经常在代码评审时顺带跑一下架构描述文件的diff,能直观看到这次改动影响了哪些调用关系。
还要注意,架构图里可以简要标注技术选型,但不要在图上堆砌过多细节,比如不要写具体的超参、不要写环境变量名。架构图的信息层次应该比详细设计文档高一层,否则图会变成一篇看不懂的文档。做到这里,图解方法论算是通了,但还要配合一套协作规范,至少约定好:谁负责更新、什么变更必须更新图、评审时看图还是看代码。没有规范约束,任何图示方案都活不过一个月。
4. 从零到一:设计一个知识库问答Agent
4.1 需求侧把边界定清楚
为了让前面的模块拆解和图解方法落地,我完整走一个案例:设计一个面向企业内部员工的知识库问答Agent,数据源有几十份产品文档、制度文档和故障处理手册,用户通过Web聊天窗口提问,期望获得带出处的答案。按之前的六层拆解,需求侧的重点不是“能回答”,而是三个边界条件。
回答必须给出文档出处,这意味着知识增强层是刚需,召回结果里必须保留来源信息和置信度。文档更新后,系统要能感知变化,需要有文档版本追踪和索引刷新机制。部分问题的答案不能被限定在文档里,需要结合实时数据比如库存数量、服务器状态,因为Agent必须能调用工具,例如查询内部API。这三个需求直接决定架构里哪些模块必须存在、哪些可以砍掉,也决定了我们最终的部署形态是私有化还是混合方案。
我们还定义了非功能需求:单次问答端到端延迟不超过三秒,日活用户不超过五百人,并发峰值为五十个会话,特殊客户数据必须留在内部网络。这几个数字,决定了Embedding模型和LLM在本地还是云端运行,决定了向量数据库选型,甚至决定了回答流式还是非流式输出。
4.2 分层实现的关键决策与配置样例
接入层我们选择了一个轻量网关服务,统一处理WebSocket会话、用户鉴权和限流,请求进入后由网关转发到Agent编排服务。为什么没用HTTP短连接?因为问答场景天然适合多轮对话,WebSocket能省去每次请求都建立连接的开销,也能更自然地上推流式回复。
编排层我们用一套规则加模型混合的路由,先通过一个极快的意图分类判断:如果问题命中“查文档资料”这个意图,就走RAG流程;如果命中“查系统状态”,就进入工具调用流程;如果两者都命中,就先检索文档,再调用工具补全实时数据。这套路由用几十条标注数据和一个较小的分类模型就能做,不需要什么复杂的推荐算法。这里一个心得是,路由意图的集合一定要控制在合理范围内,别超过十五个,否则分类准确率下降,后续维护和扩展都会很吃力。
模型层最终选择了双模型组合:问答主模型部署了一款中等参数规模的模型,偏重指令遵循和中文理解,量化后在本地单卡上跑;Embedding模型用了专门的向量模型,索引维度一千多。重排模型选择了一个轻量级的排序模型,对召回的前五十条做精排再取前几条进上下文。这套组合比“一个大模型干所有事”的方式,在延迟上优化了约一半,成本更是只用了大概三分之一。
知识增强层是工作量最大的部分。文档先按结构拆成段落,再按长度做二次切分,保证每片语义相对完整,切片后生成Embedding并写入向量库。我们最初直接用长度固定切分,效果很差,大量相关命中被割断。后来改成“按标题层级切块、块内再分片”的策略,实测召回率提升明显。重排之后还需要做一个“出处格式化”,把命中的原文片段和文档名、章节路径带回给编排层。
工具层我们接了两个内部API,一个用于查询库存数量,一个用于查询服务状态,通过函数调用约定暴露给模型。这里一个比较容易踩的坑是,工具返回的数据结构要稳定,一旦变动必须同步更新给模型看的工具说明,否则模型会按旧结构解析,经常解析出奇怪的字段。后来我们加了一个简单的json schema校验器,在工具返回的第一环做结构性检查,问题率降了很多。
4.3 配置参数:一份可以直接抄的启动清单
项目落地后,我把关键配置参数整理成了表格式清单,按模块划分,方便团队对照部署。
| 模块 | 配置项 | 参考值 | 说明 |
|---|---|---|---|
| 接入层 | 会话超时 | 10分钟无操作断开 | 配合心跳机制,避免资源空占 |
| 接入层 | 限流阈值 | 每用户每分钟20次请求 | 防止对话机器人被高频刷单 |
| 编排层 | 意图分类阈值 | 置信度低于0.7转入兜底话术 | 避免低置信度误路由到错误流程 |
| 编排层 | 最大工具调用数 | 单轮最多3次 | 防止模型陷入工具循环 |
| 模型层 | 主模型量化 | 4bit量化部署 | 兼顾回答质量和单卡推理速度 |
| 模型层 | 温度参数 | 0.3 | 知识问答类任务建议低温 |
| 知识增强层 | 切片长度 | 按语义块约300~500字 | 长文档按标题递归切分 |
| 知识增强层 | 召回数量 | 初召回50条,精排后取5条 | 给上下文足够候选,但不超窗口 |
| 上下文层 | 历史窗口 | 最近10轮摘要 | 长会话用摘要代替全量历史 |
温度参数的取舍值得多说一句。知识问答场景,你希望模型尽量忠实于检索到的内容,而不是自由发挥文采,所以温度设低一些比较稳。我在实验里把温度从0.3升到0.8,其他条件不变,连续跑了三组测试集,结果在“忠实度”这项指标上下降了十几个百分点,代价非常直观。
5. 落地实证:高频故障与排查实录
5.1 RAG不生效,问题是相关文档根本没被召回
上线后我们遇到的最典型问题是:明明知识库里有一篇文档写得很清楚,用户提问时,模型就是答不上来。一开始怀疑是生成环节的问题,调提示词、换模型都没用,后来检查重排结果发现,检索环节的召回列表里根本没有那篇文档。
排查路径是这样的:先确认文档是否成功入库,向量库里能查到对应记录;再检查输入查询向量化是否正常,手工打印用户问题的向量相似度分布;最后查出问题出在文档切分上,那份文档的关键内容在一个超长的表格里,按标题切块后被整体当成一个块,而该块的向量表示被表格中的大量数字稀释了。解决办法是增加一个表格识别步骤,把大表格拆成按行/按页的小块,再单独建立索引。从这个案例里我总结出一条规律:RAG链路不对,优先查“文档到底怎么被切的”,永远比盲目调模型参数更有效。
这类问题也可以用更系统的排查清单来梳理:检查入库文档解析是否完整,特别警惕PDF提取丢字;检查切片是否破坏语义块;检查Embedding模型和查询向量是否同一版本;检查重排是否把正确结果排到了后面;最后检查拼接好的上下文是否被截断。按照顺序一点一点排除,能节省大量试错时间。
5.2 上下文管理不当导致的多轮对话漂移
另一个高频故障是对话轮次稍长,模型就“跑偏”。用户第一轮问“打印机故障如何处理”,第二轮说“我是指三楼那台”,模型完全听不明白这个指代。问题看起来是模型能力不够,实际上是我们上下文层设计太简单——直接把全部历史消息原样塞给模型,没有做指代消解和摘要提炼。
我们后来在上下文层里增加了一个动态摘要器:当历史超过十轮,就把更早的内容压缩成一则语义摘要,保留核心实体和用户意图,同时保留近三轮完整消息用于指代识别。“三楼那台”这类指代信息必须保留在最近消息里,不能过早被摘要掉。改造后,十轮以上多轮对话的满意度有明显提升。
上下文层的设计三个要点,都是踩坑换来的:历史不是越长越好,窗口过长会稀释注意力;消息需要区分层级,系统指令、工具返回结果、历史用户消息在拼接时要有明确的优先级;敏感信息要做脱敏或权限过滤,不能让模型在回答中泄露其他用户的数据。
5.3 稳定的代价:像对待交易系统一样对待Agent
我们把Agent服务想象成一个交易系统来设计稳定性。任何一步都可能失败,所以要构建完善的错误处理机制。工具调用设置了严格的超时和重试策略,默认超时五秒、最多重试两次;模型输出做格式校验,必须符合预期的JSON结构,否则触发一次修复提示再交给模型;整个编排过程的关键节点都记录traceID,请求一进来就生成一个唯一的追踪标识,下游日志全部带上它。
排查问题时的第一个动作永远是“按traceID拉全链路日志”,而不是盯着模型输出猜。这个习惯帮我们省了无数时间。日志要区分结构化事件和内容快照,事件日志用于聚合统计,内容快照用于困难样本复盘。成本方面,我们给每个请求记录Token消耗和模型调用的费用估算,监控异常消耗。有一次线上发现某个用户的单次会话消耗突增,拉了日志后发现是Agent陷入工具循环,连续调用了十几次查询接口。在编排规则里加上“单轮最多调用工具三次”的硬限制后,这种异常基本消失了。
为了让系统可控,我们还会定期抽取线上失败的对话样本,人工复盘后加入回归测试集。这个动作比什么评估框架都实用,因为每一次Review都能直接转化为下一轮迭代的用例。
6. 从单Agent到多Agent协作的架构演进
6.1 三种协作模式,按需选择而非追新
Agent类应用的下一站通常是多Agent协作:多个具备不同专长的Agent组合起来处理更复杂的任务。但架构上的“多Agent”不是为了炫技,而是为了解决单一Agent“什么都会一点、什么都做不精”的问题。
实际工程里最常见的三种协作模式。第一种是编排者模式,一个主Agent负责接收用户请求并拆解任务,把子任务分发给不同的专家Agent,再统一汇总结果。这个模式控制性强、流程透明,适合流程相对固定的场景,比如工单处理。第二种是辩论模式,多个Agent扮演不同角色,比如产品、技术、风控,针对同一个问题提出方案并互相挑战,最终由一个裁决Agent或投票机制给出结论。这个模式适合决策类任务,但成本很高,需要注意控制Agent数量和讨论轮数以防止逻辑循环。第三种是流水线模式,把任务拆解成固定顺序的步骤,每个步骤由一个专门的Agent完成,前一个Agent的输出作为后一个的输入,比如一篇文章从资料检索、初稿撰写、合规审查到润色发布的流水线。
选哪种模式,主要看任务的可拆解性和对流程可控性的要求。我在项目里的一条原则是:能用一个Agent解决的任务,不要为了架构上的“多”去拆成多个;只有明确出现了能力冲突或独立质量瓶颈时,才值得引入多Agent协作。
6.2 协作接口比Agent内部的模型更重要
多Agent架构最容易翻车的地方,不是Agent的模型能力,而是Agent之间的通信协议。每个Agent本质上是独立的服务,相互之间要传递结构化任务、内容片段、状态信息。如果直接在代码里硬编码互相调用,一旦一个Agent的接口变了,整个协作链就瘫痪。
我们给每个Agent定义了一套统一的任务协议,包含任务类型、输入参数、上下文引用、期望输出格式、质量要求和回调地址。这样无论是哪个Agent发起的协作请求,格式都是一致的。这套协议同时也是多Agent协作架构图的重要支撑——图解上不再画“A调B、B调C”这种蛛网式线条,而是改为“所有Agent通过协议总线交换信息”的简洁结构,图面清晰很多,排查问题也简单很多。只要遵循协作协议,新增Agent不会破坏既有链路,替换某个Agent的内部实现也不影响整体架构。
6.3 演进过程中始终保持架构上的“不变项”
无论单Agent还是多Agent,有几件事在架构演进中尽量保持不变。第一,接入层对外暴露的接口形态保持稳定,用户的会话体系和后端Agent内部结构解耦,这样即使整个Agent编排方式推翻重做,用户端无感知。第二,知识增强层的数据通道保持单一入口,所有文档写入都经过同一条解析入库管道,不会因为业务复杂化就出现多个互不相通的知识源。第三,可观测性基础设施从一开始就搭建好,traceID贯穿所有Agent,这是多Agent系统里唯一能定位问题的抓手,等到出问题再来补,往往已经晚了。
我的习惯是每次架构评审时先看这三个不变项有没有被破坏。如果没破坏,内部再怎么演进都算安全;一旦破坏了,再好看的架构图也掩盖不了未来要爆的雷。
最后说一点个人体会。我在实际项目中越来越觉得,AI应用架构设计和传统软件架构没有本质区别,核心都是管理复杂度。模型只是整个系统里的一个组件,它能力再强,也替代不了清晰的边界划分、稳定的数据通道和扎实的工程规范。每次团队里有人兴奋地拿来一个新的Agent框架说“这个能帮我们解决所有问题”,我都会建议先把它的调用链图画出来,走一遍我们自己的六层拆解,再决定要不要引入。这个习惯帮我们避开了很多无效的“架构追新”。希望这份从设计方法、图解规范到落地排查的经验,能让你在下一版AI应用架构设计时少走几步弯路。