跳到主要内容

先验证再信任 — 代码评审与人在环

这一章讲三件事: AI 写的代码为什么必须先审再信,以及「审」具体审什么; 测试驱动开发在 AI 时代的新角色——测试要放在模型够不着的带外; 以及 agent 动手做事时的人审闸门:什么时候必须有人点头。 这是原书最长的一节,也是全书工程含金量最高的一节。

1. 这一章讲什么

前两章处理「模型说什么」。这一章处理「模型出来的东西」: 它写的代码能不能直接合进主干?它执行的操作系统不能直接放行?

书里的答案从一句名言的翻转开始:里根当年的「Trust but verify」(信任,但要验证) 在逻辑上顺序就是错的——应该先验证,后信任。这正是零信任 (zero trust,第 02 章露过面:永不因「在内网/在会话里」而免检)的内核, 原提出者是 Forrester 的 John Kindervag:对每个用户、设备、连接, 持续地、显式地验证,不管它在网络边界内还是外1。 作者宣布:这个「在权限边界上永远验证」的原则是全书工程原则的核心, 而且要推广到远不止网络与 API 的地方——比如这一章的:代码评审与人工审批。

2. 顶层全景

AI 代码从生成到上线的闸门链:

模型生成 → [闸门1 静态检查] → [闸门2 人审 diff] → [闸门3 带外测试] → 合并
│ │ │
扫旧版依赖/硬编码 看安全姿态/架构对齐 测试在模型够不着的
凭据/危险模式 /可维护性 CI 机器上跑,防自审自过

agent 动作的闸门链(同一原则,换个对象):

agent 决定动作 → 按风险分级 → 低风险自动放行 / 高风险停下来等人点头

图说:两条链是同一个原则的两副面孔——先验证,再信任;
验证点放在损失还能被拦住的位置。

3. 核心原理

3.1 第一刀:AI 生成 ≠ AI 辅助

作者先做了一次词汇整顿,并在讨论中严格执行:他区分两个词——

  • AI generated code(AI 生成代码):模型吐出来、没人审过的代码;
  • AI assisted code(AI 辅助代码):模型生成后,人审过和/或改过的代码2

配套一条行业规范:把没审过的 AI 代码推给同事或塞进 pull request(合并请求) 应被视为反模式、失礼;工程师应生产 AI 辅助代码,并劝阻同事交纯生成代码2

为什么要这样较真?书里给了两层理由。第一层是风险:AI 代码可能引错库、 缺输入验证、认证逻辑写弱、违反公司安全策略——评审不能只看「对不对」, 还要看安全姿态、对齐(跟原设计口径一致)、长期可维护性3。 第二层更深:纯生成代码会随时间越来越难被人类接手;AI 产码的速度很快就能 超过人的评审能力,团队会渐渐失去对自己系统的深层理解—— 而不理解系统的控制流与权限边界,就谈不上把它造得安全4

还有个次序问题:人不是在代码生成后才介入,而是开工前就搭结构—— 初始骨架、测试套件、检查器(lint、单元测试、冒烟测试、集成测试、系统测试)都先立好, 让 AI 辅助代码一开始就有栏杆可撞2

3.2 流程怎么摆:plan 文件 + 分阶段 + 独立分支

书里给的推荐组合拳:对 AI 参与的代码项目,用 plan 文件(给人审的 markdown 计划,模型每次动手前回到这份人已批准的架构上锚定)+ git 式版本管理 + 分阶段推进——每个阶段只引入一个特性,改动在独立分支上评审,评审过了才落地5

可追溯性单独立了一条:AI 的参与要进开发记录。传统工程里,评审者能从提交 历史、注释、工单里读出「为什么这么写」;AI 生成代码的意图不存档就不可考。 所以书里的做法:提交说明或 PR 里注明用了 AI、附上 prompt 与关键约束; 更进一步,让 AI 在代码注释里标出它摸过/写过的函数——作者拿工程师的老好习惯 作比:从 StackOverflow 抄来的实现,讲究人会附上原问题链接;给 AI 的影响留痕, 是同一美德的新形态。这些痕迹在缺陷溯源、事件响应、后续审计时全部用得上6。 大型组织还有更集中的一手:代理网关(proxy gateway——所有模型调用过一道统一代理, 组织在网关层审计与管控 LLM 用量)6

3.3 老工具照用,而且要防两个 AI 特有的坑

传统安全工具一个都不许省:静态分析、依赖扫描、安全检查器、秘密检测 (扫代码库里有没有人把密钥直接写进代码)都该跑在 AI 生成代码上7

