Skip to content

第 5 章 · 控制机制:防止越界与过早胜利

本章目标:掌握防止智能体越界执行和过早宣布完成的控制机制,理解三层终止检查和验证-校验双闸。

5.1 过早胜利的陷阱

你让智能体实现一个"密码重置"功能。它修改了数据库 schema、写了 API 端点、添加了邮件模板、跑了单元测试(全绿),然后自信地告诉你"完成了"。但你实际运行时发现:邮件服务配置缺失导致链接发不出去;数据库迁移中途失败留下不一致的 schema;端到端流程一次都没跑过。

这不是孤立事件。2017 年 ICML 经典论文证明:现代神经网络系统性地过度自信——模型报告的置信度显著高于实际准确率。AI 编码智能体也不例外。它们"感觉"完成了,但实际离完成还很远。你的 harness 必须用外部化、基于执行的验证替代智能体的"感觉"。

5.2 滑坡效应

过早完成声明几乎总遵循相同剧本:代码看起来没问题——语法正确、逻辑似乎合理、静态分析无明显错误。但 harness 没有强制全面执行验证,智能体跳过实际运行或只跑部分测试。跑单元测试但不跑集成测试;跑测试但不检查覆盖率。最终,"代码看起来 fine"被当作"功能已完成"的证据。

信息在每个环节都有损耗。从任务规格到代码实现到运行时行为,每次转换都可能引入偏差,每次跳过的验证都放大信息不对称。

5.3 三层终止检查

智能体说:完成了

第一层:首次运行 lint / typecheck

第二层:然后运行测试和启动检查

第三层:最后运行完整用户流程

通过全部三层才算完成
代码写完 + 单元测试绿

但应用没真正启动 + 完整流程没跑

配置、DB、外部服务问题全部隐藏

所以智能体过早宣布胜利

5.4 单元测试绿 ≠ 任务完成

这是最常见的陷阱,也是最危险的。智能体写完代码、跑单元测试、看到全绿,就说"完成"。但单元测试的设计哲学——隔离被测单元、mock 依赖——恰恰让它们无法检测跨组件问题:

接口不匹配:渲染器向 preload 脚本传相对路径,preload 脚本期望绝对路径。各自的单元测试都用 mock 所以都通过。问题只在端到端测试时暴露。

状态传播错误:数据库迁移改变表 schema,但 ORM 缓存层仍持有旧 schema 的缓存条目。单元测试每次都在新 mock 环境运行,这种跨层状态不一致永远不会暴露。

环境依赖:代码在测试环境(一切都 mock)表现正确,但在真实环境因配置差异、网络延迟或服务不可用而失败。

"顺便重构"是对完成判断的毒药

Claude Code 有一个常见行为模式:在核心功能通过验证前就开始重构代码、优化性能、改善风格。Knuth 的名言"premature optimization is the root of all evil"在智能体场景中有了新的含义——重构移动了已验证和未验证代码的边界,可能破坏之前隐式正确的代码路径。

自我评估的系统性偏差

Anthropic 在 2026 年研究中发现了更深层的失败模式:当被要求评估自己的工作時,智能体系统性给出过度积极的评估——即使人类观察者会判断质量明显不达标。

这个问题在主观任务(如设计美学)上尤其严重。"布局是否精致"是判断性问题,智能体可靠地偏向正面。即使在有可验证结果的任务上,智能体的判断力差也会降低其表现。

解决方案不是让智能体"更客观"。同一个模型既生成又评估,天生倾向于对自己宽容。解决方案是分离"干活的人"和"检查的人"。

独立评估智能体,专门调优为"挑剔",比让生成智能体自我评估有效得多。Anthropic 的实验数据:

架构运行时间成本核心功能可用?
单智能体(裸跑)20 分钟$9否(游戏实体无响应)
三智能体(规划器+生成器+评估器)6 小时$200是(游戏完全可玩)

完全相同的模型(Opus 4.5)和完全相同的提示词("build a 2D retro game editor")。唯一的区别是 harness:从"裸跑"变为"规划器展开需求 → 生成器逐功能实现 → 评估器用 Playwright 实际点击测试"。

5.5 如何防止过早完成声明

1. 外部化终止判断

在 harness 中明确定义终止条件。智能体必须满足所有条件才能宣布完成。"完成"从主观判断变为客观判定。

markdown
## 终止条件
- [ ] 所有单元测试通过 (pytest tests/ -x)
- [ ] 类型检查通过 (mypy src/ --strict)
- [ ] Lint 干净 (ruff check src/)
- [ ] 端到端测试通过 (playwright test e2e/)
- [ ] 性能基准未降级 (benchmark.sh)

2. 验证-校验双闸

第一闸(验证):检查代码是否正确实现了指定行为。 第二闸(校验):检查系统级行为是否符合端到端要求。 两闸都通过才算完成。

3. 运行时反馈信号

程序执行的日志、进程状态、健康检查——这些形成 harness 判断完成质量的客观基础。

4. 完成优先级约束

先验证功能正确性,再处理性能,最后处理风格。核心功能未验证前不允许重构。

5.6 Feature List 作为范围控制

Feature List(功能清单)是控制智能体范围的有效工具:

json
{
  "project": "my-app",
  "features": [
    {
      "id": "auth-001",
      "priority": 1,
      "title": "用户登录",
      "status": "passing",
      "verification": ["POST /api/login returns 200", "JWT returned"]
    },
    {
      "id": "auth-002", 
      "priority": 2,
      "title": "用户注册",
      "status": "in_progress",
      "verification": ["POST /api/register creates user", "Email sent"]
    }
  ]
}

规则:

  • 一次只做一个 feature
  • 不标记 feature 完成除非验证通过
  • 不在当前 feature 范围外修改代码(除非 blocker 迫使窄支持修复)

5.7 本章小结

  • 智能体系统性过度自信,需外部验证替代"感觉"
  • 三层终止检查:lint/typecheck → 测试 → 端到端流程
  • 单元测试绿不等于任务完成,需验证-校验双闸
  • 分离"生成者"和"评估者"是应对自我评估偏差的关键
  • Feature List 控制范围,一次只做一个 feature
  • 完成优先级:功能正确性 > 性能 > 风格

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. 过早完成声明的核心原因是什么?

2. 验证-校验双闸中,"校验"层检查的是什么?

3. Anthropic 实验中,三智能体架构相比单智能体裸跑的主要优势是?

4. Feature List 的主要作用是?

🛠️ 动手实践

  1. 为一个简单功能写完整的终止条件清单,包含至少三层验证。
  2. 实现验证-校验双闸:第一闸跑单元测试,第二闸跑端到端测试。
  3. 创建一个 Feature List JSON,跟踪 3 个 feature 的状态和验证证据。

下一章:可观测性与会话清理