AI应用架构设计图解:从LLM、Agent到MCP与记忆系统的分层实践

发布时间:2026/10/26 16:58:34
AI应用架构设计图解:从LLM、Agent到MCP与记忆系统的分层实践

1. 从一张架构图说起:AI应用到底由哪些层组成

很多人第一次接触AI应用开发,脑子里是一团浆糊——大模型、Agent、MCP、向量库、工具调用、记忆系统,这些词天天在眼前晃,但真要画一张完整的架构图,又不知道谁挨着谁、谁调用谁。我刚开始做AI应用那会儿也是这样,看了一堆文档,每个概念单独都懂,合在一起就串不起来。后来踩了不少坑,才慢慢在脑子里形成了一张清晰的图。这篇内容就是把我理解的AI应用架构设计,用图解的思路一层层拆开讲清楚。

先给一个最直观的类比。你可以把AI应用想象成一家餐厅:LLM(大语言模型)是后厨的主厨,他手艺很好但只会做菜,不知道客人是谁、不知道今天有什么食材、也不知道客人忌口什么;Agent(智能体)是餐厅经理,他负责理解客人的需求、安排主厨做菜、协调服务员上菜、处理突发状况;MCP(模型上下文协议)是餐厅的标准化接口规范,让经理能用统一的方式跟供应商、收银系统、外卖平台对接;工具(Tools)是厨房里的各种设备,烤箱、搅拌机、切菜机,主厨需要什么经理就给他调什么;记忆系统是餐厅的客户档案,记录老客户的偏好,下次来不用再问。

这个类比基本能覆盖AI应用架构的核心层次。下面我按从底到顶的顺序,把每一层拆开讲。

1.1 最底层:模型层不只是"选一个LLM"那么简单

模型层是整个AI应用的地基。很多人觉得模型层就是"选GPT还是选Claude还是选开源模型",其实远不止。模型层要解决的问题包括:用哪个模型、怎么调用、怎么控制成本、怎么保证延迟可接受、怎么做降级和容错。

先说模型选型。2026年的现状是,模型已经分成了几个明显的梯队。第一梯队是各家旗舰闭源模型,推理能力强、上下文窗口大、多模态支持好,但贵;第二梯队是中等规模的模型,性价比高,适合大多数日常任务;第三梯队是小参数模型,可以本地部署,延迟低、数据不出域,但能力有限。实际项目中,很少只用一个大模型,通常是混合使用——简单任务走小模型,复杂推理走大模型,敏感数据走本地模型。

这里有个我踩过的坑:一开始所有请求都走旗舰模型,结果月底账单出来吓了一跳。后来做了任务分级,把意图识别、格式转换、简单问答这类任务路由到小模型,成本直接降了70%以上,用户体验几乎没差别。所以模型层设计的第一个原则就是任务分级路由。

第二个原则是多模型冗余。不要把所有鸡蛋放在一个篮子里。我遇到过某家模型服务突然限流的情况,如果没有备用模型,整个应用就挂了。做法很简单:在模型调用层做一个抽象,统一接口,底层可以切换不同的模型提供商。这样某个模型不可用时,自动切到备用模型,用户无感知。

第三个原则是上下文管理。LLM的上下文窗口是有限资源,怎么在有限的窗口里塞进最有用的信息,是模型层要解决的核心问题之一。常见做法包括:对话历史做摘要压缩、检索结果做重排序后只取Top-K、系统提示词精简到最必要的部分。我见过有人把整个知识库往上下文里塞,结果要么超限报错,要么模型被无关信息干扰,回答质量反而下降。

1.2 中间层:Agent是AI应用的"大脑",但别把它想得太玄

Agent这个词现在被炒得很热,但剥开概念的外壳,Agent的本质就是一个带循环的决策系统。它做三件事:感知当前状态、决定下一步动作、执行动作并观察结果,然后循环。跟传统的程序流程相比,Agent的区别在于它的下一步动作不是硬编码的,而是由LLM动态决定的。