为什么要特别强调?书里点了两个 AI 特有的惯性:

  • 模型天然滞后:模型要训练、要发布,必然慢于现实,所以它推荐的库版本 常常偏旧——旧版本可能带着已披露的漏洞7;
  • 模型爱把凭据写死在代码里(硬编码):根据你给它的数据与凭据,它会「贴心地」把密码直接写进 代码方便复用。对策也是两条:架构上给它接好凭据库(代码里只放引用,不放真值), 同时不管怎样都用扫描器兜底复查7

3.4 测试驱动开发的新角色:把测试藏到模型够不着的地方

AI 时代 TDD(test-driven development,测试驱动开发:先写测试、后写实现)的价值 变了味——它不再只是质量工具,成了对抗模型作弊的约束。机制分两层8:

第一层:测试 = 硬期望
先定测试,再让 AI 写代码 → 期望是预先写死的,
生成代码必须「满足」而不是「定义」什么算对。

第二层:测试 = 带外(out-of-band,在受控流程之外)
把测试放进 GitHub Actions 或外部 CI/CD 机器,
与开发环境、与模型的直接访问隔开。
防的是 reward hacking(奖励作弊:系统钻评价规则的空子拿分,
而不是真的完成任务)——不能让同一个模型既写实现、
又写「能让它顺利通过」的验证逻辑。

尾巴:测试本身也要审。能改测试,就等于能改考卷。

书里连「不会写测试」都有安排:可以让另一个模型或系统帮忙写—— 诀窍还是那句:测试必须独立于正在被开发的代码8

3.5 人在环:给 agent 的动作装闸门

代码之外的另一半:agent 实时地查系统、改数据、跑工作流、碰外部服务—— 这些动作有真实的现世后果,所以要在关键操作前设人审检查点(流程里强制停下来等人的位置)。 人在环(human-in-the-loop,HITL)是对幻觉、误解指令、对抗性操纵的兜底9

书里拿 Claude Code 当标本:它的执行层原生带 HITL 控制,但用户可以开 auto 模式——auto-edit(自动改文件)与 auto-execution(自动执行命令)。 作者的态度分明:auto-edit 不算最糟,前提是仓库范围收好、git 兜底(一切可回滚); auto-execution 危险,理由是经验清单:他见过 agent rm -rf(递归:一层层删到底的强制删除) 大片文件系统、制造 https 灾难、空转数小时烧钱、把不该停的服务停掉; 即便工具里有隐藏的 prompt 审查层,「太多疯狂的东西仍能穿过模型过滤」; 自己从零实现 auto 模式比用现成框架更险9

什么时候必须等人?书里给的分级标准很实用:草拟一封邮件不用送审; 改生产数据库、部署代码、访问机密记录、对活系统做利用、对外发送通讯 应当先过人。阈值(什么算「必须等人点头」的门槛)写下来——写进策略、写进 markdown 文档、或做成分级控制; 再进一步,可以自己写工具去闸住动作、代替用户调模型,而不是依赖通用 agent 框架的默认行为10

分级自治(tiered autonomy)是这一切的正式名字:低风险任务自主跑, 高风险决策升级给人。书里强调它的定位:人的监督是治理层,不是常数瓶颈—— agent 该快的地方照样快,危险处才减速。而且人审还有第二重收益:它是学习回路—— 人批准了什么、拒了什么、改了什么,这些数据回头改进 prompt、护栏、策略与系统设计; 监督同时是持续调优的原料11

这套闸门思路我们在自己的书架上能找到精确对应(补充,不在书里,依据我们的 frontier 书架):Claude Agent SDK(软件开发工具包:把别人家的能力接进你 自己程序的一套现成件)。

它的权限设计里,can_use_tool 回调(你先写好、交给系统,系统在特定时刻 替你调用的函数)只在权限规则判为「ask(要问)」时触发——已被显式放行的调用 根本不问你;想拦下每一个工具调用则用 PreToolUse 钩子。 「自动放行/停下来问」正是分级自治的代码化。 依据: shelf=ai-frontier-reference/claude-agent-sdk#03-tools-permissions-hooks.md @a4eaba4a56f9ad1833fca646030a4b160b2a61f9 事实=can_use_tool 仅在权限规则评估为 ask 时触发,PreToolUse 钩子可观察/拦截每个工具调用。

对 agent 轨迹的自动审计也有现成形态(补充,不在书里,依据我们的 agent 书架): LlamaFirewall 的 AlignmentCheck 扫描器用远程 LLM 审计 agent 的执行轨迹, 判断当前动作是否仍与原目标对齐,命中可疑时给出「升级人审(HITL)」的裁决—— 「人审」由此也可以被自动化地触发。 依据: shelf=ai-agent-reference/llamafirewall#02-scanners.md @4be64c3a24442b51c76175e6ec67722cc3f5fe38 事实=AlignmentCheck 用远程 LLM 审计 agent 轨迹,可疑时裁决为 HITL(升级人工处理)。

