Agent 说“完成了”,系统为什么不能直接相信?
1. 最终消息不是工作事实
做 Agent 工程时,很容易写出这样的逻辑:
if (agent.finalMessage.includes('completed')) {
task.status = 'done'
}
真正运行一段时间后就会发现,最终消息最多只能代表 Agent 声称完成。它不能证明测试通过、产物存在、数据已经落库,也不能说明是否产生了用户没有要求的副作用。
完整研究版见:完成是一项声明,而不是已接受状态。这里重点讨论怎样把这个判断放进编码运行时。
2. 第一道门:确定性回读
能够确定性验证的内容,应该优先交给程序:
- Git diff 是否符合修改范围;
- 必需测试是否全部通过;
- 构建产物是否存在;
- 文件哈希和提交 SHA 是否一致;
- 远端分支或业务系统是否真的进入目标状态。
这些检查解决的是“环境里实际发生了什么”,而不是“Agent 认为自己做了什么”。
3. 第二道门:解释执行轨迹
确定性检查通过以后,再让验证器处理语义问题:执行过程是否合理,失败由 Agent 还是环境造成,最终结果是否满足用户意图,有没有额外副作用。
Microsoft Research 的 Universal Verifier 采用了类似分解:过程与结果分离,可控与不可控失败分离,并针对每条准则寻找相关截图证据。它提供的不是一个永远正确的完成 Oracle,而是一种按声明寻找证据的验证方式。
4. 第三道门:谁拥有接受权
验证结果仍不等于最终接受。高风险任务的接受者可以是 QA、管理员、策略引擎或明确授权的人,但不应该仍然是刚刚执行任务的那个 Agent。
因此更合理的状态转换是:
running
→ completion_claimed
→ verifying
→ accepted | rejected | escalated | undetermined
5. 失败、阻塞和未确定必须分开
Agent 按正确步骤执行,却被验证码或缺少凭据拦住,这不是成功,也不能简单归类为工作者失败。验证结果可能是:
{
"claim": "completed",
"process": "passed",
"outcome": "not_reached",
"failure_class": "external_blocker",
"acceptance": "undetermined"
}
保留这种冲突,后续才能决定重试、请求权限、修复环境还是人工接管。否则恢复 Worker 只能面对一个模糊的 failed,不知道从哪里继续。
6. 把完成证据写进契约
一个可执行的完成契约至少需要说明:
- Agent 可以提交哪些完成声明;
- 每类声明需要哪些回读和测试证据;
- 验证器版本和判断依据怎样记录;
- 谁拥有接受、拒绝和覆盖判断的权限;
blocked、escalated、undetermined怎样进入后续恢复流程。
这比在最终提示词里加一句“请确认已经完成”更可靠,因为契约约束的是状态转换,而不是说话方式。
7. 研究结论的边界
Universal Verifier 的论文结果很有价值,但外部 Browserbase 数据上的误报率仍为 8%。它不能直接证明任何生产系统已经具备通用验收能力。真正值得采用的是:执行者可以提交完成声明,但不能单独决定系统已经接受完成。
Other language: English version
如果你正在使用 Cursor、Codex 或其他编码 Agent,你现在会用哪些证据,来决定它是真的完成了,而不是只说完成了?