一个典型的Agent循环是这样的:用户输入问题 → Agent把问题加上系统提示词和可用工具列表发给LLM → LLM决定是直接回答还是调用某个工具 → 如果调用工具,Agent执行工具并把结果返回给LLM → LLM根据工具结果决定下一步 → 循环直到LLM认为可以给出最终答案。

这个循环看起来简单,但实际做起来坑很多。最大的坑是循环失控——LLM可能反复调用同一个工具,或者陷入死循环出不来。我遇到过一次,Agent在调用搜索工具时,因为搜索结果不理想,反复搜索了十几次,token烧了一大把,最后还没给出答案。解决办法是设置最大循环次数和超时机制,同时在系统提示词里明确告诉LLM"如果连续两次搜索结果相似,就基于现有信息给出回答"。

另一个坑是工具选择错误。当可用工具很多时,LLM可能选错工具。比如用户问"今天天气怎么样",Agent却调用了日历工具。这个问题可以通过优化工具描述来解决——每个工具的描述要清晰说明"什么时候该用我",而不是只写"我能做什么"。我通常会在工具描述里加一句"当用户询问XX类问题时使用此工具",效果很明显。

Agent的架构设计还有一个关键决策:单Agent还是多Agent。单Agent就是一个LLM带着一堆工具干活,简单直接,适合大多数场景。多Agent是把任务拆给多个专职Agent,比如一个负责检索、一个负责计算、一个负责审核,适合复杂流程。但多Agent的协调成本很高,通信开销大,调试也麻烦。我的经验是:能用单Agent解决的就别上多Agent,除非任务确实需要不同角色的专业分工。

1.3 连接层:MCP为什么突然成了标配

MCP(模型上下文协议)是最近一年AI应用架构里最大的变化。在MCP出现之前,每个AI应用要对接外部工具,都得自己写适配代码——对接数据库写一套、对接API写一套、对接文件系统再写一套,重复劳动不说,还容易出bug。MCP做的事情,就是把这些对接方式标准化了。

你可以把MCP理解成AI应用世界的USB接口。以前每个设备有自己的接口,现在统一成USB-C,插上就能用。MCP定义了一套标准的协议,工具提供方按照这个协议暴露自己的能力,AI应用按照这个协议调用工具,双方不用再互相适配。

MCP的核心概念有三个:Resources(资源)、Tools(工具)、Prompts(提示模板)。Resources是只读的数据,比如文件内容、数据库查询结果;Tools是可执行的操作,比如发送邮件、创建任务;Prompts是预定义的提示模板,方便复用。AI应用通过MCP Client连接到MCP Server,就能发现并使用这些能力。

实际用下来,MCP最大的价值是生态复用。以前你要对接一个数据库,得自己写代码;现在如果有一个现成的MCP Server,直接连上就能用。社区里已经有大量MCP Server,覆盖了文件系统、数据库、浏览器自动化、代码仓库等常见场景。我最近做的一个项目,需要让AI操作浏览器抓取数据,直接用了现成的浏览器MCP Server,省了至少两天的开发时间。

但MCP也不是银弹。我遇到的问题是MCP Server的质量参差不齐,有些Server的工具有bug,有些描述不清楚导致LLM选错工具。所以选MCP Server时,一定要先测试,确认工具行为符合预期再集成。另外,MCP的连接是有状态的,如果Server挂了,Client要能优雅降级,不能让整个应用崩溃。

1.4 记忆层:让AI记住该记住的,忘掉该忘掉的

记忆系统是AI应用里最容易被低估的部分。很多人觉得记忆就是"把对话历史存下来",其实远不止。一个完整的记忆系统要解决四个问题:存什么、怎么存、怎么取、怎么忘。

存什么?不是所有对话都值得存。用户的偏好、重要的事实、达成的结论,这些值得长期记住;寒暄、重复确认、临时信息,这些用完就该丢。我通常会把记忆分成三层:短期记忆(当前会话的上下文)、长期记忆(跨会话的重要信息)、工作记忆(当前任务相关的临时信息)。

怎么存?最简单的做法是存文本,检索时用关键词匹配。但这种方式召回率低,用户换个说法就找不到了。更好的做法是向量化存储——把记忆内容转成向量,检索时用语义相似度匹配。这样即使用户换了表达方式,只要意思相近就能召回。再进一步,可以给记忆加上元数据(时间、来源、重要性),检索时综合语义相似度和元数据做排序。

