1. 从工具调用到协作伙伴:Agent范式的本质变化
1.1 为什么“工具”这个词已经不够用了
过去两年,绝大多数人接触Agent的第一站都是“工具调用”。给LLM挂几个函数,让它能查天气、搜网页、读数据库,然后跑一个ReAct循环,看起来就像个Agent了。我最早做的一批项目也是这个路子,Function Calling加个while循环,能跑通demo,但一上生产就露馅。
问题出在哪?工具调用的心智模型是“人下指令,模型执行”。模型是个更聪明的命令行,你给它一个query,它选一个tool,返回结果,结束。这个模型在单轮、确定性任务里没问题,但一旦任务变成多步、有状态、需要根据中间结果调整策略,它立刻崩。因为工具调用没有“意图持续性”——模型不知道自己在为什么目标服务,它只是在每一步选一个看起来最合理的动作。
Agent范式的核心变化在于:模型不再只是选择动作,它要维护一个关于“我要去哪”的内部状态,并根据环境反馈持续修正这个状态。这就是从Tool到Agent的分水岭。Tool是动词,Agent是主语。你不再写“调用搜索工具”,你写“这个Agent负责调研某个主题,它自己决定什么时候搜、搜什么、搜完怎么判断够不够”。
1.2 Harness:被低估的工程层
热词里反复出现Harness,很多人第一反应是“这不就是个测试框架吗”。如果你只把Harness理解成跑评测的脚手架,那就错过了它真正的价值。在Agent语境下,Harness是模型与真实环境之间的全部工程胶水:它负责把模型的输出解析成可执行的动作,把环境的反馈压缩成模型能消化的观察,管理上下文窗口的裁剪与摘要,处理重试、超时、并发、幂等,以及在模型跑偏时把它拉回来。
我自己的经验是,一个Agent项目里,Harness的代码量通常是模型调用逻辑的5到10倍。你写prompt可能就几百行,但Harness里要处理的东西包括:工具返回结果太长怎么截断、工具报错怎么让模型理解而不是直接崩、多个工具并行调用时怎么合并结果、模型输出了非法JSON怎么修复、上下文快满了怎么摘要而不丢关键信息。这些东西没有一个是“AI问题”,全是工程问题,但它们决定了Agent能不能用。
DeepSeek Harness这类东西之所以被频繁搜索,本质上是因为大家发现:模型能力已经不是瓶颈了,瓶颈在Harness。同一个模型,Harness写得好和写得烂,任务完成率能差出三倍。
1.3 Skill:Agent的能力封装单元
Skill这个词在热词里出现频率极高,从“skill编码193”到“codex skill”到“豆包skill”,说明大家正在寻找一种比Tool更粗粒度、比Agent更细粒度的抽象。我的理解是:Tool是原子操作,Skill是完成一个子目标的完整能力包。
举个例子。Tool是“发送HTTP请求”,Skill是“抓取一个网页并提取正文”。Tool是“执行SQL”,Skill是“根据自然语言问题生成SQL并执行、验证结果、格式化输出”。Skill内部可能调用多个Tool,有自己的小循环,有自己的错误处理策略。它是对模型暴露的接口,但内部是工程实现。
这个抽象层次很重要,因为它让Agent的规划粒度变得合理。如果Agent直接规划到Tool级别,步骤太多,模型容易迷路;如果规划到Agent级别,又太粗,没法复用。Skill刚好卡在中间:Agent说“我需要调研这个主题”,它调用一个Research Skill;Skill内部自己决定搜几次、怎么筛选、怎么综合。Agent不需要知道Skill内部怎么实现的,就像你不需要知道搜索引擎怎么建索引的。
1.4 范式跃迁的工程含义
从Tool到Agent的跃迁,落到工程上意味着三件事。第一,状态管理从无到有。Tool调用是无状态的,Agent必须有状态,而且要决定状态存在哪、怎么持久化、怎么在崩溃后恢复。第二,错误处理从异常捕获变成策略选择。Tool报错就抛异常,Agent报错要考虑:是重试、换工具、还是告诉用户我做不到?这个决策本身就需要模型参与。第三,评测从单点变成轨迹。Tool调用只看最终结果对不对,Agent要看整条轨迹合不合理——有没有绕路、有没有该用工具时不用、有没有陷入循环。
这三件事没有一件是“调个API”能解决的,它们全是系统设计问题。这也是为什么我说Agent开发的门槛不在模型,在工程。
2. Agent核心架构拆解:规划、记忆与执行的三层结构
2.1 规划层:从静态分解到动态重规划
规划层是Agent的“大脑皮层”。最简单的做法是让模型一次性输出任务分解,然后按顺序执行。这个方案在任务步骤少于5步、且每步结果可预测时能用。但真实场景里,第三步的结果往往会改变第四步该做什么,静态分解直接失效。
我现在的做法是分层规划加动态重规划。顶层规划只定大方向,比如“先调研、再分析、最后输出报告”,不细化到具体动作。每个大方向下,Agent在执行时再生成当前步骤的具体动作。每完成一个子目标,Agent重新评估:目标变了吗?路径要调整吗?这个“评估-调整”循环是Agent和Workflow的本质区别。Workflow是预先画好的流程图,Agent是边走边画地图。
动态重规划的关键是设置重规划触发条件。不能每步都重规划,那样开销太大且容易震荡;也不能从不重规划,那样遇到意外就卡死。我的经验值是:当工具返回结果与预期偏差超过阈值、或者连续两次尝试同一类操作都失败、或者发现了规划时未知的新信息,这三个条件触发重规划。其他时候按原计划走。
2.2 记忆层:短期上下文与长期知识的分离
记忆层是最容易被做烂的部分。很多人把什么都往context window里塞,结果要么爆token,要么模型被无关信息干扰。我的架构里,记忆分三层。
第一层是工作记忆,就是当前任务的上下文,存在context window里,但要做主动裁剪。裁剪策略不是简单的FIFO,而是按“与当前子目标的相关性”排序,相关性低的先摘要再丢弃。第二层是情景记忆,存的是过去完成过的类似任务的经验,比如“上次处理这类数据时,某个工具返回的格式需要特殊解析”。这层用向量库存,按需检索。第三层是语义记忆,存的是领域知识、规则、约束,相对静态,可以预加载。
三层分离的好处是,工作记忆可以保持精简,情景记忆可以跨任务复用,语义记忆可以人工维护。混在一起的话,你没法独立优化任何一层。
2.3 执行层:工具编排与结果验证
执行层负责把规划变成动作。这里最核心的设计是结果验证。Tool调用返回结果后,不能直接喂给模型,要先过一道验证:格式对不对、内容是否为空、是否包含错误标识、数值是否在合理范围。验证不通过就触发重试或降级策略。
我见过太多Agent项目,工具返回个空结果,模型基于空结果继续推理,最后输出一堆看似合理实则完全错误的内容。这就是缺少验证层。验证层不需要很复杂,几个断言加一个重试逻辑就能挡住80%的问题。
另一个关键是并行与串行的决策。多个工具调用之间如果没有数据依赖,应该并行执行,省时间。但并行会带来结果合并的复杂度,以及部分失败的处理。我的做法是:默认串行,只有当工具调用彼此独立且延迟敏感时才并行,并且并行时给每个调用设独立的超时和降级路径。
2.4 三层之间的通信协议
三层之间怎么传递信息,这个接口设计决定了系统的可维护性。我的做法是定义一套内部消息格式,规划层输出的是“意图”,记忆层输出的是“相关上下文”,执行层输出的是“结构化结果加置信度”。所有跨层通信都走这个格式,不允许直接传自然语言。
为什么?因为自然语言在层间传递会累积歧义。规划层说“查一下最近的销售数据”,执行层理解成“查本月”,记忆层理解成“查本季度”,最后结果对不上。用结构化消息,字段明确,歧义在源头就被消除。模型只在层内处理自然语言,层间走结构化协议。
3. 工业界实战:从Demo到生产的五个关键改造
3.1 上下文工程:比Prompt工程重要十倍
Demo阶段大家比的是谁Prompt写得好,生产阶段比的是谁上下文管得好。一个真实任务跑下来,工具返回的原始数据可能几万token,全塞进去模型直接失焦。我的上下文工程策略是三级压缩。
第一级是工具层压缩,在工具返回结果进入Agent之前就处理。比如网页抓取只返回正文,不返回HTML;数据库查询只返回需要的列,不返回整行;日志只返回错误级别,不返回全部。这一级能砍掉70%的token。第二级是摘要压缩,对必须保留但太长的内容做摘要,摘要时保留关键实体、数值、结论,丢弃过程性描述。第三级是检索压缩,不把全部历史塞进context,而是根据当前子目标检索最相关的片段。
三级压缩做完,同样的任务token消耗能降到原来的五分之一,而且模型表现更好,因为干扰信息少了。
3.2 容错设计:让Agent在错误中继续前进
生产环境和Demo最大的区别是:Demo里工具永远返回正确结果,生产里工具随时可能挂。容错设计的核心原则是错误也是信息。工具报错不是终止信号,而是告诉Agent“这条路走不通,换一条”。
具体做法:每个工具调用都有超时、重试、降级三个配置。超时设短一点,快速失败比慢速成功更有价值。重试只对幂等操作做,且重试次数不超过两次。降级是提前准备好的备选方案,比如主搜索工具挂了就用备用搜索,结构化查询失败就退化成关键词搜索。
更重要的是,错误信息要经过处理再给模型。直接把“ConnectionError: timeout after 30s”丢给模型,模型不知道怎么办。处理成“搜索工具暂时不可用,你可以尝试用备用工具或调整查询策略”,模型就能做出合理决策。
3.3 并发与限流:Agent扛并发的实战方案
“AI Agent怎么扛并发”是热词里很实在的问题。Agent的并发比普通API复杂,因为一个Agent请求内部可能触发多次模型调用和工具调用,放大效应明显。一个用户请求可能变成十次模型调用加二十次工具调用,并发上来后下游服务直接被打爆。
我的方案是分层限流加请求合并。在Agent入口做用户级限流,每个用户同时最多跑N个Agent实例。在模型调用层做全局限流,保护模型API。在工具调用层做工具级限流,每个工具独立配额。请求合并是指:多个Agent实例如果请求相同的工具且参数相同,合并成一次调用,结果分发给所有请求方。
另外,Agent实例要设最大步数限制。没有这个限制,一个跑偏的Agent可能无限循环,把配额耗光。我的经验值是:简单任务20步,复杂任务50步,超过就强制终止并返回当前最佳结果。
3.4 可观测性:没有Trace就没有优化
Agent系统不上Trace,等于闭着眼睛开车。你需要知道每一次请求走了哪些步骤、每步花了多少时间、模型选了什么工具、工具返回了什么、哪一步失败了、失败原因是什么。这些信息不记录,出了问题根本没法排查。
我的Trace方案是结构化日志加可视化回放。每个Agent请求生成一个Trace ID,所有相关的模型调用、工具调用、状态变更都打上这个ID。日志字段包括:步骤序号、动作类型、输入摘要、输出摘要、耗时、token消耗、是否成功。可视化回放就是把Trace按时间轴画出来,一眼看出瓶颈在哪、哪步在绕路。
Trace的另一个用途是评测数据生成。把成功的Trace整理成few-shot示例,把失败的Trace整理成反例,用来改进Prompt和Harness。
3.5 评测体系:从单点测试到轨迹评估
Agent的评测不能只看最终答案对不对。一个Agent可能最终答案对了,但中间绕了十步弯路,或者调用了不该调用的工具,或者差点陷入循环。这些在单点测试里看不出来,但在生产里会变成成本和稳定性问题。
我的评测体系分三层。第一层是单元评测,测每个Skill和Tool的输入输出是否正确,这层是确定性的,可以自动化。第二层是轨迹评测,给定一个任务,跑多次,看轨迹的步数分布、工具使用分布、失败率。轨迹合理的标准是:步数在预期范围内、工具选择符合预期、没有重复无效操作。第三层是端到端评测,用真实用户任务集,看任务完成率和用户满意度。
轨迹评测是最容易被忽略但最有价值的一层。它能在任务完成率还没下降时,就发现Agent的行为在变差。
4. 常见问题与排查技巧实录
4.1 Agent陷入循环怎么办
循环是Agent最常见的故障。表现是Agent反复调用同一个工具、反复输出相似内容、或者在不同工具之间来回跳。根因通常是三个:一是工具返回结果没有提供新信息,Agent以为没成功所以重试;二是规划层没有设置“已尝试”标记,Agent忘了自己试过;三是终止条件不明确,Agent不知道什么时候算完成。
排查步骤:先看Trace,确认循环发生在哪一步。如果是工具返回无新信息,检查工具是否真的返回了有效结果,还是返回了空或错误但被当成成功。如果是规划层遗忘,在上下文里显式加入“已尝试动作列表”。如果是终止条件问题,在Prompt里明确写出完成标准,并在Harness里加硬性步数上限。
我的经验技巧是:给每个工具调用加一个结果指纹,如果连续两次调用的结果指纹相同,直接判定为循环,强制Agent换策略或终止。这个简单的机制能挡住大部分循环。
4.2 工具选择错误怎么纠正
Agent选错工具,通常是因为工具描述不够清晰,或者多个工具功能重叠。排查时先看工具描述:是否说清楚了“什么时候用这个工具”而不只是“这个工具做什么”。好的工具描述应该包含使用场景、输入要求、输出格式、以及与其他工具的区别。
如果描述没问题但还是选错,考虑在Harness里加工具选择约束。比如某些工具只在特定状态下可用,或者某些工具组合是互斥的。这些约束不用模型判断,直接在工程层强制。
另一个技巧是工具分组。把功能相近的工具放在一个组里,Agent先选组再选具体工具,降低选择难度。这就像给文件系统建目录,比把所有文件平铺在根目录好找。
4.3 上下文爆了怎么优雅降级
上下文快满时,不能简单截断,那样会丢关键信息。我的降级策略是按优先级丢弃。优先级从高到低:当前子目标、最近三步的完整交互、工具返回的关键结果、历史摘要、早期完整交互。丢弃时从低优先级开始,且丢弃前先做摘要。
具体操作:当token使用超过阈值(比如80%),触发降级流程。先把最老的非关键交互摘要成一句话,如果还不够,再把更早的摘要合并。整个过程在Harness里自动完成,模型无感知。
注意:降级阈值不要设太高,留出余量给模型输出。我一般设在75%到80%之间,超过就触发,不要等到95%才动手,那时候已经来不及了。
4.4 模型输出格式错误怎么修复
模型输出非法JSON、缺少必填字段、或者字段类型不对,这些在生产里天天发生。修复策略分三层。第一层是Prompt层预防,在系统提示里给出严格的输出格式示例,并说明“只输出JSON,不要有其他内容”。第二层是解析层容错,用宽松的解析器,能处理多余空格、尾随逗号、单引号等常见问题。第三层是修复层重试,解析失败时,把错误信息和原始输出一起发给模型,让它修复。
我的经验是,三层做完,格式错误率能从10%降到1%以下。剩下那1%通常是模型真的理解错了任务,不是格式问题,需要回到Prompt层解决。
4.5 常见问题速查表
| 问题现象 | 可能根因 | 排查动作 | 解决方向 |
|---|---|---|---|
| Agent反复调用同一工具 | 结果无新信息或未标记已尝试 | 看Trace确认循环位置 | 加结果指纹判重、加已尝试列表 |
| 工具选择错误 | 描述不清或功能重叠 | 检查工具描述和使用场景 | 优化描述、加选择约束、工具分组 |
| 上下文爆满 | 未做压缩或压缩不足 | 看token消耗分布 | 三级压缩、按优先级降级 |
| 输出格式错误 | Prompt不严或解析太紧 | 看错误样本 | 严格示例、宽松解析、修复重试 |
| 任务完成率下降 | 轨迹变差但未察觉 | 跑轨迹评测 | 分析步数和工具分布变化 |
| 并发下下游被打爆 | 无分层限流 | 看下游QPS | 分层限流、请求合并、步数上限 |
4.6 几个踩过的坑
第一个坑是过度依赖模型做决策。早期我把所有判断都交给模型,包括“这个结果够不够好”“要不要重试”。结果模型在这些元决策上表现很不稳定。后来我把这些决策改成规则引擎,模型只负责它擅长的部分——理解语义和生成内容。规则引擎负责流程控制。这个分工明确后,稳定性大幅提升。
第二个坑是忽略工具延迟。Demo时工具都是本地mock,毫秒级返回。生产里一个搜索工具可能三秒,一个数据库查询可能五秒。Agent串行调用五个工具就是十几秒,用户体验极差。后来我在Harness里加了并行调度和超时控制,把无依赖的工具调用并行化,延迟降了一半以上。
第三个坑是没有版本管理。Prompt改了、工具改了、Harness改了,但没有版本记录,出了问题不知道是哪个改动导致的。后来我给每次部署打版本号,Trace里记录版本,回滚时能精确定位。这个习惯救了我好几次。
5. 从能跑到好用:Agent工程的进阶方向
5.1 自我修正:让Agent学会反思
Agent跑完一个任务后,不应该直接结束,而应该有一个反思阶段。反思的内容包括:这次任务哪些步骤是必要的、哪些是绕路、哪个工具调用最有价值、如果重来会怎么调整。这些反思结果存进情景记忆,下次遇到类似任务时检索出来作为参考。
反思不需要很复杂,让模型用几句话总结就行。关键是这个总结要结构化,比如分成“有效动作”“无效动作”“改进建议”三个字段,方便后续检索和利用。我实测下来,加了反思的Agent,在重复类任务上的步数能减少20%到30%。
5.2 多Agent协作:什么时候需要,什么时候是过度设计
多Agent协作是热词,但我的观点是:大多数场景不需要多Agent。单Agent加多个Skill能解决80%的问题。多Agent适合的是任务天然可并行、且子任务之间耦合度低的场景,比如一个Agent负责调研、一个负责写作、一个负责审核,三者可以流水线作业。
如果要用多Agent,关键是定义清楚Agent之间的接口。每个Agent的输入输出必须是结构化的,不能靠自然语言传递。另外要有一个协调者角色,负责分配任务、收集结果、处理冲突。没有协调者的多Agent系统,最后往往变成互相等待或者重复劳动。
5.3 安全边界:Agent不能做什么
Agent能力越强,越要明确它不能做什么。我的做法是白名单加硬约束。工具层面,只暴露经过审核的工具,危险操作(删除、写入、发送)要么不暴露,要么加二次确认。数据层面,敏感字段在进入Agent之前就脱敏,Agent永远接触不到原始敏感数据。行为层面,设置硬性禁止动作列表,比如不允许Agent自主修改自己的Prompt或工具配置。
这些约束不能靠Prompt实现,Prompt可以被绕过。必须在Harness层用代码强制。模型可以建议,但执行权在工程层。
5.4 成本控制:Token不是免费的
Agent的token消耗是普通对话的几十倍,因为每一步都要带上下文。成本控制的核心是减少无效token。无效token来自三个地方:重复的上下文、过长的工具返回、不必要的模型调用。
减少重复上下文靠摘要和检索。减少过长返回靠工具层压缩。减少不必要调用靠规则引擎前置判断——有些决策不需要模型,规则就能做,就别浪费token。我做过一个优化,把“是否需要调用工具”的判断从模型改成规则,token消耗直接降了15%,准确率还升了。
5.5 人机协作:Agent不是替代人,是放大人的能力
最后说一个认知层面的东西。Agent的目标不是完全自主,而是让人从重复劳动中解放出来,专注于判断和决策。所以好的Agent设计应该包含人在环上的节点。比如关键决策前询问用户、不确定时请求澄清、高风险操作前要求确认。
这些节点不是Agent能力不足的表现,而是负责任的设计。一个从不让用户介入的Agent,要么能力极强(罕见),要么在悄悄犯错(常见)。我宁愿要一个会问问题的Agent,也不要一个闷头跑偏的Agent。
提示:人在环上的节点要设计得轻量。不要让用户填表单,而是给几个选项让用户点。用户的注意力是稀缺资源,每次介入都要有明确价值。
6. 我个人的一些实操体会
做Agent这一年多,最大的体会是:模型能力决定上限,工程质量决定下限。同一个模型,Harness写得好,任务完成率能从60%提到90%;Harness写得烂,再强的模型也跑不出稳定结果。所以如果你在做Agent项目,把70%的精力放在Harness、上下文管理、容错、评测上,30%放在Prompt和模型选择上。
另一个体会是不要追求一步到位。我见过太多项目想一开始就做通用Agent,结果什么都做不好。正确的路径是:先做一个垂直场景的Skill,把它做到95%可用;再加第二个Skill,处理Skill之间的协调;等Skill多了,再抽象出通用的规划层。自底向上比自顶向下靠谱得多。
最后一个体会是评测要趁早。不要等系统做完了才想怎么评。从第一天起就建评测集,哪怕只有十个案例。每次改动都跑一遍,看指标是升是降。没有评测的优化是盲目的,你觉得自己改进了,可能只是过拟合了最近遇到的几个case。
这套东西还在快速演进,今天的最佳实践明天可能就过时了。但底层的东西——状态管理、错误处理、上下文工程、可观测性——这些不会过时,因为它们解决的是工程本质问题,不是模型能力问题。把地基打牢,上面换什么模型都能接得住。