第 09 章 · 验证闭环
本章目标:让 Agent 的“完成”由外部证据驱动,而不是由模型语言风格或自信程度驱动。
1. 生成和验证是不同工作
模型擅长提出修改,但同一个上下文里的模型也容易合理化自己的方案。它可能看到代码看起来正确,就说“问题已修复”,却没有运行测试。Agent 框架应把完成条件变成显式步骤:检查 diff、运行相关测试、运行静态检查,并把结果重新送给模型。
验证闭环是:
目标 → 修改 → 外部检查 → 观察结果 → 修正或完成。
这与主循环重合,但强调最后一跳必须有证据。没有证据,只能叫“提出了一个候选答案”。
2. 验证信号的层级
| 层级 | 例子 | 能证明什么 |
|---|---|---|
| 语法与格式 | py_compile、formatter check | 文件可解析、格式满足规则 |
| 静态分析 | 类型检查、lint、安全扫描 | 一部分结构错误与规则违规 |
| 单元测试 | 相关函数测试 | 局部行为符合断言 |
| 集成与端到端 | API、浏览器、数据库流程 | 多模块真实协作 |
| 人类验收 | 产品判断、视觉质量、风险接受 | 无法完全形式化的价值 |
检查越靠下,通常越接近用户行为,也越慢、越脆弱。Agent 应先运行便宜且相关的检查,再根据风险扩大范围。
3. 如何选择相关测试
最简单的方法是使用项目规则提供的标准命令。更精细的系统根据修改文件、依赖图和历史覆盖关系选择测试。无论如何,模型必须说明为什么这些检查足够。
只运行原来失败的测试可能造成回归;每次运行完整测试又可能成本过高。可以先跑失败测试与邻近单元测试,成功后再运行模块级或全量检查。验证计划本身也是一个需要预算的决策。
4. 防止“测试迎合实现”
Agent 可能通过修改测试让错误消失。测试当然也可能有问题,但删除断言、降低阈值或跳过测试应视为高风险行为,需要额外说明和审查。Runtime 可以检测测试文件变化,并触发 Reviewer。
另一个风险是只看退出码,不看测试数量。命令因为路径错误没有收集到测试,却返回可疑结果。验证器应记录 collected、passed、failed、skipped 等摘要。
5. 非代码结果怎样验证
网页需要真实打开、点击和截图,不能只检查 HTML 字符串;文档需要渲染后检查分页;数据任务需要行数、约束和样本核对;外部操作需要读取目标系统确认状态。原则不变:找到一个独立于生成文本的观察通道。
对于主观质量,可以让独立 Reviewer 根据明确 rubric 评审,但这仍不等于事实验证。最好把可机械检查的部分先机械化,把人类留给真正需要判断的部分。
6. 完成协议
最终回答应包含修改摘要、验证命令与结果、未运行的检查和剩余风险。Runtime 还可以要求 final response 满足结构化 schema,避免模型漏报失败。
{
"status": "completed",
"changes": ["Fix quantity calculation"],
"checks": [{"command": "pytest -q", "result": "12 passed"}],
"residual_risks": []
}
核心判断
“我检查过代码”是过程描述;“pytest 收集 12 项并全部通过”是证据。设计 Agent 时,持续把前一种表述改造成后一种数据。