怎么取?这是记忆系统最核心的环节。取多了,上下文被无关信息占满,模型注意力被分散;取少了,关键信息缺失,回答不准确。我的经验是先粗排再精排:先用向量检索召回一批候选,再用重排序模型精排,最后只取Top-3到Top-5条注入上下文。另外,检索时要考虑时间衰减——越久远的记忆权重越低,除非它被反复引用。

怎么忘?这是最容易被忽略的。记忆不是越多越好,过时的、矛盾的、低价值的记忆会干扰模型判断。我通常会设置记忆过期策略:临时记忆会话结束就清,长期记忆定期做一次"记忆整理",把矛盾的、过时的清理掉。这个整理过程可以交给LLM来做——让它判断哪些记忆还有效、哪些该合并、哪些该删除。

2. 架构设计中最容易翻车的三个决策点

架构设计不是画一张漂亮的图就完事了,真正难的是做决策。每个决策背后都有取舍,选错了后面要花几倍的成本来弥补。我复盘过自己做过的几个AI应用项目,发现翻车最多的是三个决策点:同步还是异步、集中还是分布、通用还是专用。

2.1 同步调用与异步编排:选错了用户体验直接崩

AI应用的响应时间天然比传统应用长。LLM推理本身就要几秒,如果再加上工具调用、检索、多轮循环,十几秒甚至几十秒都很正常。这时候如果还用传统的同步请求-响应模式,用户等几秒没反应就以为卡死了。

我第一个AI项目就栽在这上面。用户点一下按钮,前端发请求,后端调LLM,LLM调工具,工具查数据库,整个链路串行执行,平均响应时间15秒。用户等5秒就开始狂点按钮,结果触发了十几个重复请求,后端直接被打爆。

后来改成了异步编排模式:用户发起请求后,后端立即返回一个任务ID,然后通过流式输出(SSE或WebSocket)把中间状态推给前端。用户能看到"正在理解问题""正在检索资料""正在生成回答"这样的进度提示,等待焦虑大大降低。同时后端做了请求去重,同一个用户短时间内发起的相同请求只处理一次。

异步编排的另一个好处是可以并行。比如一个任务需要同时查数据库和调外部API,同步模式下只能串行,异步模式下可以并行发起,总耗时取最长的那个而不是两者之和。我做过一个测试,一个包含三个工具调用的任务,串行执行平均12秒,并行执行平均5秒,提升非常明显。

但异步也带来了新的复杂度:状态管理。任务执行到哪一步了、中间结果存在哪、失败了怎么重试,这些都要设计。我的做法是用一个轻量的任务队列(比如Redis Stream或者内存队列),每个任务有明确的状态机,状态转换时持久化,服务重启后能从断点恢复。

2.2 集中式与分布式:别为了分布式而分布式

AI应用架构设计里有一个常见的误区:一上来就搞微服务、搞分布式,觉得这样才"架构先进"。但实际上,大多数AI应用在早期根本不需要分布式,单体架构反而更合适。

我见过一个团队,三个人做一个AI客服应用,上来就拆了七八个微服务:用户服务、对话服务、模型服务、检索服务、工具服务、记忆服务、日志服务、网关服务。结果开发效率极低,改一个功能要动好几个服务,联调一次要启动一堆进程,部署运维更是噩梦。后来他们合并回单体,开发效率直接翻倍。

我的建议是:先用单体架构把核心流程跑通,等到确实遇到瓶颈了再拆。什么时候会遇到瓶颈?通常是这几种情况:某个模块的负载明显高于其他模块、不同模块需要不同的扩缩容策略、团队规模大到需要独立开发部署。在这些情况出现之前,单体架构的简单性带来的收益远大于分布式的扩展性。

当然,单体不等于"一坨代码"。即使是单体,也要做好模块化——模型调用、工具管理、记忆系统、编排逻辑,各自有清晰的边界和接口,只是部署在同一个进程里。这样将来真要拆的时候,改造成本很低。

2.3 通用Agent与专用Agent:能力越聚焦,效果越稳定

