2026/10/25 10:20:36

AI Agent架构深度解析:从ReAct循环到多Agent协作

AI Agent架构深度解析:从ReAct循环到多Agent协作 我见过不少朋友第一次接触AI Agent时的反应给ChatGPT提个问题它能答让它“帮我查一下明天的机票”它也能一本正经地给出建议——但这并不是Agent这只是聊天。真正的Agent是让它自己决定“我要几步才能把事做完、每一步调用什么工具、拿到结果之后下一步怎么办、失败了怎么重试”最后把一件多步骤的完整任务跑通。作为“ai-agent教程”系列的第二篇这篇不讲花活专注把两个问题讲透Agent为什么非要这么设计以及当前主流的Agent架构到底长什么样。这篇内容适合两类人一类是刚看完上一篇教程、想深入理解Agent内部机制的初学者另一类是已经在做技术选型、需要在单Agent、多Agent、分布式架构之间做判断的开发者。我会从最底层的循环机制讲起逐层拆解现代Agent的模块组成再对比主流架构模式的优缺点最后给一个从零搭建的最小可用Agent代码带你完整走一遍真实调用链路。1. Agent与LLM的分水岭从“一句话回答”到“闭环执行”1.1 普通对话与Agent任务的本质区别很多人觉得Agent就是“给LLM套一层壳让它能调用工具”这话对了一半但漏掉了最核心的东西循环。普通的LLM对话本质是一次性的概率预测。你输入一段文本模型根据训练学到的模式预测下一个token最可能是什么输出一段回答结束。整个过程没有目标、没有状态、没有反馈就像你问一位顾问“北京到上海怎么走最划算”他给你一份方案但你真正去执行时遇到航班取消、换乘失败他并不知道也无法帮你兜底。Agent则完全不同。它围绕一个明确的目标把任务拆成若干步骤每个步骤都产生行动行动之后观察环境反馈根据反馈调整下一步。这个“行动-观察-再行动”的闭环才是Agent的本质。这也是我反复跟团队强调的一句话LLM是大脑Agent是大脑加手和眼睛通过循环把三者串起来。用一个类比帮助理解LLM像一个坐在办公室里只能看报告写建议的顾问Agent则像一个项目经理。项目经理手里有目标、有进度表、有能调动的人手工具每做完一件事就检查结果发现偏差立刻调整直到项目交付或者确认无法完成。1.2 Agent主循环里的“感知-推理-行动-观察”几乎所有Agent架构不管外面包了多复杂的框架最底层都是下面这个循环感知把当前的目标、历史对话、工具能力描述拼装成提示词发给LLM。推理LLM根据当前信息决定下一步动作可能是给最终答案也可能是“我需要调用某个工具”。行动如果是调用工具Agent执行对应的函数或API拿到结果。观察把工具结果作为新消息追加回上下文。回到第1步继续下一轮推理直到LLM认为任务已完成、达到最大迭代次数、或遇到无法恢复的错误。这个循环在代码里通常长这样def run_agent(user_message: str, max_iterations: int 5): messages [{role: system, content: SYSTEM_PROMPT}, {role: user, content: user_message}] for i in range(max_iterations): # 1. 推理把全部上下文交给LLM让它决定下一步 response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolsTOOLS, tool_choiceauto, ) message response.choices[0].message messages.append(message) # 2. 如果LLM没有要求调用工具说明任务完成 if not message.tool_calls: return message.content # 3. 行动遍历所有工具调用请求逐一执行 for tool_call in message.tool_calls: result execute_tool(tool_call) # 4. 观察把工具执行结果回填到上下文 messages.append({ role: tool, tool_call_id: tool_call.id, content: result, }) # 5. 回到循环顶部进行下一轮推理 return 达到最大迭代次数任务未完成。注意第2步的判断LLM一旦不再请求工具就意味着它认为可以给出最终答案了。这时候Agent退出循环把一个完整的结果交还给用户。很多初学朋友写循环时会漏掉这个退出条件结果Agent在“该停的时候不停”不停地猜用户还要什么白白消耗token。1.3 ReAct为什么能减少幻觉这个循环模式在学术界的名字叫ReAct——Reasoning and Acting让模型在推理痕迹Thought和行动Action之间交替。你可能听过这个词但不一定清楚它为什么有效。关键在于它把LLM的思考过程暴露在了工具反馈的真实结果之中。模型不再依赖自己“想象”出来的事实而是每一步都有外部环境提供的硬数据。比如模型如果只靠内部知识回答“北京现在多少度”它很可能给一个过时甚至编造的数字但在ReAct模式下它会先调用天气查询工具拿到真实返回值再基于这个值组织回答。这本质上是用外部世界约束模型的幻觉空间。我在实测中一个很深的感受是ReAct对工具结果能给出上下文极大的增强。原本模型容易在常识性问题上自信地胡说可一旦工具返回“订单状态已退款”模型就只能基于这个事实继续想编都编不圆。这也是为什么即使最简单的最小Agent也明显比纯Prompt工程调出来的“伪Agent”可靠得多。2. 拆开Agent看核心LLM、规划、记忆与工具层2.1 核心LLM只是“大脑”不是全部很多人以为Agent的价值全在模型换个更强的模型Agent就自动变强。真实情况是模型决定的是Agent的“推理天花板”而工程架构决定的是Agent能触到多高。哪怕是最强的商用模型如果你不给它工具、不给它状态、不设计循环它依然只是聊天机器人。所以现代Agent实践里核心LLM通常只负责两件事一是根据当前上下文决定下一步动作二是把若干工具结果整合成最终回答。其它的能力都靠外部模块补齐。这也是为什么架构设计比选模型更值得投入时间——模型可以随时换架构却决定了你的Agent能做多少事、能扛多复杂的任务。我建议做选型的朋友不要陷入“只追最强模型”的误区。很多Agent场景比如查单、填表、做简单分析用gpt-4o-mini级别的模型就够了成本只有旗舰模型的几十分之一速度还快一倍。真正的瓶颈往往在工具设计、记忆策略和循环控制上这些地方出了问题换再大的模型也救不回来。2.2 规划模块拆解、编排与自我反思当任务稍微复杂一点比如“帮我分析这份文档按月份生成销售趋势图再写成一段摘要发给主管”只靠一个简单的工具循环是不够的。Agent需要一个规划模块把大任务拆成子任务并确定子任务的执行顺序。规划分两种实现路线一种是完全让LLM在运行时动态规划——模型看到用户请求自己决定分几步走每步调用什么工具另一种是开发者用代码预先定义好工作流比如用LangGraph画一个状态机明确“先取数、再分析、后生成”LLM只在每个节点内部做决策。两种路线各有适合的场景。动态规划灵活能应对意外情况但不可控——我见过模型把“查天气”的任务规划出四五步无关操作。预定义工作流稳定可控但应对不了计划外的用户请求。成熟项目通常两者结合主线流程用代码固定异常分支和分支内的细节交给LLM自行决策。规划模块还包含一个容易被忽略的能力自我反思。就是在Agent执行完计划后增加一步“审视自己刚才的输出判断是否合理不合理就修正”。业界有几套实现比如LLM对自己的回答提出批评性意见再修改或者用另一个模型当裁判打分。我建议在业务影响大的Agent上加上这层——它相当于给Agent装了一道质检虽然增加一点延迟但能明显降低输出被滥用的风险。2.3 记忆系统短期上下文、长期知识与工作区记忆是Agent架构里最容易被低估的部分。聪明的读者可能已经发现前面那个主循环之所以能工作靠的就是把历史消息不断追加给LLM——这个上下文窗口就是Agent的短期记忆。但短期记忆有两个硬伤一是窗口有限装不下长时间跨度的信息二是对话一断记忆全丢。所以真正的Agent系统必须区分三层记忆短期记忆当前会话的上下文窗口直接存消息数组。管理要点是控制长度防止溢出。长期记忆跨会话保存的用户偏好、历史事实、业务知识。通常用向量数据库存embedding需要时做相似度检索这就是RAG的核心应用。打个比方短期记忆像便利贴长期记忆像档案柜。工作记忆当前任务执行过程中的中间状态比如已经完成哪些步骤、正在处理哪份文件、下一步待办是什么。在代码层面就是一个状态对象LangGraph里的State就是这个角色。我自己的经验是长期记忆的检索质量直接决定Agent在真实场景里的可用度。两个Agent用同一套代码检索做得好和做得差的体验可以天差地别。需要花时间调切分粒度、embedding模型、相似度阈值和重排逻辑这些属于RAG的范畴但记住一句话记忆系统不是“存进去再捞出来”那么简单的搬运它是Agent能否在长期任务中保持一致性和个性化的地基。2.4 工具层从Function Calling到模型上下文协议工具层是Agent的“手脚”决定了它真正能对世界做什么查数据库、发邮件、调第三方API、操作浏览器、执行代码……但工程上要解决的远不止“写一个函数然后让LLM调用”这么简单。首先是工具定义问题。LLM并不知道你的函数长什么样你需要用结构化描述告诉它这个工具叫什么、做什么用、参数有哪些、参数类型是什么。以OpenAI兼容接口为例工具描述是JSON Schema格式名字、描述、参数缺一不可。我踩过的坑是描述写得太笼统比如“查询天气”模型不知道该传“北京”还是“beijing”还是“Beijing, China”写得太啰嗦又白白消耗几百个token。好的工具描述要做到“让一个没见过这个函数的人也能准确调用”。其次是工具注册和调度。Agent可能同时有几十个工具你不能用一堆if-else硬编码。常见做法是维护一个工具注册表每个工具注册时带上名称、处理函数、参数Schema运行时根据LLM返回的函数名动态查找、执行、返回结果。这样新增一个工具只需要写一个函数加一行注册主循环完全不用改。这个做法在成熟的Agent框架里已经是标配LangChain的tool装饰器、OpenAI的function calling、以及我正在用的简单注册表模式本质都是这套逻辑。第三层是工具互联协议。2024年底到2025年行业内出现了一个很重要的趋势把Agent和工具之间的关系标准化。Anthropic提出的模型上下文协议MCP就是典型代表它把“工具接入”做成标准协议数据源和工具服务通过MCP server暴露能力Agent通过MCP client统一发现和调用。这意味着你为A项目写的一个数据库工具理论上可以直接复用到B项目不再需要为每个Agent重写适配层。如果你在做企业级Agent这个方向值得重点关注。这里整理一个模块对照表方便做架构设计时快速查漏模块核心职责常见失控点常用对策核心LLM决策与生成幻觉、决策漂移ReAct循环、外部工具反馈约束规划模块任务拆解与编排规划步骤过多或过少设置步骤上限、预置工作流兜底记忆系统短期上下文、长期知识、任务状态上下文溢出、检索失效摘要压缩、向量检索、状态快照工具层执行外部操作参数错误、调用失败Schema校验、重试机制、注册表动态调度3. 主流Agent架构模式单兵、班组与流水线3.1 单Agent的ReAct模式最快上线但不抗复杂目前最主流、最简单、也最容易被理解的Agent架构就是去中心化的单Agent模式一个Agent一个LLM若干工具一个主循环。第1章的代码就是一个典型实现。这种架构的优势是逻辑直观、调试容易、token消耗相对可控、上线速度快。我做过不少内部工具都是先用单Agent模式跑通第一天就能让业务方看到效果。如果任务是单机单域比如“查询订单状态并解释给用户”“从网页抓取信息并总结”“执行一个计算并把结果格式化”单Agent是最理性的选择。它的短板也很明显一个人同时处理太多角色时会顾此失彼。你把“数据采集”“数据清洗”“报告撰写”“质量审核”四个角色塞进同一个Agent它的系统提示词会变得巨长模型需要在多个职责间来回切换容易角色混淆——前一轮还在严谨地核对数据后一轮就开始放飞文风。这就是为什么更复杂的场景需要往多Agent方向走。3.2 多Agent协作架构跟手、裁决还是流水线当一个任务确实跨界需要多个专业角色配合时单Agent就不够用了。多Agent架构把不同角色拆成独立Agent每个Agent有自己的系统提示词、工具集和记忆角色之间互相协作像一个小型团队。从协作方式看常见的多Agent架构有三种第一种是“跟手/组织者模式”。一个主Agent通常叫Orchestrator或Planner负责理解用户意图把任务拆解后分派给不同子Agent每个子Agent完成任务后把结果汇报回来由主Agent综合成最终答案。AutoGen里最常用的就是这种模式。这套架构的可控性最好因为所有调度决策集中在一个Agent手里其它Agent都是“执行者”。第二种是“辩论/讨论模式”。多个Agent从不同视角或立场对同一个问题进行分析比如一个扮演乐观派、一个扮演风险派再有一个综合者把两边观点汇总成平衡的结论。这套模式在处理开放性问题、需要多角度验证的方案评审时效果很好但token消耗也非常可观——每一轮讨论都是一次完整的多Agent调用。第三种是“流水线模式”。任务严格按阶段递增比如Agent A负责抓数据Agent B负责清洗Agent C负责建模Agent D负责输出报告。每个Agent只吃前一个Agent的输出它的输出又成为下一个Agent的输入。CrewAI里对这种链式协作封装得非常好经常被用来做数据处理报告类任务。这套模式稳定性高、职责清晰但一旦中间某个环节出错错误会顺着流水线往下传所以必须要在每个节点输出时做质量检查。团队里我经常说一句话多Agent不是目的是手段。如果单Agent能解决问题就别为了“架构看起来很高级”而拆成多Agent——每多一个Agent你就多一份延迟、多一份token开销、多一个出错点。3.3 分层与分布式架构企业落地的MCP和网关模式聊完“班组”再聊聊企业级落地常见的分层与分布式架构。当Agent数量从几个涨到几十上百个你会发现单靠多Agent组队也不够了需要从团队管理升级到组织治理。这时候的架构设计参考的是微服务和分布式系统的老经验只不过服务变成了Agent。典型的分层结构是这样最上层是接入层负责和用户产品交互中间是编排层由调度服务统一路由请求给合适的Agent下层是执行层各种专业Agent和工具服务再往下是基础设施层包括模型网关、向量数据库、任务队列、日志与监控系统。这套架构里最关键的组件是智能体网关Agent Gateway。它有点像微服务时代的API网关负责统一鉴权、限流、Agent路由、超时控制和审计日志。用户不需要知道具体是哪个Agent在处理请求只需要面对网关暴露的一个稳定接口。这对企业来说意义重大业务方可以随时升级、替换、下线某个Agent外层完全无感。另一个重要的基础设施是MCP模型上下文协议的服务化部署。在分层架构里工具不再和Agent物理绑定而是以MCP Server的形式独立部署Agent通过MCP Client去发现和调用。这样工具层就变成了一个可以独立伸缩、单独维护的服务集群。比如你的团队有“查订单”“查库存”“发消息”三个工具它们各自是一个MCP服务订单Agent要用查订单工具时通过MCP协议远程调用就行。在分布式场景下需求量大时还可以做Agent的多实例部署用任务队列比如RabbitMQ或Kafka把请求分发到多个相同的Agent实例上并行处理。这里要提醒一件事Agent是有状态的多实例部署时要么确保每个实例之间的长期记忆共享通常通过向量数据库实现要么用粘性会话把同一用户的所有请求路由到同一个实例否则用户会明显感觉到Agent“失忆”。3.4 选型判断别用复杂度换收益最近市场上有大量多Agent框架和分布式架构的讨论几乎每个平台都在推“新一代Agent编排框架”很容易让人产生“不用多Agent就落伍了”的错觉。我的建议恰恰相反从最简单的架构起步用数据说话只有当瓶颈真的出现时再升级。架构模式适用场景优势短板代表实现单Agent ReAct单一职责、工具数量少、任务链路短简单直观、调试容易、成本低多角色任务容易混淆、扩展性有限手写主循环、LangChain多Agent协作任务需要多视角交叉验证、专业分工明确角色隔离、专业度高、可独立优化延迟高、token开销大、协作逻辑复杂AutoGen、CrewAI分层/分布式企业级多Agent规模化、多团队共享治理能力强、工具复用、便于扩容建设成本高、运维复杂自研网关MCP、LangGraph服务器化部署我见过一些团队业务还只有一个“查信息并总结”的需求就强行上了多Agent加消息队列结果运维成本超过了Agent本身带来的收益。反过来也见过用单Agent硬扛几十个工具的最后系统提示词写了两千行每次请求光让模型读懂规则就花了大量token。架构选型的关键是匹配真实复杂度工具少就单Agent任务线多就拆多Agent规模大到需要稳定性和治理能力再上分布式。4. 手把手搭一个最小可用Agent代码与实测4.1 搭建目标和环境准备理论讲了这么多现在动手。我们目标很明确搭一个能用自然语言完成任务的最小Agent它的Toolbox里有两个工具——一个查天气演示用静态映射一个做四则运算演示用解析计算。用户用中文提问Agent自行判断该调哪个工具拿到结果后再组织自然语言回复。环境方面需要Python 3.10以上安装openai库并配置好API Key。我这里以OpenAI兼容接口为例因为国内用兼容接口的人也很多逻辑完全一样只需要在代码里多传一个base_url参数指向你的服务网关。pip install openai python-dotenv把API Key写入环境变量或在代码里用os.getenv读取。这里提醒一句很多第一次做Agent的人会把密钥写死在代码里然后上传到公开仓库这是非常危险的习惯务必养成用环境变量或密钥管理服务存密钥的习惯。4.2 先给Agent准备两个工具工具定义分为两部分一部分是给LLM看的“使用说明”JSON Schema另一部分是真正执行的Python函数。定义工具时要记得描述一定要具体参数要清晰这样模型才不至于理解偏。# 给LLM看的工具定义 TOOLS [ { type: function, function: { name: get_weather, description: 查询指定城市的当前天气包括温度和风力, parameters: { type: object, properties: { city: {type: string, description: 城市名例如北京、上海} }, required: [city] } } }, { type: function, function: { name: calculate, description: 执行数学四则运算自动处理加减乘除和括号, parameters: { type: object, properties: { expression: {type: string, description: 数学表达式例如23*17} }, required: [expression] } } } ] # 真正的执行函数 def get_weather(city: str) - str: weather_map { 北京: 晴25℃无持续风向微风, 上海: 多云28℃东南风3级, 广州: 雷阵雨30℃南风2级 } return weather_map.get(city, f{city}暂无数据请稍后再试) def calculate(expression: str) - str: import re # 安全校验只允许数字和基本运算符号防止表达式注入 if not re.match(r^[\d\-*/(). ]$, expression): return 表达式包含非法字符仅支持数字和四则运算 try: result eval(expression) return str(result) except Exception as e: return f计算失败: {e}这里特别说明一下为什么calculate要做字符白名单校验。因为Python的eval直接执行表达式的过程如果有人传一个包含恶意代码的字符串比如删文件的命令后果会很严重。Agent工具本质上是一个“可以由外部输入触发的函数”它必须有和Web API相同的安全意识校验输入、限制权限、记录日志。这也是我反复强调的工具层防御思想。4.3 用十几行代码实现Agent主循环主循环的逻辑和第1章描述一致这里直接给完整实现。这个循环足够支撑很多真实场景也是理解通用Agent框架的一把钥匙——市面上的框架再复杂本质都是这个东西的增强版。from openai import OpenAI import json client OpenAI() # 通过环境变量读取API Key def execute_tool(tool_call): 根据LLM返回的tool_call动态执行对应函数 fn_name tool_call.function.name args json.loads(tool_call.function.arguments) if fn_name get_weather: return get_weather(args[city]) elif fn_name calculate: return calculate(args[expression]) return f未知工具: {fn_name} def run_agent(user_message: str, max_iterations: int 5): messages [ {role: system, content: 你是一个能调用工具完成用户请求的AI助手。 当用户需要天气信息时调用get_weather需要数学计算时调用calculate。 工具返回结果后再根据结果组织简洁自然的最终回复。}, {role: user, content: user_message} ] for i in range(max_iterations): response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolsTOOLS, tool_choiceauto, ) message response.choices[0].message messages.append(message) if not message.tool_calls: return message.content # 模型不再要工具任务完成 for tool_call in message.tool_calls: result execute_tool(tool_call) messages.append({ role: tool, tool_call_id: tool_call.id, content: result }) return 达到最大迭代次数任务未完成已安全终止。 if __name__ __main__: print(run_agent(北京天气怎么样另外帮我算一下 23*17 等于多少。))代码里最值得注意的细节有三处第一message.tool_calls可能同时包含多个工具调用请求。LLM在上下文充足、工具定义清晰的情况下有时会“聪明地”一次请求同时调用两个工具来提速。我们这里用循环逐一执行并把每个结果都以role为“tool”的消息回填带上对应的tool_call_id。tool_call_id是关联LLM请求和工具结果的关键字段漏了它模型就不知道这个结果对应哪次调用。第二max_iterations必须设置。Agent像一把会自我迭代的锯子如果没人喊停它会一直锯下去。我在生产环境里默认设10简单任务用5就够。设置上限不仅是为了防死循环也是在防token成本失控——每一轮调用都是真金白银。第三tool_choiceauto的含义是让模型自己决定是否调用工具、调用哪个。如果你想强制某个步骤必须用某个工具也可以设置成tool_choice{type: function, function: {name: get_weather}}但一般别这么做会破坏Agent的灵活性。4.4 实测一轮完整调用链我实际运行了这段代码打开调试日志能看到完整的调用链路第一步LLM收到用户请求“北京天气怎么样另外帮我算一下 2317”然后返回两个tool_calls——一个是get_weather参数是“北京”一个是calculate参数是“2317”。第二步Agent执行两个函数拿到“晴25℃无持续风向微风”和“391”。第三步把这两个结果回填给LLM。第四步LLM组织出最终回答“北京今天天气晴朗气温25℃微风。另外你问的23乘以17等于391。”如果你自己跑一遍可能会发现第一次请求的响应偶尔只调用其中一个工具这是正常的——模型对工具的描述理解有细微差异或者它选择“分两步走”。这种情况下一轮没做完主循环会继续下一轮让模型看到已有结果后补齐剩余动作。这正是循环的价值所在它不要求一次完美而是通过多轮反馈逼近正确结果。4.5 三个值得调的关键参数搭建完成后我建议你把注意力放在三个参数上它们对最终效果的影响远大于换模型第一个是温度temperature。默认0.7是通用推荐值但Agent场景我建议设低一点比如0.2到0.4。因为Agent的工作偏向“准确执行”而不是“创意发挥”温度过高会让模型在决定“要不要调工具”时飘忽不定出现“明明该查天气却自己编一个”的怪事。降低温度能让决策更稳定。第二个是系统提示词里的工具使用说明。前面说过工具的描述要具体但不啰嗦。实测下来描述里明确给出“当出现xx关键词时调用xx工具”这种条件式指引效果会明显好于只是罗列工具功能。因为模型在决策时走的是语义匹配条件越清晰匹配越准。第三个是max_tokens单次回答的最大token数。Agent不像纯聊天它每一步的回复要么是一次工具调用请求、要么是一段最终结果都不需要太长。给模型设一个合理的单轮输出上限能防止模型在中间步骤长篇大论解释自己的推理过程白白消耗预算。我们这里没写是因为OpenAI新版本接口会默认给一个值但如果你用的是别的API或自建模型这个参数必须手动控制。5. 真正的坑都在工程侧调试、记忆、成本与延迟5.1 Agent行为不确定调试要“录屏式”观测做Agent和做传统程序最大的区别是它跑一次一个样同一个输入、同一个模型两次结果可能不同。你很难用“打断点、看变量”的传统方式调试因为问题往往出在“模型那一轮到底是怎么想的”。我的实际做法是给Agent加“录屏式”日志每轮循环都把完整的messages数组、模型返回的原始响应包括tool_calls参数和tool_call_id、工具执行结果、耗时全部结构化落盘。这样无论Agent在线上出了什么问题我都能事后“回放”它每一步的思考过程和动作快速定位是工具描述不清、参数传错还是模型决策策略跑偏了。市面上有一些Agent可观测性工具比如Langfuse、LangSmith、Phoenix它们做的正是这件事自动追踪每一步LLM调用、token消耗、工具调用链。如果你用的是自研框架哪怕只用logging模块记录JSON日志也要保证日志结构足够完整别为了省事只记一句“调用了get_weather”——等到出问题时你会后悔的。另外复现问题也有技巧。遇到Agent行为不稳定不要只把temperature设为0就以为万事大吉。更可靠的做法是固定输入、固定模型版本、固定temperature同时记录模型返回时的seed参数如果接口支持这样能最大概率复现。但坦白说Agent的随机性无法完全消除——这也是为什么生产环境里要给关键路径加上人工审核或规则兜底而不是完全信任一次模型输出。5.2 上下文窗口溢出压缩与摘要策略第二个坑是上下文窗口溢出。Agent每一轮都会把之前所有消息重新发给模型轮数一多、工具结果一长token数很快逼近窗口上限。你必须主动管理上下文而不是等到报错再做处理。常用的招数有三种一是截断只保留最近N条消息把更早的历史直接丢掉。适合历史对当前任务无影响的场景。二是摘要用一个轻量模型把老对话归纳成一段摘要放进系统消息里既保留关键信息又大幅压缩token。适合长期对话场景。三是关键信息提取比如只保留用户的核心诉求、已完成的工具结果摘要、当前任务状态丢弃无关寒暄。我自己的默认策略是普通任务保留最近10轮消息超过就触发摘要压缩当任务跨天或跨会话时把长期记忆落到向量数据库从“对话上下文依赖”切到“知识检索依赖”。这里提醒一句压缩本质上是有损的如果被压缩掉的内容对后续决策很关键Agent就会“失忆”。所以压缩策略要配合工作记忆明确记录已完成步骤和待办事项一起用把“过程的细节”丢掉、把“状态的骨架”留住。5.3 成本与延迟失控预算上限和并行调用Agent的调用次数天然比普通LLM多成本也被放大。一个用户请求内部可能经历5到10次LLM调用每次调用又附带工具结果token消耗很容易是肉眼预估的3到5倍。控制成本是每个Agent项目必须做的功课。监控报告是第一步。只要记录每次调用的模型、token数、工具名、耗时你就能在一周内找出“成本黑洞”。我经历过的情况是一个Agent在设计时看起来每个工具都很合理但跑了两周一看明细超过半数的token花在了“模型反复校验和犹豫”上——它每轮都在重新分析同一个上下文迟迟不决定调用工具。这种问题靠降低温度、精简系统提示词、设置单轮输出上限就能优化掉大半。延迟方面最大的浪费来自串行等待。很多工具的调用是互相独立的比如用户同时问“北京和上海的天气怎么样”程序完全可以在同一轮里并行执行两个工具请求而不是等第一个返回再发第二个。上一节的演示代码里LLM如果想并行会一次性返回多个tool_calls我们用了for循环串行执行虽然在示例里感觉不到差异但在真实场景里这个for循环换成并发执行可以把整段延迟降低一半以上。如果你用Python可以改写成asyncio.gather统一执行所有工具调用再统一回填结果。还有一个小技巧是结果缓存。对天气查询、汇率、股票价格这类短时间内不会变化的数据可以用一个简单的TTL缓存把最近的结果存下来命中缓存就直接返回不走工具、不用再用模型消化一次结果既省token又省延迟。这个优化虽然简单但回报率在Agent场景里非常可观。5.4 工具调用失败的兜底逻辑工具调用不是每次都成功的。网络超时、参数类型不对、第三方接口返回500、用户提供的城市名在数据源里不存在……这些失败如果处理不当Agent会陷入两个极端要么直接把错误原样抛给用户让用户看一堆技术报错要么用想象力补全一个“看起来正确”的结果把人带进坑里。正确的做法是设计“失败回传”。工具执行捕获异常后不要抛出而是把错误信息作为正常的tool消息回传给模型让模型基于错误信息决定下一步可以换一个参数重试也可以转变策略用备选方案还可以如实告诉用户失败原因。比如查询城市不在列表里工具返回“该城市暂无数据”模型看到后会回复“抱歉目前数据库中还没有这个城市的信息”而不是编一个温度数字给用户。这部分在第4章的代码里已经体现——get_weather用get方法设置了默认返回calculate里也把异常转换成了字符串返回这些都是失败兜底的雏形。生产环境里还需要考虑重试策略。对瞬时性错误网络超时、偶尔的5xx可以重试一到两次对确定性错误参数非法、数据不存在重试也没意义直接让模型换路。另外那些会产生外部副作用的工具比如发邮件、转账、下单必须格外小心调用成功但网络返回超时这种情况千万不能盲目重发否则可能造成重复操作。这个场景下要做幂等控制给每次调用生成一个唯一请求ID让服务端去重。这是金融级Agent必须考虑的问题虽然很多项目用不到但只要你做的是“能对世界产生真实改变”的工具就必须把副作用管理提上日程。我在实际项目中还有一个体会工具层的稳定性顶半边天。再聪明的Agent如果工具的API时好时坏、参数定义含糊、返回结构不统一整个系统的体验都会被拖垮。与其反复调整模型Prompt不如把精力花在把工具定义做规范、把工具的容错和监控做扎实这才是性价比最高的优化方向。