开发者用分离的AI Agent构建验证系统,通过强制质量门禁和可查证据链工作,人类只做最终风险判断。
TL;DR:AI 生成代码,由独立的 AI 智能体通过强制质量门和可查验的证据进行验证。人类并不盲目信任任何一个智能体,而是判断剩余风险是否可接受,并对结果负责。
六个月前,一个 AI 智能体实现了一个修改,该修改通过了 lint 和所有测试,但实现仍然是错误的。我在代码审查过程中发现了它。
随着 AI 提升了我的开发效率,审查成为了瓶颈。但把这项工作交给另一个 AI 会引发一个更难的问题:
另一个 AI 智能体能否在不继承编写代码的 AI 智能体的假设的前提下,发现同样类型的失败?
寻找答案的过程演变成了一套验证系统,在实际工作的间隙逐步构建起来。
如今,AI 编写和审查了我大部分的代码。我仍然审批每一个 pull request,并对结果负责。但我审查的内容已经改变了。
我审查系统产生的证据、仍然存在的不确定性,以及出错的后果。

在我的博客页面上有一个更大版本的验证流程图,大到可以逐门阅读。
该图有三条泳道和两个人类边界。
在最上层,人类拥有需求、验收标准、架构规则和智能体规则。在最下层,人类拥有残余风险和发布决定。
在这两个边界之间:
编排器拥有工作流程。它跟踪状态并启动下一个工作阶段。
子智能体拥有具体工作。需求、架构、实现和验证在独立的、窄化的上下文中完成。
制品拥有状态。规格说明、验收标准、计划、diff 和验证报告存在于任何智能体对话之外。
Human definition
-> requirements and architecture
-> task-level developer-validator loops
-> whole-feature validation
-> repository CI and separate PR review
-> risk-based human approval
每个失败的门控都会将工作返回给实现和验证阶段。没有任何东西仅仅因为一个智能体说它准备好了就往前推进。
我在《当 AI 智能体编写我的代码时,我如何验证质量》一文中描述了更广泛的质量流水线。这里我想专注于一个更难的问题:什么能防止 AI 验证成为一个昂贵的橡皮图章?
任务是:在管道运行期间锁定导航。在实现开始之前,它有三个验收标准:
实现之后,每个可见的机械信号都是绿色的:
=== VALIDATION: D8 "Lock navigation during pipeline execution" ===
LINT=PASS
TESTS=6104 passed, 0 failed
COVERAGE=94.6%
RESULT=FAIL: AC-1, 2 and 3 not completed.
验证器将实现映射回原始标准:
代码中包含了一个 PipelineRouteGuard,但它依赖于生产应用程序从未提供的路由上下文。它的单元测试伪造了该上下文,因此它在真实应用程序中不存在的条件下验证了一个孤立的回调。
然后验证器智能体运行了一个证伪测试:临时移除该 guard 并重新运行套件。所有 6,104 个测试仍然通过。
这将一个看似合理的担忧变成了一个经核实的、高级别的发现,并阻止了任务继续。该套件执行了代码,但它从未证明所请求的行为存在于生产集成中。
这个案例包含了该工厂的核心设计原则:
被门控的行为必须独立于实现来定义。
AI 生成的测试可以编码与 AI 生成的代码相同的错误假设。如果测试意图是从代码中派生出来的,实现和测试可能完全一致,而用户面向的行为却是错误的。
在这个智能体编程工作流中,我与一个需求智能体合作,直到预期的结果清晰且验收标准可测试。然后架构师在人类拥有的架构规则内进行设计,并将工作分成有边界的任务。
这就创建了一条可追溯链:
business goal
-> acceptance criterion
-> implementation plan
-> task
-> code change
-> validation result
验证器可以反向追溯这条链:为什么存在这个变更,它应该提供哪种一致的行为,什么证据表明它确实提供了该行为?
通过的测试仍然是有用的证据。但它们不是正确性的定义。
开发者的测试确认代码按预期运行。独立验证确定该预期是否与任务匹配。
AI 代码审查中的一个常见失败模式是要求一个智能体在生成实现的长运行上下文中"审查你的工作"。该模型已经为其解决方案为何正确编织了一个连贯的故事。详细的审查提示并不能消除这些继承的假设。
启动一个新的智能体是必要的,但还不够充分。如果新上下文接收了开发者的推理、总结和对为何实现应通过的说服性解释,它就继承了开发者的框架。
我的验证器从原始源制品开始:
任务和需求
验收标准
相关架构规则
实现计划
变更的代码和 diff
它自己的角色文件和发现评分标准
它不接收开发者的任何对话或关于实现为何应通过的主张。
验证器自行重新运行相关的构建和测试,验证所需的制品是否存在,然后评估机械检查无法决定的内容:验收标准是否满足、实现是否遵循架构、是否引入了不必要的变更或重复,以及是否有一个未归档的决策本应被上报。