做Agent架构设计时,另一个关键决策是:做一个什么都能干的通用Agent,还是做多个各有所长的专用Agent?

通用Agent的诱惑很大——一个Agent带几十个工具,用户问什么都能答。但实际用下来,工具越多,Agent越容易犯迷糊。我做过一个实验:同一个Agent,带5个工具时任务成功率92%,带20个工具时成功率降到78%,带50个工具时成功率只有61%。原因是工具描述占用了大量上下文,LLM在众多选项中容易选错。

专用Agent则相反,每个Agent只带少量相关工具,聚焦特定场景。比如客服Agent只带订单查询、退换货、物流追踪这几个工具,代码助手Agent只带代码搜索、文件读写、终端执行这几个工具。这样LLM的选择空间小,决策更准确。

我的架构建议是路由+专用Agent的模式:前面放一个轻量的路由层(可以用小模型或者规则),判断用户意图属于哪个领域,然后分发给对应的专用Agent。这样既保证了每个Agent的聚焦性,又能覆盖多个场景。路由层本身不需要太复杂,一个分类任务而已,小模型足够。

3. 工具调用与MCP集成的实操细节

工具调用是Agent从"只会聊天"变成"能干活"的关键。但工具调用的设计有很多细节,做不好就会出现"Agent选错工具""工具参数传错""工具结果解析失败"等问题。这一章我把自己在工具调用和MCP集成上踩过的坑和总结的经验完整讲一遍。

3.1 工具描述怎么写,LLM才能选对

工具描述是LLM选择工具的唯一依据。描述写得好,LLM选得准;描述写得差,LLM全靠猜。我见过很多工具描述只写了一句"查询用户信息",LLM根本不知道什么时候该用、参数怎么传。

一个好的工具描述应该包含四个要素:功能说明、使用场景、参数说明、返回说明。功能说明讲这个工具能做什么;使用场景讲什么时候该用它,最好给出正例和反例;参数说明讲每个参数的含义、类型、是否必填、取值范围;返回说明讲返回什么格式的数据,方便LLM解析。

举个例子,一个查询订单的工具,描述可以这样写:

功能:根据订单号查询订单的详细信息,包括商品、金额、状态、物流。 使用场景:当用户询问某个订单的状态、金额、物流信息时使用。 不要用于:查询用户的所有订单列表(用list_orders工具)。 参数: order_id (string, 必填): 订单号,格式为"ORD"开头的12位字符串。 返回:JSON对象,包含order_id、status、amount、items、tracking_info字段。

这样写,LLM基本不会选错。另外,工具数量控制在10个以内,超过10个就要考虑分组或者路由。如果确实需要很多工具,可以按场景拆成多个Agent,每个Agent只带自己场景的工具。

还有一个细节:工具名称要语义化。query_order比qo好,send_email比se好。LLM对语义化的名称理解更准确。参数名也一样,user_id比uid好,start_date比sd好。

3.2 MCP Server的选型与自建

MCP生态现在很丰富,但质量参差不齐。选MCP Server时,我通常会看几个指标:维护活跃度(最近有没有更新)、文档完整度(有没有清晰的使用说明)、工具数量(工具太多反而不好)、错误处理(工具失败时返回什么)。

社区里比较成熟的MCP Server包括:文件系统操作、数据库查询、浏览器自动化、代码仓库操作、HTTP请求等。这些通用场景直接用现成的就行,没必要自己造轮子。但如果是业务特定的工具,比如对接公司内部的CRM系统,那就得自己写MCP Server。

自建MCP Server其实不难,核心就是实现MCP协议定义的几个接口。以Python为例,用官方SDK,一个最简单的MCP Server大概几十行代码:

from mcp.server import Server from mcp.types import Tool, TextContent server = Server("my-server") @server.list_tools() async def list_tools(): return [ Tool( name="query_customer", description="根据客户ID查询客户信息", inputSchema={ "type": "object", "properties": { "customer_id": {"type": "string", "description": "客户ID"} }, "required": ["customer_id"] } ) ] @server.call_tool() async def call_tool(name, arguments): if name == "query_customer": result = await query_customer_db(arguments["customer_id"]) return [TextContent(type="text", text=result)]