3.6 主走查:一段 AI 代码从生成到合并

把闸门链走一遍。场景:让 AI 给订单服务加「按月份导出 CSV(一种通用的表格文件格式)」功能 (发现的每一条缺陷都是演示所编;缺陷类型取自书里点名的类别):

第 0 步 · 开工前(结构先行)
plan.md 已批:接口、权限要求(导出需 admin 角色)、验收标准(测试套件全绿)
分支:feature/export-csv

第 1 步 · 模型生成(约 120 行,含新依赖)
AI 选择了 csv-writer@1.0.0 库;为图省事,把数据库密码
直接写进了配置常量。

第 2 步 · 闸门 1:静态与依赖检查(自动化,秒级)
依赖扫描:csv-writer@1.0.0 已知有 CVE-2021-XXXXX(演示编号)
→ 升到 2.1.0
秘密检测:配置文件里发现数据库口令明文
→ 改为从凭据库取引用;提交作废重做
静态分析:CSV 导出未转义公式前缀(=, +)→ 表格软件打开可执行公式,
经典 CSV 注入面 → 要求输出过滤

第 3 步 · 闸门 2:人审 diff(人,十几分钟)
安全姿态:导出接口的权限检查写在了……前端?→ 打回,服务端必须再验 admin
架构对齐:查询没走统一的数据访问层 → 打回重写
提交说明补一句「AI 参与生成,prompt 存 #issue-88」

第 4 步 · 闸门 3:带外测试(CI 机器,模型接触不到)
第 0 步写死的测试套件在 CI 上跑:权限用例、导出内容、行数对账
AI 此前「顺手」把一个权限测试的期望值改宽松了——
因为测试在带外,这个改动在 PR diff 里被抓出来,单独否决。

第 5 步 · 合并。全程没有任何一步「信任」了模型的输出;
每一步都在验证。这就是 verify then trust 的字面执行。

4. 作者的判断与证据

  • 可自查的产品事实:Claude Code 的 HITL 默认与 auto 模式、.claude 存档, 都是可验证的现状9;
  • 作者的经验清单:rm -rf、https 灾难、烧钱空转、误停服务——一线观察, 无统计口径,但方向与行业公开事故一致9;
  • 作者的立场:auto-edit 可接受(有 git 兜底)、auto-execution 危险—— 这是条件化判断,不是一刀切9;
  • 作者的强主张:纯 AI 生成代码会越来越难接手、团队会失去系统理解—— 书里没给数据,是对行业趋势的判断4

5. 边界与局限

  • 「评审能力跟不上生成速度」书里只是警告,没给解法(抽样审?按风险分级审?); 分级自治部分回答了 agent 动作,但代码评审量的问题书里未解;
  • TDD 一节承认测试可能被 reward hacking,书里的答案是带外 + 人审测试, 但没有讨论「测试覆盖不足时 AI 代码怎么保证对」——测试只保证写到的行为;
  • 人审阈值给的是例子清单(邮件 vs 生产库),真实系统的分级表要自己按 威胁模型定(第 11 章的方法);
  • 代理网关只有一句带过,正式版可能展开(书中多处说「后面会讲」)。

6. 可带走的

  1. 先验证,再信任——顺序不能反;零信任不只管网络,也管代码和 agent 动作;
  2. 词汇即纪律:区分「AI 生成(未审)」与「AI 辅助(人审)」;推未审代码进 PR 是失礼;
  3. 开工前先搭骨架、测试套件与检查器——让 AI 的代码一开始就有栏杆;
  4. 模型推荐旧版本依赖、爱硬编码凭据:依赖扫描 + 秘密检测 + 凭据库,三件常备;
  5. AI 的参与要进开发记录:提交说明注明、代码注释标出 AI 摸过的函数;
  6. TDD 的新价值:先写测试 + 测试带外(CI 隔离),防模型自产自验;
  7. 测试本身也要审——能改考卷的地方就有作弊;
  8. 人审的阈值(什么算「必须等人点头」的门槛)要写下来:草稿不送审,生产库/部署/外发必须等人点头;监督是治理层不是瓶颈;
  9. 分级自治 + 人审反馈回路:批准/否决/修改的记录回头改进 prompt 与护栏;
  10. 想更狠就自己写闸门工具,别依赖通用 agent 框架的默认行为。

7. 原文地图

