1. 从“工具调用”到“协作伙伴”:Agent 范式到底变了什么
过去两年,我参与过不少 Agent 相关的项目,从最早的“LLM 套壳加几个 API”到后来逐步引入规划、记忆、反思机制,再到最近半年频繁接触 Harness 工程化落地,最大的感受是:Agent 这个词被用烂了,但真正理解它和 Tool 之间本质区别的人并不多。很多人嘴上说着 Agent,手里做的还是“给大模型挂几个函数”的活。这篇文章我想把论文里看到的范式演进和工业界踩过的坑串起来聊一聊,重点讲清楚 Tool、Skill、Harness 这几个概念在实战中到底怎么区分、怎么配合,以及为什么说 Agent 正在从“工具”变成“伙伴”。
先说结论:Tool 是能力,Skill 是策略,Agent 是意图的执行者,Harness 是让这三者稳定运转的工程骨架。这四者不是替代关系,而是层层包裹的关系。你如果只做了 Tool 调用,那叫“函数调用系统”;你如果加了 Skill 编排,那叫“工作流引擎”;只有当你让 Agent 自己决定用哪个 Skill、什么时候用、用完怎么评估结果、失败了怎么换路,这才算摸到了 Agent 的门槛。而 Harness 就是把这个过程工程化、可观测、可复现的那一层。
我见过太多团队一上来就堆 Tool,接了二三十个 API,结果 Agent 在真实场景里表现还不如一个写死的 if-else。问题出在哪?出在他们把“能力供给”当成了“智能”。Agent 的核心不是它能调多少工具,而是它能不能在模糊、多变、信息不全的环境里做出合理决策。这就像你给一个新人配了全套工具箱,但他不知道该用哪个、什么时候用、用错了怎么补救,那工具箱再多也没用。
所以这篇文章我会从四个层面展开:第一,把 Tool、Skill、Agent、Harness 的概念边界彻底厘清,用实际项目里的例子说明它们各自解决什么问题;第二,讲 Agent 架构设计中的核心决策点,包括规划模块、记忆模块、执行模块怎么搭,以及为什么很多 Agent 项目死在“规划”这一步;第三,深入 Harness 工程化实践,这是目前工业界最缺人、也最能拉开差距的方向,我会结合 DeepSeek Harness 这类工具的设计思路,讲清楚 Harness 到底在“Harness”什么;第四,整理一份实战避坑清单,把我在并发、安全、评估、调试这几个维度踩过的坑和对应的解法列出来。
适合谁看?如果你正在做 Agent 开发,或者准备从传统后端/算法转 Agent 方向,又或者你只是好奇“Agent 和普通 LLM 应用到底差在哪”,这篇文章应该都能给你一些可以直接抄作业的思路。我不会讲太多论文里的公式,更多是从工程落地角度说人话。
2. Tool、Skill、Agent、Harness:四个概念的真实边界
2.1 Tool 的本质是“无状态能力单元”
Tool 在 Agent 体系里就是最底层的原子能力。一个 Tool 通常对应一个明确的输入输出契约,比如“查天气”这个 Tool,输入城市名,输出温度湿度。它不关心谁调用它、为什么调用、调用完结果怎么用。Tool 的设计原则是:单一职责、无状态、幂等优先。
我见过一个反例:某团队把“发送邮件”和“记录发送日志”塞进同一个 Tool 里,结果 Agent 在重试时重复发了三封邮件。这就是典型的 Tool 职责不纯。正确的做法是拆成两个 Tool,或者把日志记录放到 Harness 层去做,Tool 本身只负责“发邮件”这一个动作。
Tool 的另一个关键点是描述质量决定调用准确率。很多人写 Tool 描述就一句话“查询用户信息”,然后抱怨 Agent 老是调错。你得把描述写成给一个新员工看的操作手册:这个 Tool 什么时候用、输入格式是什么、返回什么、有什么限制、失败了怎么办。我实测下来,Tool 描述从 20 字扩展到 200 字,调用准确率能提升 30% 以上。
2.2 Skill 是“带策略的能力组合”
Skill 和 Tool 最大的区别在于:Skill 有状态、有流程、有决策逻辑。一个 Skill 通常由多个 Tool 按特定顺序组合而成,并且包含条件分支和异常处理。比如“处理退款申请”这个 Skill,它可能包含:查订单 Tool → 验证退款资格 Tool → 计算退款金额 Tool → 发起退款 Tool → 通知用户 Tool。中间任何一步失败,Skill 要决定是重试、跳过还是终止。
这里有个容易混淆的点:Skill 到底应该由代码写死,还是由 LLM 动态生成?我的经验是核心业务 Skill 必须代码化,边缘场景可以 LLM 动态编排。原因很简单:核心业务要求稳定、可审计、可回滚,LLM 每次生成的流程可能都不一样,出了问题你连复现都做不到。而边缘场景本身就不确定,让 LLM 灵活处理反而更合适。
Skill 的另一个重要特征是可复用性。一个好的 Skill 应该像乐高积木一样,能在不同 Agent 之间共享。我现在的做法是把 Skill 注册到统一的 Skill 仓库里,每个 Skill 有明确的版本号、输入输出 schema、依赖的 Tool 列表、以及测试用例。这样当某个 Tool 升级时,我能快速知道哪些 Skill 会受影响。
2.3 Agent 是“意图驱动的决策主体”
Agent 和 Skill 的关系,有点像项目经理和施工队。Skill 负责“怎么干”,Agent 负责“干什么、为什么干、干到什么程度算完”。Agent 的核心能力包括:意图理解、任务分解、Skill 选择、执行监控、结果评估、失败恢复。
我观察到一个现象:很多 Agent 项目失败,不是因为 Skill 不够多,而是因为 Agent 的“评估能力”太弱。它不知道自己做得好不好,也不知道什么时候该停。比如你让 Agent“帮我整理一份竞品分析”,它可能调了十个搜索 Tool,生成了一堆内容,但根本不知道这些内容是否覆盖了关键维度。没有评估能力的 Agent,本质上只是一个自动化的 Tool 调用器。
Agent 的另一个关键设计点是记忆管理。短期记忆(当前对话上下文)和长期记忆(跨会话的知识积累)要分开处理。短期记忆用滑动窗口加摘要压缩,长期记忆用向量库加结构化标签。我踩过的坑是:把什么都往长期记忆里塞,结果检索时噪音太大,Agent 反而被误导。后来改成“只存经过验证的事实和用户明确偏好”,效果好了很多。
2.4 Harness 是“让 Agent 稳定跑的工程底座”
Harness 这个词最近很热,但很多人理解偏了。Harness 不是 Agent 框架,也不是 Tool 集合,它是让 Agent 在生产环境里可观测、可控制、可复现的那一层基础设施。你可以把它理解成 Agent 的“操作系统”。
Harness 通常包含这些能力:执行沙箱(隔离 Agent 的运行环境)、调用链追踪(记录每一步的输入输出和耗时)、权限控制(限制 Agent 能访问哪些资源)、限流熔断(防止 Agent 失控)、评估回放(把历史执行记录拿出来重新跑,验证改动效果)。
为什么 Harness 现在这么重要?因为 Agent 的行为是概率性的,同样的输入可能产生不同的执行路径。没有 Harness,你根本不知道线上那个 Agent 到底在干什么。我经历过一次线上事故:Agent 在某个边界条件下陷入了无限循环,疯狂调用搜索 Tool,半小时烧掉了几百块 API 费用。如果当时有 Harness 的调用链追踪和熔断机制,这个问题在第一次循环时就能被发现。
提示:如果你现在做的 Agent 还没有接入任何 Harness 层的能力,建议优先把“调用链追踪”和“费用熔断”这两个做起来,投入产出比最高。
3. Agent 架构设计的核心决策点
3.1 规划模块:为什么大多数 Agent 死在第一步
规划模块是 Agent 的大脑,负责把用户意图拆解成可执行的步骤序列。我见过三种主流的规划方案,各有适用场景。
第一种是静态规划,也就是提前把流程写死。比如“订机票”这个任务,固定就是:查航班 → 选航班 → 填乘客信息 → 支付 → 出票。这种方案稳定、可预测,但灵活性差,遇到“帮我订一张明天去上海的最便宜航班,但不要早于 9 点”这种带约束的需求就抓瞎。
第二种是动态规划,让 LLM 每次根据当前状态生成下一步。这种方案灵活,但容易“跑偏”。我实测过一个案例:让 Agent 规划“帮我准备一场技术分享”,它第一版规划里居然包含了“购买投影仪”这种完全不必要的步骤。原因是 LLM 把“准备分享”理解成了“准备场地”。
第三种是混合规划,也是我现在最推荐的方案:用静态模板定义任务骨架,用 LLM 填充具体参数和分支条件。比如“准备技术分享”的骨架是:确定主题 → 收集素材 → 制作大纲 → 制作幻灯片 → 预演。LLM 负责决定每个步骤的具体内容,但不能增删骨架步骤。这样既保证了流程可控,又保留了灵活性。
规划模块还有一个容易被忽视的点:规划粒度。粒度太粗,执行时容易卡住;粒度太细,规划本身的开销就很大。我的经验是:每个步骤的执行时间控制在 30 秒到 2 分钟之间。如果一个步骤预计超过 2 分钟,就继续拆;如果两个步骤加起来不到 30 秒,就合并。
3.2 记忆模块:短期、长期、工作记忆的三层设计
记忆模块的设计直接决定 Agent 能不能“记住事”和“学到东西”。我把记忆分成三层:
短期记忆就是当前会话的上下文,用滑动窗口管理。窗口大小不是越大越好,我实测下来 8K 到 16K token 是比较平衡的区间。超过这个范围,LLM 的注意力会被稀释,反而容易忽略关键信息。窗口满了之后,用 LLM 做一次摘要压缩,把旧内容压成几句话保留。
工作记忆是当前任务执行过程中的临时状态,比如“已经查了 3 个竞品,还差 2 个”。这部分我建议用结构化数据存储,而不是塞进 prompt 里。因为工作记忆需要频繁读写,塞 prompt 里每次都要重新生成,既慢又贵。
长期记忆是跨会话的知识积累,用向量库加元数据标签存储。这里的关键是写入策略:不是什么都要记。我的做法是只记三类内容:用户明确表达的偏好、经过验证的事实结论、以及失败教训。其他内容一律不写长期记忆,避免污染检索结果。
注意:长期记忆的检索一定要加时间衰减和置信度过滤。我踩过的坑是:半年前的一条过时信息被检索出来,导致 Agent 给出了错误建议。后来加了“超过 30 天的记忆置信度打七折”的规则,问题就解决了。
3.3 执行模块:Tool 调用的稳定性比智能更重要
执行模块负责实际调用 Tool 和 Skill。这里最大的误区是过度追求智能,忽视稳定性。我见过一个 Agent,规划做得花里胡哨,但执行时连最基本的“重试”都没做,一个网络抖动就整个任务失败。
执行模块的核心设计原则是:假设一切都会失败。每个 Tool 调用都要有超时、重试、降级三个机制。超时时间根据 Tool 的历史 P99 耗时来定,一般是 P99 的 1.5 倍。重试策略用指数退避,最多重试 3 次。降级方案要提前准备好,比如搜索 Tool 挂了,就降级到缓存结果。
另一个关键点是并发控制。Agent 在执行时经常需要同时调用多个 Tool,比如同时查三个数据源。这时候要控制并发数,不能无限开线程。我的经验是:IO 密集型 Tool 并发数控制在 5 到 10 之间,CPU 密集型控制在核数以内。超过这个范围,收益递减,但失败率会上升。
3.4 评估模块:没有评估的 Agent 就是盲盒
评估模块是区分“玩具 Agent”和“生产 Agent”的分水岭。评估分两个层面:单步评估和端到端评估。
单步评估是在每个 Skill 执行完后,判断这一步是否成功。比如“查订单”这个 Skill,评估标准可以是“返回了订单号且状态字段非空”。单步评估要快、要轻,不能引入额外的 LLM 调用,否则成本受不了。我一般用规则引擎做单步评估,只有规则无法判断时才调 LLM。
端到端评估是在整个任务完成后,判断最终结果是否满足用户意图。这个可以用 LLM as Judge 来做,但要设计好评判标准。我的做法是给 Judge 提供三个维度的评分:完整性(是否覆盖了所有要求)、准确性(信息是否正确)、可用性(结果是否直接可用)。每个维度 1 到 5 分,总分低于 3 分就触发人工复核。
评估结果要回流到规划模块,形成闭环。如果某个 Skill 连续多次评估不通过,就要考虑替换或优化这个 Skill。这个反馈循环是 Agent 持续进化的关键。
4. Harness 工程化:让 Agent 从 Demo 走向生产
4.1 Harness 到底在“Harness”什么
Harness 这个词直译是“马具”,引申为“控制、驾驭”。在 Agent 语境下,Harness 驾驭的是 Agent 的不确定性。LLM 的输出是概率性的,Agent 的执行路径是动态的,这两者叠加导致 Agent 的行为很难预测。Harness 的作用就是给这种不确定性套上缰绳。
具体来说,Harness 要解决四个问题:可观测性(Agent 每一步在干什么)、可控性(能不能在必要时干预或终止)、可复现性(同样的输入能不能得到可比较的输出)、安全性(Agent 会不会做出危险操作)。
我现在的项目里,Harness 层是独立于 Agent 逻辑的。Agent 只管“想干什么”,Harness 管“能不能干、怎么干、干完记录什么”。这种分层设计的好处是:Agent 逻辑可以快速迭代,Harness 层保持稳定。换一个 Agent 框架,Harness 层几乎不用改。
4.2 执行沙箱:隔离是安全的第一道防线
执行沙箱是 Harness 最基础也最重要的能力。Agent 执行的任何代码、调用的任何 Tool,都应该在沙箱里运行。沙箱要限制:文件系统访问范围、网络访问白名单、CPU 和内存配额、执行时间上限。
我见过一个真实案例:某团队的 Agent 在调试时执行了一段 LLM 生成的代码,结果这段代码把服务器上的一个配置文件删了。原因就是没有沙箱隔离,Agent 直接在生产环境上跑。后来他们引入了容器化沙箱,每个 Agent 任务跑在独立容器里,文件系统只读挂载,网络只允许访问白名单域名,问题就再也没出现过。
沙箱的粒度也要考虑。按任务隔离还是按会话隔离?我的建议是按任务隔离。因为不同任务之间可能互相干扰,比如任务 A 写了一个临时文件,任务 B 读到了这个文件,就会产生不可预期的行为。按任务隔离虽然资源开销大一点,但换来的是确定性。
4.3 调用链追踪:Agent 的“黑匣子”
调用链追踪记录 Agent 执行过程中的每一个关键事件:LLM 调用(输入 prompt、输出内容、token 消耗、耗时)、Tool 调用(参数、返回值、耗时、是否成功)、Skill 切换(从哪个 Skill 到哪个 Skill、触发条件)、状态变更(记忆写入、任务状态更新)。
这些数据要能按任务 ID、会话 ID、时间范围等维度检索。我常用的排查流程是:先看任务整体耗时分布,找到耗时异常的环节;再看该环节的输入输出,判断是 LLM 的问题还是 Tool 的问题;最后看上下文,确认是不是上游数据有问题。
调用链追踪还有一个重要作用:成本归因。Agent 的 API 费用往往很高,但钱花在哪了?有了追踪数据,你可以精确算出每个任务、每个 Skill、每个 Tool 的 token 消耗和费用。我靠这个数据砍掉了一个“看起来有用但实际很少被调用”的 Skill,每月省了 20% 的 API 费用。
4.4 限流熔断:防止 Agent 失控的最后一道闸
Agent 失控的表现形式很多:无限循环、疯狂重试、并发爆炸、token 消耗失控。限流熔断就是针对这些情况的保护机制。
限流分三个维度:单任务限流(一个任务最多调用多少次 LLM/Tool)、单用户限流(一个用户同时最多跑几个任务)、全局限流(整个系统每秒最多处理多少请求)。这三个维度的阈值要根据实际容量来定,我一般从保守值开始,逐步调优。
熔断是在检测到异常时主动切断。触发条件可以是:连续失败次数超过阈值、单任务耗时超过上限、token 消耗超过预算。熔断后要能优雅降级,比如返回“当前任务过于复杂,请简化后重试”,而不是直接报错。
提示:熔断阈值不要设得太死,要留人工干预的接口。我遇到过熔断误触发的情况,这时候需要能手动恢复,而不是等冷却时间。
4.5 评估回放:用历史数据验证改动效果
评估回放是 Harness 的高级能力,也是我认为最有价值的能力之一。它的思路是:把历史执行记录保存下来,当 Agent 逻辑或 Skill 实现发生变更时,用同样的输入重新跑一遍,对比新旧结果。
这个能力解决了一个核心痛点:Agent 的改动效果很难评估。你改了一个 prompt,怎么知道是变好了还是变差了?靠线上 A/B 测试成本太高,靠人工抽查样本量又不够。评估回放可以快速给出量化对比。
我现在的做法是:每次上线前,从历史记录里抽 100 到 200 个代表性任务,跑一遍回放,对比关键指标(任务完成率、平均耗时、平均 token 消耗、评估得分)。如果新版本在多个指标上都优于旧版本,才允许上线。这个流程帮我避免了好几次“看起来改好了实际改坏了”的情况。
5. 实战避坑清单:并发、安全、评估、调试
5.1 并发问题:Agent 怎么扛住高并发
Agent 的并发挑战和传统 Web 服务不一样。传统服务的请求是独立的,Agent 的请求可能共享状态(比如共享记忆库、共享 Skill 注册表)。这就导致并发问题更复杂。
我踩过的坑包括:两个任务同时写同一条记忆,导致数据覆盖;多个任务同时调用同一个有状态 Tool,导致状态混乱;Skill 注册表在热更新时被并发读取,导致部分任务读到旧版本。
解决方案是分层加锁:记忆写入用乐观锁加版本号,冲突时重试;有状态 Tool 用队列串行化,或者改成无状态设计;Skill 注册表用读写锁,更新时短暂阻塞读操作。另外,任务调度要支持优先级,重要任务优先分配资源,避免被低优先级任务挤占。
5.2 安全问题:Agent 的权限边界怎么划
Agent 安全是个大话题,我这里只讲最核心的:最小权限原则。Agent 能访问的资源,应该是完成任务所必需的最小集合。比如一个“查资料”的 Agent,就不应该给它“写文件”的权限。
具体做法:每个 Tool 声明自己需要的权限,Harness 在调用前检查当前 Agent 是否有这些权限。权限按任务类型分配,而不是按 Agent 实例分配。这样即使某个 Agent 被注入攻击,它能造成的破坏也是有限的。
另一个重点是输入输出过滤。Agent 的输入可能包含恶意 prompt,输出可能包含敏感信息。要在 Harness 层做过滤,而不是依赖 Agent 自己判断。我一般用规则加小模型做过滤,规则处理已知模式,小模型处理变体。
5.3 评估问题:怎么判断 Agent 到底行不行
评估 Agent 最难的地方是没有标准答案。传统机器学习有准确率、召回率,Agent 的任务往往是开放式的,怎么打分?
我的经验是分场景设计评估标准。对于有明确结果的任务(比如“查订单状态”),用规则判断;对于开放式任务(比如“写一份分析报告”),用 LLM as Judge 加人工抽检。Judge 的 prompt 要反复调优,我一般会准备 20 到 30 个标注样本,用来校准 Judge 的评分。
还有一个技巧:用“任务完成率”而不是“单步准确率”作为核心指标。因为 Agent 的价值在于端到端完成任务,中间某一步不完美但最终结果对,也是可以接受的。反过来,中间每步都对但最终结果错,那才是大问题。
5.4 调试问题:Agent 出错了怎么排查
Agent 调试比传统程序调试难得多,因为执行路径不确定。我的排查流程是:先复现,再定位,后修复。
复现是最难的。同样的输入,Agent 可能这次跑对下次跑错。我的做法是:Harness 记录完整的执行轨迹,包括每次 LLM 调用的随机种子(如果支持的话)。复现时用同样的种子和输入,大概率能得到相同的执行路径。
定位阶段,我会把执行轨迹按时间轴展开,找到第一个“异常点”。异常点可能是:LLM 输出格式不对、Tool 返回了预期外的值、评估模块误判。找到异常点后,再往前看是什么导致了它。
修复阶段,优先改 Harness 层(加校验、加兜底),其次改 Skill 层(调整流程),最后才改 prompt。因为 prompt 改动的影响面最大,最难评估。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 | 解决方案 |
|---|---|---|---|
| Agent 反复调用同一个 Tool | 评估模块未正确判断完成状态 | 检查评估规则和完成条件 | 增加完成状态校验,设置最大调用次数 |
| 任务耗时突然变长 | 某个 Tool 响应变慢或 LLM 输出变长 | 查看调用链耗时分布 | 加超时和降级,优化 prompt 长度 |
| 结果与预期偏差大 | 记忆污染或 Skill 选择错误 | 检查长期记忆检索结果 | 清理过期记忆,优化 Skill 描述 |
| token 消耗异常高 | 上下文窗口管理不当 | 统计每步 token 消耗 | 压缩历史上下文,减少冗余 prompt |
| 并发时结果错乱 | 共享状态未加锁 | 检查有状态资源的访问 | 加锁或改为无状态设计 |
| Agent 拒绝执行任务 | 权限不足或安全过滤误判 | 查看权限检查日志 | 调整权限配置,优化过滤规则 |
6. 从工具到伙伴:我对 Agent 未来形态的一些判断
聊了这么多工程细节,最后说点偏感受的东西。我做了这么久 Agent,最大的认知转变是:Agent 的价值不在于它多聪明,而在于它多可靠。一个能稳定完成 80% 常见任务的 Agent,比一个偶尔能完成 100% 任务但经常翻车的 Agent 有价值得多。
从 Tool 到 Skill 到 Agent 到 Harness,这条演进路径的本质是从“能力供给”走向“意图执行”。Tool 解决“能不能做”,Skill 解决“怎么做”,Agent 解决“做什么”,Harness 解决“做得稳不稳”。四个层次缺一不可,但优先级上,我认为 Harness 的投入应该排在前面。因为 Agent 的智能水平受限于 LLM 的能力,短期内很难有质变,但工程稳定性是可以靠投入快速提升的。
我现在看一个 Agent 项目,第一眼不看它的规划多花哨,而是看它的 Harness 层有没有做好。调用链追踪、沙箱隔离、限流熔断、评估回放,这四个能力有没有?如果没有,那这个项目大概率还停留在 Demo 阶段。
至于“伙伴”这个说法,我觉得现在还处于早期。真正的伙伴关系需要 Agent 能理解长期目标、能主动提出建议、能在不确定时主动求助。这些能力目前还在论文阶段,工业界落地的不多。但方向是明确的:Agent 会从“你让它干什么它就干什么”逐步走向“它知道你想干什么,并且能帮你干得更好”。
这个系列我打算继续写下去,下一篇想聊聊 Agent 的评估体系怎么从零搭建,包括 Judge prompt 的设计、标注样本的构造、以及怎么用评估数据驱动 Agent 迭代。如果你也在做类似的事情,欢迎交流。