这是上下文隔离,而非统计独立性。来自同一模型家族的智能体仍然可能共享盲点。新上下文减少了锚定效应和确认偏误;但它不能消除相关性错误。
这种分离之所以有效,是因为三个角色有不同的职责:
编排器转移控制权。它跟踪任务是在等待实现还是验证,并在结果明确时遵循标准转换。
专业子智能体执行狭窄的工作。开发者实现一个任务;验证器尝试证伪该任务已准备就绪。
制品携带交接。需求、代码、工具输出和发现保持在对话之外,保持持久性和可审查性。
专家之间没有对话式交接。他们通过共享制品进行通信。
在 PASS 时,编排器提交并转向下一个任务。在 FAIL 时,它启动一个新的开发者-验证器循环;工作流异常的处理不承担底层技术决策的所有权。
技术发现保留在报告中,供下一个开发者使用,也供后续审计。编排器不需要裁定哪个技术论点听起来更有说服力。
这是审查机器人和门控之间的区别。审查机器人撰写可能被忽略的评论。验证器控制工作流是否可以继续。
当一个真实问题伴随着二十个看似合理的怀疑出现时,AI 代码审查就变得毫无用处。如果人类必须调查每一个直觉,自动化只是移动了瓶颈,而非消除它。
因此,每个发现都要回答两个独立的问题:
如果该问题存在,它会有多严重?
验证器做了什么来证明它确实存在?
严重性使用特定于项目的锚点:
证据记录验证器实际建立的内容:
工作流决策来自项目拥有的矩阵:
严重但未经验证的问题会触发针对性验证:验证器必须命名并运行能够确认或否定它的具体检查。投机性的低价值发现会被丢弃。
这些阈值并非通用标准。我花了好几个月才调整好,因为未经校准的审查器要么漏掉缺陷,要么用大量看似合理但无意义的噪音淹没工作流。我根据真实和历史缺陷来调校这些阈值:验证器能否发现已知问题而不产生过多报告?人类定义什么对项目是危险的;智能体则应用这个决策。
智能体说它运行了检查,这仍然只是一个声明。
声明: "我运行了测试,它们通过了。"
证据: 一份记录在案的报告,包含命令名称、结果、测试数量和失败信息。

在一种实现中,一个包装器运行测试命令并将结构化结果写入工作区。一个停止钩子验证报告存在、是最新的且可以解析。工作流使用记录的 result 来决定任务是否继续。
有用的模式是结合模型判断与确定性执行:
产物存在并不自动等于其为真。当问题是是否存在 bug 时,模型写的摘要不如捕获的工具输出强;捕获的输出不如复现的失败强。
产物使声明持久且可检查。它的来源决定了它应得到多少权重。
功能不仅仅是其任务的总和。局部门禁可以通过,而行为在任务边界之间可能已经损坏。
在任务级验证之后,工厂运行林挺、类型检查、相关测试套件和生产构建。然后它对整个功能运行多智能体审查,每个智能体从一个狭窄的角度:
智能体的数量不是重点。每个审查者需要一个狭窄的问题、相关的源产物和清晰的报告阈值。