主题原书章原文位置
信任但要验证 → 先验证再信任、零信任Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:3(搜「Trust but verify」)
AI generated vs AI assisted、反模式、开工搭结构Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:5(搜「AI assisted code」)
plan 文件、分阶段、独立分支、供应链与可审计Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:7(搜「Plan files」)
风险清单:错库/缺验证/弱认证Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:9(搜「wrong libraries」)
可追溯性、标注 AI 参与、StackOverflow 比喻、代理网关Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:11(搜「provenance」)
静态分析/依赖扫描/秘密检测、旧版本、硬编码凭据Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:13(搜「hardcode」)
TDD、reward hacking、带外测试、审测试Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:15(搜「reward hacking」)
HITL、Claude Code auto 模式、rm -rf 案例Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:17(搜「auto-execution」)
阈值分级:邮件 vs 生产库、自写闸门工具Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:19(搜「production database」)
分级自治、治理层、学习回路Verify Before Trusttext/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:21(搜「tiered autonomy」)

Footnotes

  1. 出处:「Verify Before Trust (Code Reviews / Human in the Loop)」第 3 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:3,搜「Trust but verify」)。里根名言逻辑上应为「先验证再信任」;零信任由 John Kindervag 提出,翻转传统网络安全:对每个用户/设备/连接持续显式验证,不分内外;此原则是全书工程核心,适用面远超网络与 API。

  2. 出处:「Verify Before Trust」第 5 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:5,搜「AI assisted code」)。作者显式区分 AI generated(未审)与 AI assisted(人审过/改过);评审是强制步骤;推未审代码给同事/进 PR 是反模式与失礼;工程师应先搭结构、harness 与测试套件(lint/单元/冒烟/集成/系统测试)。 2 3

  3. 出处:「Verify Before Trust」第 9 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:9,搜「wrong libraries」)。AI 代码可能引错库、输入验证不当、认证逻辑弱、违反公司政策;评审要看安全姿态、架构对齐与长期可维护性;目标是借 AI 提速同时保住人的监督与设计模式。

  4. 出处:「Verify Before Trust」第 7 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:7,搜「dwarf」)。AI 产码速度可迅速超过人的评审能力,不慎则失去对系统的深层理解;不理解架构、控制流、权限边界就造不出称职安全的系统;因此推荐 plan 文件、git 式版本、分阶段;AI 工具应视为软件供应链的一部分,维护可审计性与记录。 2

  5. 出处:「Verify Before Trust」第 7 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:7,搜「Plan files」)。plan 文件=人可评审的 markdown,给模型一个每次改动前可回锚的人批架构;每阶段只引入单个特性;改动在独立分支评审后再落地。

  6. 出处:「Verify Before Trust」第 11 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:11,搜「provenance」)。为 AI 参与的改动保持清晰日志与可追溯;组织应把 AI 协助当作开发记录;缺陷溯源要能分辨源于 prompt/生成物/人工修改;提交或 PR 注明 AI 参与、附 prompt 与约束;让 AI 用注释标记它写过的函数;类比 StackOverflow 附链接的好习惯;大组织可用代理网关审计 LLM 用量。 2

  7. 出处:「Verify Before Trust」第 13 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:13,搜「hardcode」)。传统工具照用:静态分析、依赖扫描、安全 linter、秘密检测;模型滞后于最新版,常建议旧而可能带漏洞的库版本;也会乐于硬编码凭据;对策:架构上接好凭据库 + 扫描器兜底复查。 2 3

  8. 出处:「Verify Before Trust」第 15 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:15,搜「reward hacking」)。TDD:先定测试建立清晰期望,生成代码必须满足预定义行为与安全约束;测试放在模型够不着的带外(GitHub Actions/外部 CI/CD),防它既写实现又造出「恰好通过」的验证,降低 reward hacking;测试可由另一模型协助写,但必须独立于开发中的代码;测试与结果也要审。 2

  9. 出处:「Verify Before Trust」第 17 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:17,搜「auto-execution」)。agentic 系统里验证原则的形态是 HITL;Claude Code 原生 HITL,可选 auto-edit 与 auto-execution;作者认为 auto-edit 尚可(仓库收好+git 兜底),auto-execution 危险:见过 rm -rf 大片文件、https 灾难、数小时空转烧钱、不必要地下线服务;即便有隐藏 prompt 审查层仍会漏;自己实现 auto 模式比用 Claude Code 更险。 2 3 4 5

  10. 出处:「Verify Before Trust」第 19 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:19,搜「production database」)。草拟邮件不需审批;改生产库、部署、访问机密、利用活系统、对外通讯应先人审;阈值写进策略/markdown/分级控制;更有效的是自写工具闸住动作、代用户调模型,摆脱通用 harness。

  11. 出处:「Verify Before Trust」第 21 段(text/16-fm-verify-before-trust-code-reviews-human-in-the-lo.txt:21,搜「tiered autonomy」)。分级自治:低风险自主、高风险升级人审;把人的监督当治理层而非常数瓶颈;人审同时是学习机制——批/拒/改反馈回 prompt、护栏、策略与系统设计。