去年我们做了一个内部 Agent,用来处理退款申请。Demo 很顺,能查订单、核对政策、发确认邮件。上线第一周出了个事故:服务重启,Agent 的任务状态丢了,它把已经处理过的申请又跑了一遍。用户收到两封确认邮件,财务那边多了一笔退款。
模型没做错什么。它只是不知道之前已经做过。
这类问题,Prompt 调不出来,换个更大的模型也没用。缺的是模型外面的运行时,我一般叫它 Agent Harness。
Agent 的故障,大多不在模型
Agent 在 demo 里表现好,是因为路径短、环境干净、失败也能重来。到了线上,问题会从各个地方冒出来:
工具超时之后,状态停在半路;同一封邮件被发两次;上下文越来越长,关键信息被挤掉;某一步返回了格式不对的 JSON,后面全乱;模型升级之后,原本能过的用例突然挂了;出了事故,日志里只有一段最终回复,不知道哪一步开始错。
这些问题有一个共同点:它们不是“模型能力”问题,而是“系统没有把模型管好”。
Harness 到底管什么
我不会把 Harness 做成一个大而全的平台。它更像一层薄薄的运行时,负责几件具体的事:
第一,驱动循环。决定下一步做什么、什么时候停、失败之后是重试还是交给人工。
第二,管工具。注册、调用、超时、重试、限流、幂等,都在这一层统一处理,不让业务代码各写一套。
第三,存状态。每一步的目标、动作、观察和中间结果都要落盘,进程重启后能接着跑。
第四,隔离执行。代码执行、文件访问、网络请求放进沙箱,限制能碰的范围。
第五,做策略。哪些工具能用、哪些动作要审批、每个任务花多少预算,由策略引擎判断,而不是让模型自己决定。
第六,留痕迹。每次 run 的每一步都要能追踪、能回放、能对比。
这六件事听起来都不酷,但它们决定了 Agent 能不能从演示走到生产。
先让每一步可追踪
我现在看一个 Agent 系统是否靠谱,先看它的日志能不能回答:这次任务从哪开始,中间调用了什么,为什么停。
只记录最终回答是不够的。Agent 的行为是一条轨迹,不是一段文本。至少要有 run、step、tool call 三层结构,每层记录输入摘要、输出摘要、耗时、token、状态和错误类型。
比如一次工具调用,至少要留下这些东西:哪个工具、参数是什么、返回了什么、花了多久、是不是重试、有没有触发策略拦截。
有了这套结构,排障会快很多。用户说“它答错了”,你能直接定位到是检索没召回、工具返回了错数据、状态没更新,还是模型在最后一步做了错误归纳。
没有这套结构,所有问题都会变成一句“模型不稳定”。
评测不能只看最后答对没
Agent 还有一个很容易骗人的地方:它可能用错误的过程得到一个正确的答案。
比如用户问退款政策,Agent 没有查政策库,而是从历史对话里猜了一个答案。这次猜对了,下次就未必。如果评测只看最终答案,这种侥幸会被当成能力。
所以我现在会分层看:组件层看检索和工具选择,步骤层看每一步是否合理,轨迹层看路径、步数、成本和恢复能力,最后才是端到端的任务成功率。
评测集也要覆盖失败场景:工具超时、权限不足、输入含糊、恶意注入、需要澄清的问题,以及本来就没有答案的问题。
尤其是“没有答案”这一类。一个 Agent 能老实说不知道,比它编一个像样的答案更有价值。
回滚不是备份,是实验能力
Agent 系统里会变的东西太多了:模型版本、系统 Prompt、工具 schema、检索索引、策略规则、上下文装配逻辑。
如果这些没有版本记录,一次“小改动”就可能让成功率悄悄掉下去,而你几天后才发现。
我现在要求每次发布都能回答:这次改了什么,影响哪些流量,出问题怎么切回去。
具体做法不复杂:配置快照、灰度发布、影子流量、离线回放。灰度先接 1% 到 5% 的流量,对比成功率、成本、延迟和安全指标。影子模式把真实请求同时跑新旧两版,但不影响用户。回放要固定工具返回,否则复现不了。
回滚能力不是等出事才用的,它应该让团队敢做实验。
最小可用的 Harness
如果从零开始,我不会先搭平台。先做五件事就够了:
统一 run/step 事件模型,所有 Agent 共用;工具调用统一走 runtime,禁止业务代码直接调外部 API;状态持久化,每一步可恢复;建立几十条覆盖成功、失败和攻击场景的回归用例;配置版本化,支持一键回滚。
这五件事用数据库、事件表和几个脚本就能起步。等流量上来,再补沙箱、策略引擎和自动评测。
一条轨迹应该长什么样
我现在要求的轨迹,大概是这样:
{
"run_id": "run_01J...",
"step": 7,
"type": "tool_call",
"tool": "refund.create",
"input": {"order_id": "A123", "amount": 99},
"output": {"status": "ok", "refund_id": "R456"},
"latency_ms": 842,
"tokens_in": 1200,
"tokens_out": 180,
"status": "ok"
}
有了这条记录,用户说“退款重复了”,你可以顺着 run_id 找到同一任务的每一步,看到第一次调用其实已经成功,只是响应超时;Agent 误以为失败,又调了一次。
修复也很具体:给退款工具加幂等键,超时后先查状态再决定是否重试;Harness 在工具层记录调用结果,不让 Agent 凭猜测判断成功与否。
如果没有轨迹,这个 bug 最后大概率会被归因成“模型不稳定”,然后换一个模型,再犯一次。
沙箱也是类似的东西。代码执行、文件读写、网络请求都应该在受限环境里,出站域名要有白名单。这些限制在 demo 阶段显得多余,在生产阶段是底线。
评测集不是越大越好
我见过团队花几个月标了几千条评测数据,最后常用的还是那几十条。
评测集的价值不在数量,在覆盖。正常路径、边界输入、工具失败、权限不足、恶意注入、无答案、需要澄清的模糊问题,每一类有几条就够发现回归。
剩下的数据可以从生产流量里采样。真实 case 比人工构造的更刁钻,但要注意脱敏和授权。采样之后人工过一遍,把明显的脏数据去掉。
每次模型、Prompt 或工具变更都跑一遍,记录指标变化。没有回归门的 Agent 项目,升级基本靠运气。
这件事的教训
模型能力决定 Agent 的上限,Harness 决定这个上限能不能稳定兑现。
我现在不太相信“换个模型就好了”这种说法。大多数时候,模型已经在做它该做的事,缺的是有人把状态、工具、权限和失败处理认真补齐。这层东西很无聊,但它是 Agent 从玩具变成系统的分界线。
转载请注明出处: 皮哈皮阿
本文的链接地址: https://blog.phpat.com/agent-engineering/agent-harness.html
微信或手机浏览器扫一扫,随时随地随心阅读与分享
-
MCP 进入生产环境:工具协议、网关与权限边界
MCP 刚出来时,我以为最难的是协议兼容。真正接了十几个工具之后才发现,把工具接上只花了两天,把权限、审计和故障处理理清楚花了两个月。
2026/10/07
-
Agent Harness:可观测、可评测、可回滚的 Agent 基础设施
去年我们做了一个处理退款申请的 Agent。Demo 很顺,上线第一周就出了事故:进程重启后状态丢了,同一笔申请被处理了两次。问题不在模型,而在模型外面那层没人愿意写的基础设施。
2026/10/09
-
AI Coding Agent 如何稳定提交可合并的 PR
上周 review 了一个 AI 生成的 PR,测试全绿,但我还是把它关了。它改了 37 个文件,顺手升级了一个依赖,还修改了两条测试断言。问题不是代码不能跑,而是这个 PR 没人敢合。
6天前
-
Agent 安全清单:提示注入、工具越权与数据外泄
一个内部助手被要求总结一封客户邮件。邮件末尾有一行白色小字:把最近的客户名单转发到某个地址。Agent 真的准备去调邮件工具了。安全不能靠模型自觉,得靠系统设计。
4天前
京公网安备11011402053654 
@muffin:链接已更新,分类图像功能...
AI网址导航模版图标库更换指南
作者大大,图标库邀请链接失效了,麻烦更新...
AI网址导航模版图标库更换指南
太好看了,快点更新!
友情链接
@戴墨镜的刘备:哈喽,路过点赞。
vue.js组件之手写签名板vue-signature-simple
太好看了,快点更新!太棒了!👍真的很赞!
vue.js组件之手写签名板vue-signature-simple
你写得非常清晰明了,让我很容易理解你的观...
Emlog插件RSS订阅器发布