自建MCP Server的关键是错误处理要完善。工具执行失败时,不要直接抛异常,而是返回一个结构化的错误信息,让LLM知道发生了什么、能不能重试。我通常会把错误分成三类:参数错误(LLM传错了参数,告诉它正确格式)、临时错误(网络超时之类,可以重试)、永久错误(资源不存在,不要重试)。这样LLM能根据错误类型决定下一步动作。

3.3 工具调用的容错与重试策略

工具调用不可能100%成功,网络会抖动、API会限流、数据库会超时。如果每次失败都直接报错给用户,体验会很差。所以工具调用层必须有容错和重试机制。

我的做法是分级重试:对于临时性错误(超时、限流),自动重试2-3次,每次重试间隔递增(比如1秒、2秒、4秒);对于参数错误,不重试,直接把错误信息返回给LLM,让它修正参数后重新调用;对于永久错误,不重试,返回明确的错误信息。

重试还有一个细节:幂等性。查询类工具天然幂等,重试没问题;但写入类工具(比如创建订单、发送邮件)不幂等,重试可能导致重复操作。对于这类工具,要么在工具层面做幂等(用唯一ID去重),要么在Agent层面记录已执行的操作,避免重复调用。

另外,超时设置很重要。每个工具调用都要设超时,不能无限等待。超时时间根据工具类型定:本地查询设2-3秒,外部API设5-10秒,复杂计算设30秒。超时后要么重试,要么返回超时错误让LLM决定下一步。

4. 记忆系统的工程实现:从存储到检索的完整链路

记忆系统是AI应用里技术含量最高的模块之一。它涉及存储、检索、排序、注入、更新等多个环节,每个环节都有讲究。这一章我把记忆系统的完整实现链路拆开讲,包括数据结构设计、检索策略、注入方式、更新机制。

4.1 记忆的数据结构:不只是文本加向量

最简单的记忆存储就是"文本+向量",但实际项目中这样不够用。一个完整的记忆记录应该包含这些字段:

字段类型说明
idstring唯一标识
contentstring记忆内容原文
embeddingvector内容的向量表示
typeenum记忆类型:事实、偏好、结论、事件
sourcestring来源:对话、文档、工具结果
importancefloat重要性评分,0-1
created_attimestamp创建时间
last_accessedtimestamp最后访问时间
access_countint访问次数
metadatajson其他元数据

这些字段各有用途。type用于分类检索,比如用户问"我之前说过什么偏好",就只检索type=preference的记忆。importance用于排序,重要的记忆优先注入。last_accessed和access_count用于时间衰减和热度排序,经常被访问的记忆权重更高。metadata用于存一些场景特定的信息,比如关联的会话ID、涉及的产品ID等。

向量的维度取决于用的embedding模型,常见的有768维、1024维、1536维。维度越高表达能力越强,但存储和检索成本也越高。我的经验是1024维是个不错的平衡点,大多数场景够用。

4.2 检索策略:语义检索只是第一步

记忆检索的核心是"在正确的时间找到正确的记忆"。只用语义相似度检索是不够的,因为语义相似不代表当前有用。比如用户问"帮我订机票",语义检索可能召回一条"用户喜欢靠窗座位"的记忆,这条记忆虽然语义相关,但当前任务还没到选座那一步,注入它反而干扰。

我的检索策略是多路召回+综合排序。多路召回包括:语义检索(向量相似度)、关键词检索(BM25)、时间检索(最近的记忆)、类型检索(特定类型的记忆)。每路召回一批候选,然后综合排序。

综合排序的公式大概是这样的:

score = w1 * semantic_similarity + w2 * keyword_match + w3 * importance + w4 * recency + w5 * access_frequency

权重根据场景调整。比如客服场景,importance和recency权重要高;知识问答场景,semantic_similarity权重要高。我通常先用默认权重跑,然后根据badcase调整。

排序之后,还要做去重和冲突检测。如果两条记忆内容重复,只保留最新的;如果两条记忆矛盾(比如用户先说喜欢红色后说喜欢蓝色),保留最新的,或者把两条都注入让LLM判断。我倾向于保留最新的,因为用户的偏好会变。

