loading

Loading

探索与发现

首页 Agent 工程

Agent Harness:可观测、可评测、可回滚的 Agent 基础设施

分类:Agent 工程
字数: (2783)
阅读: (4)
0
摘要:去年我们做了一个处理退款申请的 Agent。Demo 很顺,上线第一周就出了事故:进程重启后状态丢了,同一笔申请被处理了两次。问题不在模型,而在模型外面那层没人愿意写的基础设施。

去年我们做了一个内部 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

手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

1 / 1
预览图