每个标记的问题都有单独的验证上下文。验证器必须确认问题存在于变更的代码中,然后才能进入最终报告。无法重新确认的发现就在那里终止。
我没有系统地测量过结果,所以这些是工作估计而非基准数据。在我自己的使用中,任务级验证大约在半数的任务中发现值得纠正的问题。最终验证大约让四分之一已完成的功能被打回重做,通常是架构、代码复用或业务逻辑问题,而非基本测试失败。
Token 统计是测量过的。一个功能经历上述每个门禁:
每个智能体的 Token 使用量
+-----------------------+--------+----------+-------------+--------------+
| Agent | Calls | Output | Cache write | Cache read |
+-----------------------+--------+----------+-------------+--------------+
| TASK LOOP architect, then one developer/validator round per task |
| architect | 130 | 98,912 | 1,350,067 | 16,672,330 |
| developer (Phase 1) | 427 | 87,864 | 2,405,777 | 85,269,594 |
| validator | 63 | 5,674 | 172,524 | 2,950,926 |
| developer (Phase 2) | 236 | 49,554 | 1,091,574 | 42,760,414 |
| validator | 65 | 10,457 | 236,936 | 3,416,637 |
| developer (stalled) | 48 | 8,454 | 463,209 | 3,174,643 |
| developer (Phase 3) | 249 | 65,749 | 1,169,642 | 46,599,603 |
| validator | 47 | 5,394 | 133,439 | 1,779,760 |
+-----------------------+--------+----------+-------------+--------------+
| Implementation total | 1,265 | 332,058 | 7,023,168 | 202,623,907 |
+-----------------------+--------+----------+-------------+--------------+
| FINAL VALIDATION parallel reviewers over the whole feature diff |
| docs (rules) | 19 | 11,066 | 315,590 | 918,551 |
| summary | 34 | 11,403 | 226,320 | 2,069,973 |
| backend architecture | 32 | 8,324 | 330,709 | 2,496,241 |
| frontend architecture | 15 | 5,874 | 189,851 | 855,451 |
| bugs | 90 | 39,499 | 561,488 | 7,845,994 |
| security | 43 | 23,060 | 434,620 | 2,923,798 |
| bugs (2nd, stopped) | 30 | 8,545 | 183,677 | 1,990,978 |
+-----------------------+--------+----------+-------------+--------------+
| Review total | 263 | 107,771 | 2,242,255 | 19,100,986 |
+-----------------------+--------+----------+-------------+--------------+
| Orchestrator | ~330 | ~205,000 | ~570,000 | ~62,000,000 |
+-----------------------+--------+----------+-------------+--------------+
| Total | ~1,858 | ~645,000 | ~9,835,000 | ~283,725,000 |
+-----------------------+--------+----------+-------------+--------------+
任务级验证是便宜的部分。Phase 1 的 developer 花费了 427 次调用和 87,864 个输出 token。检查它的 validator 花费了 63 次调用和 5,674 个输出 token,读了大约 3% 的缓存上下文。另外两轮有相同的形态。
最终验证才是验证成本真正所在。六个审查者对整个差异进行检查,加上一个被停止的审查者,它们之间产生了 107,771 个输出 token,超过了任何单个 developer 智能体。这就是对同一个差异提出多个狭窄问题而非一个宽泛问题的代价。
检查工作的成本是做事成本的一小部分。
工厂并非对每个变更都有同样深度。审查范围和门禁深度应随失败的不确定性和后果规模进行缩放;设计原则保持不变,即使低风险任务使用更少的阶段。
阻塞性发现将工作返回到实现和验证阶段。通过则允许编排器打开一个草稿 pull request。
仓库 CI 仍然运行所有在这套系统存在之前就已运行的确定性检查:构建、完整测试套件、林挺和静态分析。智能体没有取代其中任何一个。这个系统中没有任何东西可以替代那些已经承压的工程实践,红色流水线完全像以前一样阻塞 pull request。
一个独立的 AI 审查者 GitHub Copilot 然后检查最终的合并差异。它运行在与写代码的智能体不同的模型家族上,因此它不会携带关于正确代码长什么样的相同假设。这缩小了共同的盲点。
因此 PASS 只意味着:每个定义的质检门禁都完成了,没有阻塞性发现。其置信度由验收标准质量、检查的覆盖率以及模型共同的盲点所限制。
是我构建了这个系统,还是 AI 构建了批准 AI 的控制措施?
如果编码智能体可以重写评判其工作的评分标准、架构规则或角色文件,循环就在错误的方向上闭合了。智能体可以逐渐围绕自己的输出重新定义成功。
在我的项目中,智能体规则、架构规则和其他决策边界是归人类所有并锁定的。智能体可以读取它们并提出修改建议,但不能推送修改。
锁定不等于冻结:重复的发现可以产生新的规则提案,但只有人类可以批准它们进入测试工具。
在这些记录在案的边界内,智能体可以自主行动。如果实现需要一个新的架构选择、产品规则或风险决策,而文档没有解决,智能体必须停下来升级而不是即兴发挥。
AI 在记录在案的决策边界内行动。文档未解决的产品、风险和架构决策升级给人类。
这些锁定控制的技术实施在 5 个月内完成。100% Claude Code。零架构漂移。这里的责任点更简单:智能体不能拥有决定其自身工作是否可接受的控制系统。
在所有这些质检门禁之后,pull request 仍然到达人类。
AI 一天之内生成和审查的代码比我现实上能逐行重读的要多得多。如果责任意味着假装不是这样,人类参与式审查要么成为永久瓶颈,要么成为表面仪式。
相反,我检查范围、证据和后果:
哪些文件、服务和系统边界发生了变化?
哪些业务行为受到影响?
变更的哪些部分是关键的,哪些是例行的?
质量门禁生成了哪些证据?
哪些假设或决策被上报了?
失败的可见性、可逆性和成本如何?
高风险变更会接受深入的人工审查。认证、权限、支付、迁移和安全控制不会与可见、易于回滚的 UI 代码获得同等程度的审查深度。
低风险变更仍然会被审查,但人工审查的深度与失败的成本、可发现性和可逆性成正比。
AI 审查海量变更。人类审查风险。
更准确地说,人类审查的是证据、仍然存在的不确定性以及出错的后果。
当我点击 Approve 时,我知道:
变更本应做什么
哪些证据让它通过了
哪些决策被上报了
验证系统在哪些地方仍然不确定
失败会付出什么代价
我的审批并不意味着系统证明了变更的正确。它意味着定义的质量门禁未发现阻塞性证据,而我接受剩余未被证明的部分。
如果我发布了变更,我仍然对结果负责。
审查曾成为瓶颈。现在它是一个决策,而不是队列。
在与 AI 合作了大约两年后,我更信任模型周围的验证系统,而不是任何单个模型的判断。
信任来自于模型周围的验证系统。
工具:Claude Code(编排层用 Opus,开发者用 Sonnet,任务验证用 Haiku)、Beads 和 Linear 做 issue 追踪、GitHub Actions 做 CI、GitHub Copilot 做单独的 PR 审查。