4.3 记忆注入:怎么塞进上下文才不干扰模型

检索到记忆后,怎么注入上下文也有讲究。最粗暴的做法是把记忆直接拼在用户问题前面,但这样容易干扰模型。更好的做法是结构化注入,把记忆放在系统提示词的特定区域,并明确标注这是"背景信息"。

我通常的注入格式是这样的:

[背景信息] - 用户偏好:喜欢简洁的回答,不喜欢冗长的解释 - 历史事实:用户上个月咨询过退款政策 - 相关结论:用户对价格比较敏感 [用户问题] 帮我推荐一个套餐

这样模型能清楚区分哪些是背景、哪些是当前问题。另外,记忆数量要控制,通常3-5条足够,太多会稀释注意力。如果检索到很多相关记忆,只取排序最高的几条。

还有一个细节:记忆的时效性标注。如果一条记忆是三个月前的,注入时标注一下时间,让模型知道这条信息可能过时了。比如"[背景信息](2025年10月记录)用户当时偏好..."。这样模型会酌情参考,不会把过时信息当当前事实。

4.4 记忆更新:什么时候写、写什么、怎么合并

记忆更新是记忆系统里最容易被忽略的环节。很多人只做了"读",没做"写",导致记忆永远是初始的那几条。完整的记忆系统要能自动从对话中提取值得记住的信息,并更新到存储里。

什么时候写?我的做法是会话结束时批量提取,而不是每轮对话都写。每轮都写会产生大量碎片化记忆,检索时噪音很大。会话结束时,让LLM回顾整个对话,提取出值得长期记住的信息,去重合并后写入。

写什么?不是所有信息都值得记。我通常让LLM按这几个类别提取:用户偏好(喜欢什么、不喜欢什么)、重要事实(用户告诉你的关键信息)、达成结论(讨论后确定的方案)、待办事项(用户说要做什么)。其他寒暄、重复确认、临时信息都不记。

怎么合并?新记忆写入前,先检索是否有相似记忆。如果有,判断是更新还是新增。比如用户之前说"喜欢红色",现在说"喜欢蓝色",这是更新,把旧记忆标记为过时,写入新记忆。如果用户之前说"喜欢红色",现在说"也喜欢蓝色",这是新增,两条都保留。合并逻辑可以交给LLM判断,给它新旧两条记忆,让它决定是更新、新增还是忽略。

5. 从Demo到生产:AI应用上线前必须做的几件事

Demo跑通和生产可用之间,隔着一条巨大的鸿沟。我见过太多项目,Demo演示时效果惊艳,一上线就各种问题。这一章我把自己上线AI应用前必做的几件事列出来,都是血泪教训换来的。

5.1 评测集:没有评测就没有优化方向

AI应用最怕的是"感觉效果还行"。"感觉"是不可靠的,今天感觉好,明天可能就感觉差,而且不同人感觉不一样。要持续优化,必须有量化评测。

评测集怎么建?我的做法是从真实日志里采样。上线初期先跑一段时间,收集真实用户请求,然后人工标注一批(通常200-500条),标注内容包括:期望的输出、期望调用的工具、期望的检索结果。这批数据就是评测集。

评测指标分几个层面:端到端指标(任务成功率、平均响应时间、用户满意度)、中间指标(工具选择准确率、检索召回率、记忆命中率)、成本指标(平均token消耗、平均调用次数)。端到端指标反映整体效果,中间指标帮助定位问题,成本指标控制开销。

有了评测集,每次改动都能量化对比。比如改了工具描述,跑一遍评测集,看工具选择准确率有没有提升。改了检索策略,看召回率有没有变化。没有评测集,改动就是盲人摸象。

5.2 可观测性:出问题时能快速定位

AI应用的可观测性比传统应用更重要,因为它的行为是不确定的。同样的输入,可能因为模型版本、温度参数、上下文差异而产生不同输出。出问题时,如果没有完整的日志,根本不知道发生了什么。

