这两年真正动手做过 AI Agent 的人,大概率都有过同一个体验:模型本身并不差,差的是怎么把模型组织成一个能稳定干活的系统。我最早接触 Agent 的时候,想法非常朴素——把大模型接上几个工具,让它自己调用就行了。结果一到真实任务就露馅:任务复杂度稍微上来,模型就开始在中间步骤里“自由发挥”,要么工具返回了错误它却视而不见,要么在同一个失败操作上反复重试,白白烧掉大量 token。后来我被逼着换了个思路,把一个 Agent 彻底拆开,逐个环节排查,才发现 Agent 工程化的问题从来不是“模型聪不聪明”,而是组成 Agent 的各个要素有没有被认真设计,七个关键决策点有没有被正面做过取舍。
这篇文章就是当时拆解过程的完整复盘。我会把 Agent 工程实现中绕不开的七个组成要素讲清楚,再沿着搭建时要回答的七个决策点逐个展开,每一步都给出我实测过的坑和调整方向。适合正在用 LangChain、LlamaIndex 这类框架开发 Agent,或者打算从零自己搭建一套 Agent 的工程师阅读。如果你还停留在“跑通 Demo”阶段,这篇文章能帮你省掉不少“看起来能跑、一用就崩”的冤枉路。
1. 七要素拆解:先搞清楚 Agent 在工程上到底由什么组成
我见过不少人把 Agent 直接等同于“大模型 + 工具调用”。做 Demo 展示的时候,这个理解勉强够用;一旦进入真实业务,就会发现自己缺了一堆东西。从工程实现的角度看,一个完整的 Agent 至少要包含七个要素:推理核心、规划能力、记忆系统、工具调用、行动执行、反馈机制、运行环境。它们不是七个可以独立插拔的插件,而是互相耦合的七个环节——你改任何一个,都会影响其他六个的行为表现。
1.1 推理核心与规划层:Agent 的“大脑”和“路线图”
推理核心是那个大模型本身,负责理解用户目标、处理环境返回的信息、生成下一步决策。这里要强调一个容易被忽略的判断:模型的能力边界直接决定了 Agent 的上限。我在对比不同模型的时候发现,指令遵循能力和函数调用(function calling)的稳定性,比通用知识测试分数重要得多。Agent 本质上在循环执行“读状态 -> 决策 -> 输出结构化动作”,模型一旦在某一步输出格式不对,整个闭环就得中断。
规划层是“路线图”,它把一个大目标拆解成模型可以逐步执行的小步骤。最简单的做法是让模型在每一轮输出时写下“当前任务、下一步动作”;复杂一点的,先让模型产出完整计划,再逐项执行。这个环节最常见的误区,是把所有步骤一股脑写进 System Prompt,告诉模型“先做 A,再做 B,再做 C”。任务一变,Prompt 就得跟着改,毫无扩展性。工程化的做法,是让模型根据目标动态生成步骤,而不是在提示词里写死执行路径。
1.2 记忆与工具:Agent 的“笔记本”和“手”
记忆分为短期和长期两部分。短期记忆就是当前会话的上下文窗口,负责记录本回合内发生的事;长期记忆是存放在外部的历史信息,比如用户偏好、领域知识、历史操作记录,需要时再检索回来。不少 Agent 项目在初期不做长期记忆也能跑,但只要业务涉及跨会话或者大量历史数据,记忆系统就成了硬需求——不做的代价是上下文被撑爆,既费 token,又降低准确率。
工具层则是 Agent 能“动手”的关键。没有工具,模型只能输出文字,所有回答都停留在“建议”层面;有了工具,模型才能查数据库、发 HTTP 请求、读写文件、操作外部系统。工具层要处理的核心工程问题有三个:工具描述是否足够清晰,输入参数 schema 是否完备,以及调用失败时错误信息能否被模型正确理解。这三个问题我会在决策点四里详细展开。
1.3 行动与反馈:闭环是 Agent 与普通提示词工程的分水岭
行动层负责把模型决策变成真实可执行的动作,比如发起一次 API 调用、执行一段代码。这里很多人会忽略“结果怎么送回模型”这个细节:工具返回的数据、报错信息、超时状态,都要以结构化方式写回上下文,模型才可能在下一步做出正确判断。反馈机制则利用这些结果修正后续的决策方向。
一个闭环的 Agent,每一步都发生在“行动 -> 观察 -> 决策”的循环里,直到完成目标或者触发终止条件。这也是 Agent 和普通提示词工程最本质的区别:普通提示词是“一次性输出”,Agent 是“多轮自我纠错”。没有反馈闭环,你做的其实只是一个“会调工具的聊天机器人”,不算是工程意义上的 Agent。
1.4 运行环境:Agent 能碰到哪一层,决定了它能造成多大影响
运行环境是 Agent 运行时的权限边界——它能读哪些数据、调用哪些服务、操作哪些系统。做 Demo 时放开权限没有感觉,上了生产环境,权限不收敛一定会出问题。我见过一个内部 Agent 因为工具权限过宽,在一次测试中误删了测试环境的一批数据,直接引发事故。工程上务必做到最小权限:能只读就只读,能隔离就隔离,能加审计就加审计。别等到出了问题再回来补权限,那时候代价往往已经付过了。
2. 决策点一:模型选型——先别盯榜单,先看 Agent 的“稳定调用”能力
很多人选模型时最爱比较“哪家排行榜分数高”,但对 Agent 工程来说,最关键的指标不是通用推理分数,而是函数调用(function calling)的稳定性和指令遵循率。模型能不能稳定输出“该调用哪个工具、参数是什么”的结构化结果,直接决定 Agent 能不能跑下去。
2.1 为什么函数调用稳定性比分数更重要
一个 Agent 任务里,模型几乎每一轮都要输出结构化动作。只要模型经常输出格式错误、参数缺漏、或者幻觉出不存在的工具名,再强的推理能力也发挥不出来。我在对比实测中发现,相同任务在不同模型上的成功率差异可以非常大,特别是工具数量超过十个时,有些模型会开始频繁选错工具。所以我的选型习惯是,先建一个“Agent 专项测试集”,专门考察多工具场景下的正确调用率、参数准确性、错误恢复能力,而不是靠几个问答样本来拍板。
2.2 上下文长度是加分项,不是必选项
现在聊天模型普遍宣传 200K 上下文,不少团队因此觉得买了大上下文模型,记忆问题就解决了。这是典型的错觉。上下文窗口再大,塞满之后照样影响延迟和效果;而且 Agent 每轮带着状态走,几十轮就把窗口打满。与其为超大上下文付出高昂成本,不如在记忆层、上下文压缩上做工程处理,具体方案我在决策点五里讲。选型时,更应该看“有效注意力范围内的准确度”,而不是“能装多少 token”这个数字。
2.3 成本与并发:不要只算单步单价,要算单任务总成本
Agent 跟普通聊天的成本模型完全不同。一次问答可能花一两万 token,一个复杂 Agent 任务可能循环几十步,每一步都把累积的上下文送到模型里,单任务总 token 会非常可观。所以选型时不能只看模型单价,还要估“平均步数 x 平均每步 token”这两个变量。
我在一个项目里做过真实测算:用某家大参数模型做 Agent,单个任务总成本比中等参数模型高出五倍,成功率只提升了六个百分点。后来我们微调了架构,用中等模型加更精细的工具描述,把成功率和体验拉回同一水平,成本还降了一半。这个案例说明,模型选型很少是“选最好的”,而是“在成本、稳定性、上下文策略之间做权衡”。
3. 决策点二:规划策略——ReAct 还是 Plan-and-Execute,本质是“探索”与“流程”的取舍
第二个无论如何都要正面回答的决策,是 Agent 怎么组织自己的行动步骤:每一步“想一下再做一下”(ReAct),还是“先整体规划,再逐步执行”(Plan-and-Execute)。这两个模式看着只是顺序不同,实际跑起来,体验天差地别。
3.1 两种模式各自的长处和短板
ReAct 模式让模型先思考当前状态,做出一个动作,观察结果,再思考下一步。它的最大优势是灵活,特别适合你不知道确切步骤、必须边做边摸索的探索型任务。缺点是步数越多,token 消耗越大,而且模型在中后期容易逐渐偏离最初的任务目标——这是长任务中最常见的失控方式。
Plan-and-Execute 模式让模型先把整个任务拆成一份步骤计划,再按计划逐一执行。它的优势是整体感强,任务目标一直摆在那里,不容易跑偏,适合步骤相对明确的业务场景。缺点也很明显:如果第一步计划就错了,后面会全盘照着错误方向走,所以必须额外设计“计划修正”机制,在发现某一步不符合预期时重新规划。
3.2 实际项目里怎么选:混合路线最稳
我的经验是优先考虑 Plan-and-Execute 的变体,而不是让 Agent 完全自由地 ReAct。理由很简单:真实业务中,你通常对任务有相当程度的了解,可以做一个初步规划;即使模型计划得不够好,也能通过“每步执行后对照计划”来纠正。纯 ReAct 在长时间任务中的失控率明显更高。
更稳的折中方案是混合:首轮让模型产出初步计划,之后每个执行步让模型生成“当前状态 + 下一步动作 + 这一步对整体计划的影响”。这样既保留了规划的锚点,又保留了执行时的灵活性。我在生产环境里推荐的就是这个形态,它比单纯 ReAct 少了很多“跑着跑着忘了目标”的情况。
3.3 终止条件和失败重试必须提前写死在工程里
选好规划模式之后,还要给 Agent 定死终止条件:目标达成、达到最大步数、或模型判定失败,三者必须至少有一个生效。否则 Agent 会无限循环,费用跟着失控。我在生产环境里看到过太多因为重试策略不明确导致的死循环,模型连续十次调用同一个失败工具,照样不放弃。
同时要设计失败重试的决策链:工具调用出错时,是重试、换一个工具、还是上报失败?这个判断不能完全交给模型自由发挥,应该在工程层预设好规则,比如“固定工具连续失败两次以上,进入人工兜底流程”。没有这层防护,Agent 的稳定性永远建立在对模型自律性的幻想上。
4. 决策点三:记忆架构——“什么都往向量库里塞”其实是最贵的偷懒
记忆系统在 Agent 工程里被高估的同时也被低估。高估的是大家相信“加个向量数据库,Agent 就有记忆了”;低估的是真正做好记忆,牵涉到的工程细节远比想象中多。如果所有历史都无脑往向量库里塞,你会很快发现检索回来的内容经常不是最关键的,而是最相似的,模型反而更糊涂。
4.1 记忆分层的工程设计
我建议按职能把记忆拆成三层。第一层是工作记忆,负责当前任务上下文,保留最近几轮的对话和工具结果,用完后做压缩;第二层是情景记忆,负责跨会话的用户偏好、关键决策、历史任务摘要,可以用结构化存储加向量检索;第三层是语义知识,负责领域知识库内容,通常预先构建,与单个用户历史关系不大。
三层各自对存储方案的要求完全不同。工作记忆留在上下文里,由 token 管理控制;情景记忆比较适合向量库,但没有必要每轮都查;语义知识只在当前任务明确涉及某个领域时按需检索。很多人做出来的 Agent 变慢,往往不是模型慢,而是每轮都去向量库捞一大批无关片段,把上下文塞满,模型判断力自然下降。
4.2 写长期记忆的门槛要设高一点
最容易犯的错误就是“全量写入”——把每一轮工具输出、每一段用户对话都往向量库里写。这样做短期内看着“记录得很全”,用一周之后检索质量就会急剧下降,因为相似的片段实在太多了,召回的正确率越来越差。
真正值得写入长期记忆的,是那些“对后续任务有确定性价值”的信息:用户明确表达的偏好、用户纠正过的错误认知、任务最终结果、关键业务实体。我建议每次写入前,先用模型做一个判断——“这条信息如果未来被检索到,会不会帮助 Agent 做更好的决策?”有价值才写入。这个“记忆整理”步骤会多花一次模型调用,但换来的是长期记忆系统的可用性,这笔账非常划算。
4.3 记忆的时效性:过期记忆比没有记忆更糟糕
实战里我还发现,记忆的“过期策略”是必须明确设计的点。用户偏好会变、历史订单会更新、地址会改动,如果旧信息一直占据检索权重,Agent 就会被过期记忆误导。简单可行的做法是给每条记忆增加时间戳和置信度字段,检索时做加权排序,超过有效期的降权或者直接清理。
这一层在 Agent 上线初期看不到明显作用,但运行时间越长,它的价值越突出。我见过好几个项目上线一个月后效果明显下滑,排查下来都不是模型退化了,而是长期记忆里积累了太多过期且互相冲突的信息,把决策信号搅浑了。早点把过期策略做进去,后面省的是整夜的排查时间。
5. 决策点四:工具接口设计——模型没法跟你“心有灵犀”,所以工具描述就是契约
工具层是 Agent“动手”的通道,但很多人把它理解为“注册几个 Python 函数”就完事了。真正的工程化,是把工具设计成一份模型和系统都能理解的接口契约。你的工具描述写得好不好,直接决定模型选对工具的概率;你的返回值规不规范,直接决定模型能不能理解执行结果。
5.1 工具描述写“什么时候用”,别只写“能做什么”
在函数描述里,光写“查询订单”远远不够。模型做决策时需要区分的是“该查订单还是该查库存”,所以描述必须包含使用场景。比如:查询订单——当用户询问订单状态、物流信息、售后进度时使用;查询库存——当用户询问商品是否有货、库存数量、补货时间时使用。加上这类场景说明,工具选择准确率能在不更换模型的前提下获得明显提升。这是我每次搭新 Agent 都优先做的低成本优化。
5.2 工具粒度:太粗会失控,太细会噎住
工具粒度是另一个关键决策。如果把“整站下单流程”做成一个工具,模型无法控制中间步骤,出错了也很难定位;可如果拆得过细,十几个参数让模型一次性填对,填错率反而上升。实践下来,比较稳的做法是中等粒度加参数收敛:一个工具只完成一个有明确输入输出的子任务,参数尽量控制在五个以内;能做枚举就别用自由文本,能设计默认值就别让模型必须填。整体上,参数越是收敛,模型调用工具的出错率越低。
工具数量多了之后还会遇到一个问题:功能相近的工具会让模型产生选择困难。这时候要在描述里明确写清楚差异点,甚至可以直接写“本工具与 XX 工具的区别在于……”,把容易混淆的边界直接点破。这种描述层面的“排错”比换模型便宜得多。
5.3 返回结构和错误处理必须形成契约
工具返回给模型的格式,建议统一成 JSON 结构,明确区分成功状态、业务数据、错误信息。一个血泪教训是:错误信息写得含糊,比如只返回“调用失败”,模型经常理解成“工具成功了但没有结果”,然后在没有任何实质进展的情况下反复重试同一个工具。所以每条错误信息里,都要尽量带上“失败原因 + 下一步建议”。前端数据异常返回失败代码,网络超时返回超时标记,权限不足返回权限错误并明确告诉模型“不要重试”。这些约定都是 Agent 稳定性的隐形支柱,越早定下来越好。
6. 决策点五:上下文与状态管理——Token 预算是 Agent 的命脉
做过 Agent 的人都会承认:上下文窗口是目前最稀缺的资源。模型调用费用、延迟、最终效果全都和上下文内容直接相关。如果不加控制,一个多步任务会随着历史消息越堆越长,先是变慢,然后是变笨,最后直接跑不动。
6.1 三种上下文裁剪策略,以及我习惯的组合
常见的裁剪手段有三种。第一种是直接截断最旧的消息,实现最简单,但会丢掉早期关键决策;第二种是滚动总结,每 N 轮历史就调用模型生成一段摘要,用摘要替换旧轮次,适合对话型 Agent;第三种是关键信息抽取,把当前状态、用户约束、已完成步骤提取成一个结构化“状态块”,放在每轮上下文最前面。
我的实践是把三种策略组合起来:每轮开始前,对当前上下文做一次“总结 + 状态块”压缩,用摘要替换掉中间轮的原始消息,只保留最近三五轮原始消息供模型精细决策。这样既能控制 token 总量,又不丢失任务关键信息。实测下来,Agent 在长任务里的稳定性和成本控制都有明显改善。
6.2 系统提示词也要做 Token 瘦身
系统提示词是每轮调用都要计入的固定开销。很多人喜欢往里面塞大量公司资料、背景说明、规则手册,动辄两三千 token。问题在于,这些内容不是每轮都重要,反而会摊薄模型对当前步骤的注意力。
工程做法是“分层注入”:把真正时刻需要的核心规则放进系统提示词,按需使用的知识放到知识库,在相关步骤触发时再检索注入。我做过一次很直观的优化,把系统提示词从 2800 token 压到 600 token,模型工具选择的准确率反而提升了 7 个百分点。内容少了,模型注意力更聚焦,效果自然上来了。
6.3 状态持久化:Agent 会话比 HTTP 请求活得久得多
Agent 任务动辄持续几十分钟甚至几小时,中途进程挂了怎么办?会话状态必须做持久化。正确的做法是每轮循环结束后,把当前任务计划、已完成步骤、状态块、决策历史全部写入存储。这样进程重启后,Agent 能恢复到最近的决策点继续执行,而不是从头再来。
这里要特别区分两个概念:上下文是给模型看的“当前信号”,状态库是给程序用的“执行快照”。两者各管各的,不要图省事把所有状态都塞进对话历史里。一旦混在一起,你既没法做精准的 token 压缩,也没法在重启后准确恢复。这个是很多自研 Agent 框架设计时的通病。
7. 决策点六:单 Agent 还是多 Agent——单体没做稳之前,别急着让人开会
多 Agent 是这两年的热门话题,很多人一上来就规划“三个 Agent 协作完成任务”的架构。但工程上我必须先说一句逆耳的话:绝大多数业务场景,单 Agent 加工具已经够用。多 Agent 引入的沟通开销、上下文分裂、调试复杂度,都是成倍增长的。它不是一个免费升级,而是一笔需要算清楚的投资。
7.1 什么情况才真正需要多 Agent
我的判断标准很直白:单 Agent 的上下文已经不可控,或者任务需要多个专业角色并行处理时,才考虑多 Agent。典型场景包括:一个 Agent 负责理解用户意图,另一个 Agent 负责数据操作,还有一个负责审核输出,三者职责互不重叠。注意,职责必须“不重叠”,否则大家都会抢着做同一件事,结果互相矛盾。
如果只是任务步骤复杂,优先靠规划、记忆、工具设计去解决,而不是拆分角色。多 Agent 最常见的失败形态,是几个 Agent 各干各的,没有一个统一目标,最后产出互相冲突的内容,效果比单 Agent 还差。分布式系统的复杂度,不会因为加了层模型就消失。
7.2 协作模式:主从编排比议会讨论更可控
多 Agent 的协作模式有很多种,我建议从最简单的主从模式开始:一个编排 Agent 负责拆解任务、分派子任务、汇总结果;若干个执行 Agent 只负责执行分配下去的子任务。这种模式的调试性最好,因为你总能定位到“是编排者决策错了,还是某个执行者执行错了”。
议会讨论模式看起来很美——多个 Agent 自由讨论、投票决定方案——但在生产环境里稳定性很差。投票过程消耗大量 token,模型之间又容易相互说服,最后得到的常常不是更理性的结论,而是更强词夺理的结论。不是不能做,但它更适合用于研究性项目,不适合默认业务链路。
7.3 多 Agent 之间的上下文隔离,比任何框架都重要
多 Agent 之间必然要传递信息,但工程上不要把所有内容都塞进一个共享上下文。应该只传递“任务描述 + 必要数据 + 约束条件”。每个执行 Agent 都有自己的独立上下文,避免执行过程中的中间噪音污染其他 Agent。
需要共享的状态,应该写入一个统一状态中心,各 Agent 按需读取。其实这又回到了记忆架构的设计:Agent 与 Agent 之间的通信,本质上就是记忆系统的一次接口调用,而不是“让所有 Agent 围观同一份聊天记录”。顺着这个思路设计,多 Agent 系统会清爽很多。
8. 决策点七:可观测性与评测——没有 Trace 的 Agent 不值得上线
普通后端接口出了问题,你靠日志和报错堆栈就能定位。Agent 不一样,它是非确定性的多步系统,每轮都在决策和行动,无法用普通接口测试保证可用。没有可观测性,Agent 出错时你只能对着模型的原始输出猜,那效率低得可怕。这也是 Agent 工程和普通后端工程最大的不同:必须提前设计“看得到模型每一步在想什么、做了什么”的观测体系。
8.1 可观测性的三个层次:日志、Trace、评估
最基础的是日志:每个节点的输入、输出、工具调用结果、token 数、耗时都记录下来。再往上一层是 Trace:把一次 Agent 任务的完整决策链串起来,用户问了什么、模型想了什么、调了哪个工具、拿到了什么结果、下一步怎么决策。光有日志没有 Trace,你仍然很难把碎片拼成完整画面。
第三层是评估:准备一组标准任务定期跑回归,看成功率、平均步数、平均成本、延误率这些指标的变化。三个层次缺一个,你优化 Agent 就只能靠感觉。尤其到了后期调 Prompt、调工具描述时,没有评估体系,你根本说不清这次改动到底是让系统变好了还是变差了。
8.2 评测集要提前建,失败用例要持续沉淀
很多团队把评估放在 Agent 开发完成后,这是顺序搞错了。正确做法是先建评测集,再开发功能。比如做一个客服 Agent,先准备五十个能代表真实用户分布的典型问题,标注好期望的工具调用路径和期望的最终回答;每次修改后跑一遍全部用例,哪条失败就说明哪次改动引入了回归。
评测集还应该是活的。每次真实环境里 Agent 表现不佳的案例,都值得整理进评测集里,长期维护成一个“失败用例库”。这大概是最笨但也最有效的 Agent 质量提升方式——每解决一个失败用例,系统就真实地变好了一点,而不是靠感觉调参。
8.3 上线的灰度与兜底,比模型切换更重要
上线时不要全量切流量,一定要灰度。要给 Agent 配置“人工兜底”的通道:Agent 处理不了时,能顺利转人工或走默认流程。很多自研 Agent 项目翻车,不是因为模型选得不好,而是上线前只测了 Happy Path,一遇到边界情况就崩,还没有兜底预案。
Agent 的稳定性永远不能靠模型自觉,只能靠工程上的失败降级和人工介入预案。你可以先让 Agent 只处理它最有把握的任务类型,其他全部转人工,等成功率稳定上来了再逐步扩大边界。这个渐进过程,才是 Agent 上生产环境的正确姿势。
这套“七要素 + 七个决策点”的框架,我自己用了很多遍之后,最大的体会是:Agent 从来不是“搭出来”的,而是“调出来”的。每个决策点都没有标准答案,并且它们互相牵制——选了便宜的模型,可能就得在工具描述上多花功夫;选了 Plan-and-Execute,就得同步设计计划修正机制;选了多 Agent,就要接受调试成本的上升。你不可能在方案评审阶段一次性全想对,但只要清楚每个决策点背后的权衡,迭代起来就有明确方向。
最后分享一个我一直在用的小技巧:每次只优化一个决策点,然后用同一套评测集跑三遍,盯住成功率、平均步数、平均成本三个指标。如果一次改动让成功率上升但成本暴涨,或者成本降了但成功率明显下滑,那就说明这个改动不划算,需要继续找平衡点。按这个节奏迭代几个月,你会明显看到 Agent 越来越稳定,而且每一分改进究竟花在了哪里,心里都有数。