让 Agent 真正完成任务:证据、对抗验证、失败恢复与运行回执
本文是 Harness Engineering 总览 的验证与运维专题,依据 0xkichiro 分享的 Karpathy Agent 讲座视频和帖子引用的公开指南整理。视频没有公开逐字字幕,本文按引用文章的结构化内容进行中文归纳。
“完成”必须由环境证明
Agent 说“完成了”只是另一条模型输出,不是证据。完成状态应该由环境中的可观察变化决定:编译器、schema 校验、测试、查询、校验和、浏览器流程或人工审批都比模型自评更可靠。
建议采用由便宜到昂贵的检查顺序:
语法 / 类型
→ 定向测试
→ 集成测试
→ 浏览器或语义检查
→ 人工审批
模型适合处理歧义,代码适合处理管道。模型可以提出“应该完成了”,只有环境才能证明“确实完成了”。
验证器应该尝试推翻结果
Worker 的目标是产生最好的候选结果,Verifier 的目标是寻找拒绝它的理由。让同一个 Agent 在相同上下文里对自己说“再检查一遍”,常常只会重复原来的假设。
独立验证阶段应该拥有:
- 明确的拒绝标准;
- 对产物的直接访问;
- 对任务契约和验收条件的访问;
- 必要时使用独立工具或新上下文;
- 在发现问题时可以拒绝,而不是必须替 Worker 修复。
验证不是第二个观点,而是一次有意的反证尝试:它要主动寻找遗漏、越界、错误假设和不支持的完成声明。
Worker 产出候选
↓
Verifier 读取契约、产物和独立证据
↓
通过 → 接受
失败 → 返回定向证据和失败类别
模型提出,策略授权
有些规则不能依赖模型“记得”。它们应该成为位于推理循环外的策略:
| 风险 | 适合的控制 |
|---|---|
| 读取项目文件 | 路径沙箱和项目根限制 |
| 访问网络 | 域名白名单、超时和返回大小限制 |
| 修改代码 | 工作区范围、差异检查和测试门槛 |
| 写入数据库 | 事务、幂等键和回滚策略 |
| 发送消息 / 发布 | 明确审批和发送回执 |
| 删除或部署 | 强确认、审计和可回滚版本 |
自主性不是没有控制,而是在清晰、可执行的边界内自由操作。后果越严重,闸门就越硬。
恢复应该针对失败类别
“出错了,再试一次”不是恢复,而是重复。重试前,Harness 应先分类失败,并让下一次尝试改变一个相关条件:
| 失败类别 | 可能的下一步 |
|---|---|
| 工具超时 | 退避重试、缩小请求、换只读检查 |
| 参数非法 | 修复参数或更新工具契约 |
| 上下文缺失 | 检索特定文件或加载项目地图 |
| 测试失败 | 读取失败栈、定位模块、增加定向修复 |
| 权限不足 | 请求审批或选择安全路径 |
| 外部动作结果未知 | 查询状态和幂等键,先对账再决定是否重放 |
| 规则矛盾 | 暂停并升级给人,而不是强行选择 |
| 同一失败反复出现 | 停止循环,记录 Harness 改进项 |
每个循环都需要预算:最大尝试次数、最大耗时、最大费用、最大破坏范围和升级条件。可靠 Agent 不仅知道如何继续,也知道什么时候继续已经不合理。
指令要下沉成基础设施
当一个规则经常被提醒,说明它不应该继续停留在自然语言层。可以采用这样的下沉阶梯:
解释
→ 清单
→ 模板
→ 自动检查
→ 强制策略
例如,“不要修改生成文件”应变成路径保护;“迁移必须可回滚”应变成 CI 检查;“发布前需要批准”应变成外部动作闸门。Prompt 负责解释判断,Harness 负责执行不变量。
观察运行过程,而不只看最终文件
一个看起来正确的最终产物,可能掩盖了糟糕的过程:读取了错误数据、忽略了失败命令、重复执行外部动作、消耗十倍预算,或者只是碰巧得到正确结果。
可重建的 trace 至少应该记录:
- 状态转换;
- 上下文来源和版本;
- 工具输入与输出;
- 环境变化;
- 验证结果;
- 重试原因;
- 审批决定;
- 费用和延迟。
目标不是记录一切,而是在第 18 步失败时,能够从可信 checkpoint 恢复,而不是重新播放整段任务。
每次运行都要有变更回执
长 transcript 不适合人工复核。Harness 应在结束时编译一份小型 change receipt:
OBJECTIVE
任务目标
CHANGED
实际改变的文件、数据或外部资源
VERIFIED
已经通过的检查和证据
NOT VERIFIED
仍然没有验证的依赖、环境或权限
DECISIONS
关键选择及其原因
RISKS
已知风险和可能影响
APPROVAL NEEDED
仍需人工确认的动作
它不是模型说了什么的摘要,而是系统能够证明什么的摘要。对人类来说,这是审阅界面;对下一次 Agent 会话来说,这是可信起点。
失败要升级 Harness
修复失败输出只帮助当前运行;修复允许失败发生的系统,才能帮助之后的运行。每次失败后可以问:
- 任务契约是否含糊?
- 关键上下文是否不可见?
- 暴露了错误工具?
- 是否缺少前置条件?
- 结果是否无法验证?
- 策略是否被错误地放在 prompt 里?
- 恢复范围是否太大?
- trace 是否不足以定位问题?
然后把答案转成地图、规则、测试、工具契约、校验器或新的 checkpoint。这样失败会留下基础设施,系统才会逐渐变可靠。
Harness 也会衰减
更多 Harness 不总是更好。模型、工具和任务都会变化,针对旧模型添加的路由、评估器、记忆层和重试规则,可能变成今天的额外延迟和复杂度。
对每个 Harness 组件定期追问:
- 它防止哪一种失败?
- 这种失败现在还发生多频繁?
- 它增加了多少延迟和维护成本?
- 能否用更简单的机制达到同样效果?
- 删除它会发生什么?
最佳 Harness 不是最大的系统,而是能可靠缩小“意图”和“证据”之间差距的最小系统。要允许删除已经没有收益的防护。
从最小可行 Harness 开始
可以按六层逐步建设:
| 层级 | 最小能力 |
|---|---|
| 1 | 目标、范围、约束、验收检查 |
| 2 | 项目地图、命令、局部规则、已知依赖 |
| 3 | 类型化工具、参数校验、路径权限、结构化结果 |
| 4 | 运行状态、checkpoint、决定、失败教训 |
| 5 | 确定性检查、对抗验证、变更回执 |
| 6 | 失败分类、有界重试、升级和 Harness 更新 |
不要因为一个 prompt 偶尔需要澄清,就直接搭建多 Agent 编排平台。复杂度应该由观察到的失败赢得,而不是由想象中的未来需求预支。
衡量“被接受的工作”
Token 数、调用次数和尝试任务数都不是最终指标。更有用的单位是 accepted work:通过验收并被人或系统接受的工作量。
可以跟踪:
- 首次通过率;
- 工具失败后的恢复率;
- 同类失败重复率;
- 每个任务的人为介入次数;
- 无证据完成声明数;
- 从请求到验证结果的时间;
- 每个 Harness 组件的开销。
目标不是让 Agent 产生更多活动,而是让每单位人工注意力获得更多可信结果。
来源与边界
- 原始视频
- 0xkichiro 原帖
- LunarResearcher 的引用长文
- 本文保留了公开指南的核心概念,但重新组织了例子和表格;示例不是原作者的生产代码,也不构成某个 Agent SDK 的保证。