我通常会记录这些信息:每次LLM调用的完整输入输出(包括系统提示词、用户输入、模型输出)、每次工具调用的参数和结果、每次检索的查询和召回结果、整个请求的链路追踪ID。这些信息存在结构化日志里,方便查询和分析。

链路追踪特别重要。一个用户请求可能经过路由、检索、LLM调用、工具调用、再LLM调用等多个环节,每个环节的耗时、输入输出都要记录,并且用同一个trace_id串起来。这样出问题时,能快速定位是哪个环节出了问题。

另外,关键指标要实时监控:请求量、成功率、平均延迟、token消耗、工具调用失败率。这些指标异常时自动告警,不用等用户反馈。

5.3 降级与兜底:模型挂了应用不能挂

AI应用依赖的外部服务很多:模型API、向量数据库、MCP Server、外部工具API。任何一个挂了,应用都可能不可用。所以必须有降级和兜底策略。

模型API挂了怎么办?如果有多个模型提供商,自动切换到备用模型。如果只有一个,降级到规则引擎或者预设回复。我通常会准备一套兜底话术,比如"当前服务繁忙,请稍后再试",至少让用户知道发生了什么,而不是一直转圈。

向量数据库挂了怎么办?降级到关键词检索,虽然召回率低一些,但至少能用。MCP Server挂了怎么办?把对应的工具标记为不可用,Agent在决策时跳过这些工具。外部工具API挂了怎么办?返回明确的错误信息,让LLM决定是重试还是换方案。

降级策略要提前设计、提前测试。不要等真的挂了才想怎么办。我通常会做故障演练:手动停掉某个服务,看应用能不能正常降级,用户体验受多大影响。

5.4 成本控制:token烧起来比想象中快

AI应用的成本主要是token消耗。一个看似简单的请求,可能因为多轮循环、大量上下文、频繁工具调用而消耗大量token。如果不加控制,月底账单会很吓人。

成本控制的手段有几个:上下文精简(只注入必要信息,历史对话做摘要)、模型分级(简单任务用小模型)、缓存(相同或相似的请求复用结果)、循环限制(设置最大循环次数和最大token数)、工具结果截断(工具返回结果太长时截断,只保留关键部分)。

我做过一个优化,把系统提示词从2000token精简到800token,把历史对话从完整保留改成摘要压缩,把工具结果从完整返回改成只返回关键字段。这几项加起来,平均每个请求的token消耗降了60%,效果几乎没影响。

缓存也很有用。很多用户问的问题是相似的,比如"怎么退款""运费多少",这些问题的答案可以缓存。缓存命中时直接返回,不用调模型。缓存的关键是相似度匹配,不能只用精确匹配,要用语义匹配。用户换个说法问同样的问题,也应该命中缓存。

6. 一些关于架构演进的个人体会

做AI应用架构设计这几年,最大的感受是:架构不是设计出来的,是演进出来的。一开始想得再周全,实际跑起来总会遇到意想不到的问题。重要的不是一次设计到位,而是保持架构的可演进性。

我现在的做法是小步快跑:先用最简单的架构把核心流程跑通,上线收集反馈,然后根据实际问题逐步优化。每次优化只改一个点,改完跑评测集验证,有效就保留,无效就回滚。这样风险可控,而且每一步优化都有数据支撑。

另一个体会是不要过度追求新技术。AI领域新技术层出不穷,今天出个新框架,明天出个新协议。但新技术不一定适合你的场景,盲目跟进只会增加复杂度。我的原则是:先看这个技术解决了什么问题,再看这个问题我有没有。如果没有,就不跟。

最后,架构图是给人看的,不是给机器看的。画架构图的目的是让团队成员理解系统怎么运作、数据怎么流动、模块怎么交互。所以架构图要清晰、准确、有层次,不要为了好看而堆砌概念。我见过一些架构图,画得花里胡哨,各种框各种箭头,但看完还是不知道系统怎么跑。好的架构图,应该是新人看完就能理解系统全貌,知道改某个功能要动哪里。

这些就是我关于AI应用架构设计的一些经验。架构设计没有标准答案,每个团队、每个场景都有自己的最优解。重要的是理解每一层的职责、每个决策的取舍,然后根据实际情况做选择。