图解AI应用架构设计:从模型选型到RAG与Agent编排落地
在AI应用开发这个圈子混了这么多年,我发现一个特别普遍的现象:很多人手里有大模型API的调用经验,也看过一堆技术文档,可真到自己从零设计一个AI应用的时候,往往脑子里是一团浆糊——模型放哪一层?上下文怎么管理?Agent和业务流程怎么衔接?工具调用失败怎么兜底?这些问题单独拎出来都能聊几句,合在一起就不知道从哪下手了。
“图解”这两个字,恰恰是我觉得解决这个问题最好的方式。软件的复杂性一旦变成视觉化的结构图,很多说不清的关系一眼就能看懂。这篇文章我打算用图文对照的方式,带你走一遍AI应用从需求到落地的架构设计全流程,把我实际做过的几个项目里的设计图、踩坑记录和改进方案都摊开放在桌面上聊,不藏着掖着,希望能给刚接触AI应用设计、或者正在被复杂架构折磨的朋友一些靠谱的参考。
1. 内容整体设计与思路拆解
1.1 AI应用架构到底在设计什么
先说个我经常在技术群里看到的问题:“AI应用不就是调API吗?有什么架构好设计的?”有这种想法的人,大概率只做过Demo级别的应用,比如在Jupyter Notebook里跑个LangChain的快速开始,或者用Flask开一个接口让后端调大模型。这类东西确实不用设计架构,几十行代码就能跑通,但一旦进入到真实的生产环境,情况就完全不是一回事了。
真实生产环境下的AI应用,至少要解决六个层次的问题:
第一层是接入层,你的应用怎么接收用户输入,是Web页面、IM机器人、还是API调用。第二层是流程编排层,多步任务怎么拆解,Agent节点怎么串联,状态怎么流转。第三层是模型层,你用的是云端大模型API还是部署在自建GPU上的开源模型,或者是两者混用。第四层是上下文管理层,对话历史怎么存储,怎么做向量检索,怎么控制token成本。第五层是能力扩展层,模型要调用哪些外部工具,工具的参数格式怎么约定,失败和重试的策略是什么。第六层是质量与安全层,怎么控制输出格式,怎么处理敏感内容,怎么在模型“胡说八道”时兜底。
所谓AI应用架构设计,本质上就是把这六个层次之间的关系画清楚,然后把每一层的具体技术选型和数据流转路径定下来。
我自己的习惯是,在正式写代码之前,先画一张分层架构图。画的这个过程,比最终那张图本身更有价值。因为你会发现很多问题在画图的时候就会暴露出来,比如你可能会发现查询类操作和写操作共用了一个状态存储,将来会有并发问题;也可能会发现工具调用链路过长,模型一次次地带着中间结果往回走,token成本高得离谱。
1.2 图解思维对方案选型的实际影响
图解思维对这个领域最有价值的一点,是它能把“系统能力”和“模型能力”清晰地区分开。在文字描述里,这两者经常缠在一起分不清,但图表上一旦把边界画出来,谁该干什么立刻一目了然。
我举个例子。假设我们要做一个智能客服应用,用自然语言处理售后问题。用文字描述需求,可能写出来是“用户提出问题,AI判断问题类型,查找相关政策,给出回复”。这种描述属于流程叙事,理解起来没问题,但如果直接照着写代码,大概率会把所有判断、查找、回复的逻辑全塞进一段让模型自由发挥的提示词里,希望在多轮对话内一次性搞定。
实际这种方案上线后你会被坑得很惨,因为大模型的输出是不稳定的。它今天能正确地从政策文档里抽取出退款规则,明天就有可能自己脑补一条不存在的规则。问题出在哪?问题出在你把“理解文本”和“数据检索”这两件事混在一起了,让模型跳过了稳定的结构化查询,直接靠记忆和推断去回答。
把同样的需求画成架构图,思路立马就清晰了。你会把整条链路拆成三类组件:
用户消息进来之后,先过一个意图识别模块,这个模块的任务是判断用户想干什么。根据意图,系统走不同的处理流,有的意图直接去查知识库,有的意图需要调用订单接口获取数据,这些外部数据拿到之后,再连同用户的原始问题拼装成最终的提示词,送进大模型生成回答。
这张图画完之后,你会发现一个启发:模型只做一件事——基于充分的结构化数据做推理。而意图识别、信息检索、业务数据查询,全部由外部模块负责。这么改造之后,模型的幻觉率会大幅下降,因为需要它“自己编”的部分变少了,大部分答案的素材是真实数据,模型的工作主要集中在组织和表达这些数据上。
这就是图解设计对方案选型的直接影响。图没有告诉你什么具体技术,但图让你看清了系统边界和职责划分,选型自然就有了方向。
2. 核心组件设计与关键技术选型
2.1 模型层选型:云端API和本地部署的权衡
模型层是AI应用架构里的心脏,选型直接决定了整个系统的能力上限和成本基线。这个选择没有绝对的对错,只有适不适合当前场景。
云端大模型API,比如各类主流大模型厂商提供的接口,最大的优点就是省心。你不用管GPU、不用管推理优化、不用管滚动升级,一个API Key就能用上当前能力最强的模型。对于大多数应用来说,这是最现实的起步方案,尤其是需要强推理能力和复杂指令遵循的场景,云端API的能力优势非常明显。
但云端API也有几个没法忽视的问题。首先是延迟,跨公网调用,单次往返少说几百毫秒,复杂的多轮Agent任务可能要调用几十次模型接口,累积延迟会直接伤害用户体验。其次是成本,如果你做的是一个高频调用场景,token账单会膨胀得很快。再有就是数据合规,某些行业要求用户数据不能出域,这时候云端API就很难落地了。
本地部署开源模型正好能解决这几块问题。延迟是毫秒级,成本主要是前期的硬件投入,数据全程在自己手里。但代价是你得有能力维护一套推理服务,包括CUDA环境、vLLM或TGI这类推理框架的配置、模型量化、并发调度、故障恢复,每一件都不是省心事。而且开源模型的能力确实和头部云端模型有差距,特别是在复杂推理长链条任务上。
我个人的经验是不把这两者对立起来,而是做混合路由。基本原则是:简单任务走本地小模型,比如文本分类、意图识别、信息抽取,这类任务模型不需要多聪明,7B到14B的开源模型微调或者直接提示词就能做得很好,走本地又快又便宜;复杂任务走云端大模型,比如长文档总结、复杂多步推理、生成式创作,这种任务对模型能力要求高,多花点token和延迟是值得的。
这个方案的实现核心是一个路由层。根据任务类型、输入长度、所需上下文规模做规则判断,命中轻量任务就走本地,命中重量任务就走云端。如果你追求更灵活的分配策略,也可以维护一个动态路由模型,让它根据历史成功率自动调配,但这属于进阶玩法,初期用规则路由就够了。
2.2 上下文管理:要求高就四层结构
AI应用里最容易被新手低估的部分就是上下文管理。明明同样都是基于大模型的对话,为什么有的应用越是聊到后面越聪明,你的应用却聊几句就开始“失忆”?这个问题的答案就在上下文管理设计上。
我习惯把上下文管理拆成四层来设计。
第一层是会话级短期记忆。就是当前对话窗口里模型的输入输出历史,按时间顺序排列,直接拼进提示词里。这一层的容量有限,受模型的上下文窗口约束,通常几千到几万token,超过就得做截断或摘要。
第二层是用户级长期记忆。用户的偏好、身份信息、历史关键结论,这些数据需要持久化存储。怎么存储呢?两种主要方式,一种是结构化存储,存在数据库里,需要时查询取出;另一种是向量化存储,把用户的历史内容切成块做Embedding,存进向量数据库,需要时做相似度检索。这套机制对于“这个用户上次说过他在上海工作”这类场景特别有效。
第三层是业务知识记忆。这部分对应的是知识库,怎么把企业的产品文档、政策制度转成可被模型检索的向量索引,然后通过RAG的方式注入到提示词里。RAG这部分我会在后面专门展开讲,这里先记住它是上下文管理里信息密度最高的一层。
第四层是工具结果记忆。Agent调用外部API拿到返回数据之后,这些数据要不要在下一次调用时携带?这个决策很关键。如果每次都让模型重新去调工具拿数据,那就是人力物力的双重浪费。更合理的做法是把上一步工具返回的关键结果做结构化缓存,在后续推理步骤中直接引用。
四层结构画出来之后,你就能看到一个清晰的信号:上下文管理不仅仅是“往上堆内容”,更是一套有层次的存取策略。每一层有各自的生命周期、存储介质、写入时机和读取路径。图上把数据流画清楚,实现的复杂度就能降一大截。
2.3 Agent编排与工具调用设计
Agent是现在AI应用架构里最热的方向,也是翻车最多的地方。本质上Agent就是把一次用户请求拆解成多步子任务,每一步决定调用什么工具、传什么参数、拿到什么结果,然后循环推进直到最终完成。
这个循环的抽象形式很简洁:感知-决策-行动-观察,再来一轮。感知阶段从上下文和当前状态里抽取出模型需要的信息,决策阶段让模型输出下一步动作,可能是调用工具也可能是直接生成最终回答,行动阶段执行工具调用,观察阶段把执行结果写回上下文。就这么一个循环,写出来不难,难在让它在真实数据下稳定运行。
先说Agent节点拆解。建议把Agent里涉及的功能拆成独立的可编排节点,而不是写一个巨大的死循环让它自己乱跑。比如,一个客服Agent可以拆成意图分类节点、信息提取节点、工具调用节点、答案生成节点。前期用工作流的方式写死一部分逻辑,只有当计划步骤确实不确定时才把控制权交给模型的Agent循环。这种混合编排的方式,比纯开放式Agent可靠得多。
再讲工具调用的函数定义。模型能不能正确地调用工具,很大程度上取决于你给模型的工具描述。OpenAI兼容的函数调用格式里,每个工具都要提供名称、描述、参数结构,其中描述这一项特别强调:要写清楚这个工具是干什么的、什么时候该用它、参数有哪些约束。描述写得模糊,模型就会在多个工具之间徘徊,或者传错参数。
我见过一个很典型的错误是工具描述里有错别字或过于简略。比如一个查询订单接口,描述只写“查订单”三个字,模型真的就敢在用户问“我上个月买的东西什么时候发货”的时候直接跳过工具调用开编。后来把描述改成“查询用户订单的物流状态,支持按订单号和商品名称模糊查询,必须在用户提供有效订单号或完整商品名时调用”之后,正确率明显提升。
工具调用的容错设计也不能忽视。工具不总是成功,有可能抛异常、返回空结果、超时。设计的时候一定要给工具调用加超时阈值和重试策略,而且最关键的是,当工具调用失败时,要把失败原因明确地写回上下文里,让模型知道发生了什么、下一步该怎么办。如果这个环节做得不好,模型会默默吞掉错误,然后生成一个自信满满的错误答案。
2.4 RAG检索增强生成的技术要点
RAG这个词已经快被说烂了,但真正把RAG做好的项目并不多。它的核心思想很简单:模型的知识有截止日期、会编造,所以检索外部知识库补充真实信息,再让模型基于检索到的内容去回答。但在实际架构里,简单地说一句“检索增强”远远不够。
完整的RAG链路需要拆成两个阶段:离线的知识处理阶段和在线的检索生成阶段。离线阶段做的事情,是把原始文档清洗、切块、Embedding,然后存进向量库。在线阶段做的事情,是接收用户问题、Embedding化、向量相似度检索、拼装上下文送进模型。
离线阶段看起来步骤简单,但每一步都有坑。
文档清洗是第一个坑源源不断的环节。PDF格式转出来的文本经常会有乱码、页眉页脚混入、表格结构丢失这些问题,如果不做清洗直接切块,知识库里会堆积大量不可用的chunk。我的经验是清洗环节至少要处理:去除页眉页脚、修复异常换行、过滤低信息量的啰嗦段落、对表格做结构化的行列重排。清洗完了之后一定要做抽检,随机挑几十个chunk看一眼,别嫌麻烦,这步省了后面在线检索就是垃圾进垃圾出。
切块策略是一个真正影响检索效果的因素。切得太小,比如一句话一个chunk,检索出来片段缺乏上下文语义;切得太大,比如一整个章节一个chunk,检索出来内容太泛,且浪费token。实践中比较稳妥的做法是:按语义段落边界切分,chunk大小控制在200到500个token之间,相邻chunk间保留10%到15%的重叠,这是为了不让被切在边界处的信息丢失掉。切完之后还可以做一层小优化,叫元数据标注,给每个chunk记上来源文档、章节标题、页码,在线检索时可以直接按来源过滤,也方便回答中注明出处。
Embedding模型的选择也有讲究。开源的BGE系列、M3E系列在中文检索上表现都不错,商业的Embedding服务则胜在省事和稳定。评估一个Embedding模型是否好用,不能只看榜单分数,一定要在你自己的知识库样本上跑一跑召回测试,看看真正相关的文档是不是能被稳定地排在前面。
在线检索阶段,除了向量相似度,一定要配合关键词检索做混合召回。向量检索擅长语义相关性匹配,但面对专有名词、产品型号、ID编号这类文本,词的精确匹配往往是逃不开的。用RRF分数融合算法合并两类结果,效果通常比单独任何一种都要好。检索完之后有一个容易被忽略的环节叫重排序,用rerank模型对检索回来的候选chunk做最终精排序,只把质量最高的前四五个chunk塞进提示词。加了这个环节,回答质量的提升是肉眼可见的。
最后检查一个硬指标:你RAG系统的召回率到底有多高。建议离线把测试问题集建好,每个问题都配好正确的知识库出处,然后在线批量跑检索,统计Top5命中率。低于70%的话别急着调提示词,大概率是切块、Embedding或召回链路出了问题。
3. 实操过程与核心环节落地记录
3.1 从零画出你的第一版架构图
很多新人会被架构设计吓住,觉得一张高完成度的架构图背后必然有深厚的经验积累。实际上,架构图可以分版本迭代,第一版的任务是让所有组件各就各位,到后面版本再优化细节。
我从零画图会遵循一个非常标准化的步骤。第一步,列功能清单,把用户可见的功能和系统内部的支撑功能全部用文字列出来,比如“用户发送消息”、“识别用户意图”、“检索产品资料”、“生成回复”、“记录对话历史”,写在一张纸上。第二步,规划分层,按接入层、编排层、模型层、上下文层、能力层、质量层把这些功能归类,每个功能必须能找到自己所在的一层。第三步,画数据流线,从用户请求开始,一步步追着数据流画线,经过哪些组件、读写哪些存储、调用哪些外部服务。第四步,找瓶颈和单点,仔细看有没有某个组件被多条链路共用,如果它挂了整条系统还能不能工作。
以我手头做过的一个企业知识问答系统为例,第一版架构图里出现的组件大致是:Web客户端、对话API网关、会话管理器、检索服务、向量数据库、大模型网关、Embedding服务、重排序服务、以及企业内部的文档解析流水线。
画完第一版你会发现几个问题需要立刻确认。第一个问题,网关和会话管理器之间的协议怎么定。第二个问题,检索失败时系统是直接返回空结果还是触发降级策略。第三个问题,大模型网关的超时和重试熔断机制要设多大。这些问题在画图阶段发现并解决,要比上线后被线上故障逼着解决便宜得多。
3.2 把架构图映射成实际项目代码结构
架构图画好了,接下来的问题就是怎么落到真实的工程里。很多人卡在“图是图,代码是代码”这个断层上,觉得图纸画完之后不知道怎么开始写。我提供一个我一直在用的映射方法:按架构图的组件边界拆目录,一个组件一个模块,模块之间通过明确的接口通信。
比如按前面那张架构图,工程代码的结构可以是:
app/ gateway/ # 接入层,处理HTTP/WS协议 api_routes.py request_validators.py orchestration/ # 编排层,流程调度与Agent循环 agent_loop.py intent_router.py task_graph.py context/ # 上下文管理层 conversation_cache.py memory_store.py prompt_builder.py rag/ # 检索增强模块 retriever.py reranker.py chunker.py tools/ # 能力扩展层 order_tool.py policy_tool.py tool_registry.py model_gateway/ # 模型网关 llm_client.py model_router.py circuit_breaker.py这个结构的好处是显而易见的,你想改模型层的路由策略,只需要动model_gateway这一个目录;你想给RAG的重排序换个模型,只需要动rag目录;不同模块之间的改动互不干扰。
特别提一下model_gateway,我把它单独抽出来当作独立目录,是吃过亏后总结出来的。早期项目里我直接把OpenAI的SDK调用散落在各个业务模块里,结果某天想统一加一层缓存时,全局搜索替换改了几十处文件,苦不堪言。独立出一个网关后,所有模型调用都收口在一个地方,做缓存、限流、日志、降级都是顺带的事。
3.3 串联一次完整的推理请求流程
我拿一个实际的用户请求来说明整套架构是怎么协作的。用户输入:“帮我查一下我们公司今年的差旅报销标准,超标的单子应该怎么处理。”
请求进入网关,网关做完身份校验、参数清洗、频率限制后,把请求转给编排层的会话管理器,它负责把这轮对话的上下文从缓存里加载出来。然后意图路由器开始工作,判断这个问题属于“企业政策咨询”意图,路由到RAG链路。
RAG的查询处理器把用户问题做改写。这里有个细节,原始问题很长,直接拿去检索效果往往不如精简后的核心问题好。改写后的查询是“2024年度差旅报销标准,超额处理规则”,然后同时做向量检索和关键词检索,各取Top20候选,交给重排序模型精排,取Top5的chunk拼装进上下文。
接着编排层把这些检索结果、用户历史偏好(比如用户所在部门信息)、以及预设的系统提示词一起传给模型网关。模型网关根据任务标签路由到云端大模型,因为这个问题需要较强的理解能力,生成最终回答。回答生成后再过一层输出校验器,检查有没有遗漏的政策要点、有没有出现幻觉性的编造数据。
到这里,一次完整的推理请求才结束。这个过程看似复杂,但在架构图里,就是几条数据流线的事情。我特别推荐你手动模拟这个流程走一遍,把每一步的输入和输出打印出来,观察一次请求到底流转了哪些组件,这个体验比看十篇架构文章都有用。
4. 常见问题与排查技巧实录
4.1 一张问题排查速查表
把团队这些年碰到过的问题整理成了一张速查表,按症状和排查方向分组。
| 症状 | 可能原因 | 排查方向 |
|---|---|---|
| 回答内容与知识库明显不符 | RAG检索召回不足或排序错误 | 检查召回Top5命中率,检查query改写是否偏离原意 |
| 同样的请求不同时间结果差异大 | 上下文截断策略不稳定或模型参数未固定 | 检查天气数据、随机参数,复现时固定相同条件 |
| Agent循环停不下来,反复调用工具 | 工具结果未正确写回上下文,模型感知不到进展 | 打开工具调用的结果日志,确认每一步结果被记录 |
| 请求延迟飙升 | 路线错误走了云端大模型,或是重排序队列积压 | 检查路由命中日志,看延迟消耗在哪个环节 |
| 多轮对话突然失忆 | 短期记忆被截断掉,长期记忆未命中 | 检查会话缓存上限,检查长期记忆写入时机 |
| 工具频繁返回错误参数 | 工具schema描述不清,模型理解不了参数含义 | 重写工具描述,补充参数约束和典型示例 |
这张表的每一条背后都有真实事故支撑。比如“多轮对话突然失忆”那条,我们线上有个客服系统,用户聊到第八九句话时,AI突然开始答非所问,排查半天发现是短时记忆缓存设置了固定窗口1000条消息,而这批用户话特别多,早期的重要信息被挤出去了。后来改成按token数截断,并且把用户声明的关键信息(如“我在上海工作”)提前写入长期记忆层,问题才彻底解决。
4.2 延迟、成本与输出质量的三角平衡
AI应用架构里有个绕不开的三角关系:延迟、成本、质量。三样都想要完美是不可能的,实际项目里总是要取一个平衡点。这个三角平衡不能靠拍脑袋定,要有数据的支撑。
我做过一个批量内容审核的AI子系统,最初方案是全部请求都走云端大模型,正确率确实高,但每天账单下来之后,负责成本的同事脸色瞬间就不好看了。后来加了层路由:先用本地7B小模型过一遍,判断这条内容是不是“明显正常”或“明显异常”,只有那些模棱两可的边际case才转给云端大模型做二次复核。
这么一改,约65%的请求在本地就被解决了,云端调用量下降了大半,成本直接砍了40%以上。代价是整体审核延迟从原本的400毫秒增加到约500毫秒,因为本地模型计算也需要时间,但考虑到成本下降的幅度,这点延迟完全在可接受范围内。
这个优化方案能在架构图上一眼就看明白,也是图解思维带来的直接收益之一。你在图上很容易看出来哪些流量是高频且可以本地化的,哪些是必须走云端的高质量链路。把这两条路画成分流的双车道,成本和质量就能同时兼顾。
4.3 关于可观测性的一些经验
最后一定要单独强调可观测性。很多AI项目上线后最大的问题不是功能不工作,而是出了问题你根本不知道问题出在哪个环节。传统软件的可观测性关注请求跟踪、日志、指标,AI应用在此基础上还多了一个维度:每一轮模型调用的输入和输出。
我的做法是给每一次模型调用生成trace ID,从上到下贯穿整个调用链。用户在Web端发起的请求,在网关产生一个trace ID,这个ID跟随检索、重排序、模型调用整个链路。每个环节的耗时、token数量、结果状态,统一写入日志系统。当用户投诉“回答是错的”时,技术团队可以通过trace ID把这次回答的完整推理链路拉出来,看是检索没找到正确内容、还是模型在拼接时产生了幻觉、或者是工具返回了错误数据,定位效率和曾经“啥也查不到只能重试”的体验完全不在一个层面。
另外还有一个小技巧:对模型输出做结构化的质量评分。比如让一个轻量的评判模型对每次回答的相关性、完整性和格式合规性打分,低于阈值就自动触发降级策略,比如换更强的模型重答一次,或者退回给人工处理。这个机制看着简单,却能把系统里大量暗含的低质量输出在萌芽状态拦截住,省掉很多事后骂娘的精力。
这些是我和团队在多个项目里的实际经验,踩过的坑、流过的汗都在这些内容里了。AI应用架构设计这个方向还在极速演进,今天的架构模板明天可能就不适用了,但把组件职责画清楚、把数据流找出来、把不确定环节加兜底,这套基本功我相信很长时间内都不过时。