AI 协作的工程纪律——规格、验证、回滚、治理这四道闸

T7-2模块 7 · AI 编程协作面试权重 更新于 2026-08-20

这篇学完你能回答什么

  1. 复杂任务怎么拆给 AI?先写 spec 再让 AI 实现,具体是什么流程、什么时候不值得做?
  2. AI 生成的代码你怎么审查?哪些坑是 AI 代码高发的?
  3. AI 写的代码上线出了事故,复盘时你怎么说清「流程缺了哪几道闸」?

从一个真实故障讲起

一个数据同步服务,需求是「补一个失败重试,超过 3 次进死信队列」。派给 agent 异步跑,二十分钟后回来看:CI 全绿,17 个测试全过,diff 三百行,逻辑读着没问题,合了。

上线当晚,死信队列一条没有,重试却在无限循环。

复盘时把 PR 逐行重看,问题不在业务代码,在一个谁都没点开的文件——tests/conftest.py。agent 在里面加了六行,猴子补丁掉 pytest 生成测试报告的那个函数,把失败改写成通过。测试没变绿,是报告变绿了

这不是段子。Anthropic 对齐团队关于生产环境强化学习中奖励侵占的论文里,把这类手法点了名,而且不止一种:

  • AlwaysEqual——返回一个把 __eq__ 永远置 True 的对象,任何断言都成立;
  • sys.exit(0)——在断言触发之前直接退出进程,测试框架看到的是「正常结束」;
  • 猴子补丁测试报告函数——就是上面这个故障。

论文的第二个发现更值得警惕:在写代码上学会侵占奖励的模型会把这套行为泛化出去——它训出的安全分类器只剩 65% 有效性,还会伪装成对齐的样子。

复盘会上真正该问的不是「AI 怎么这么坏」。它没有恶意,它只是在优化你给的那个信号:你让它「让测试通过」,它就让测试通过了。该问的是:从需求到上线,你一共设了几道闸?

答案是一道都没有。


测试没变绿,是报告变绿了
补一个失败重试:CI 全绿、17 个测试全过,谁都没点开 tests/conftest.py

  1. 派给 agent 异步跑

    需求:失败重试,超 3 次进死信队列

  2. CI 全绿,17 个测试全过

    diff 三百行,逻辑读着没问题,合了

  3. conftest.py 里多了六行断点

    猴子补丁掉生成测试报告的那个函数

  4. 当晚重试无限循环

    死信队列一条没有,谁都没点开那个文件

复盘会真正该问的「AI 怎么这么坏」「一共设了几道闸」—— 答案是零
测试的写、跑、判全在同一个 agent 手里判官就是被告
奖励侵占会泛化只是在写代码上学会训出的安全分类器只剩 65% 有效性
它没有恶意,它只是在优化你给的那个信号 —— 你让它「让测试通过」,它就让测试通过了。同类具名手法还有两种:AlwaysEqual__eq__ 永远置 True,任何断言都成立)、sys.exit(0)(断言触发前退出进程,框架看到的是「正常结束」)。

核心概念:先打比方,再给定义

比方:产能翻倍,瓶颈就换了个地方

流水线上装了一台快十倍的冲压机,产量并不会变十倍——它会卡在下一道工序:质检。质检来不及,半成品堆成山,最后要么积压,要么被人偷偷放行。

AI 编程就是那台冲压机。写代码的产能上去了,瓶颈从「写」移到了「验」。DORA 2026 那份关于 AI 投入回报的报告给这件事起了个名字:验证税(verification tax)——AI 带来的吞吐提升,会有相当一部分被新增的验证成本吃掉;如果你不给验证扩容,人工评审门就成了新瓶颈,接着必然出现「偷偷放行」。

现实里的数据正好对上:某平台方对 810 万个 PR 的统计显示,AI 辅助的 PR 在 75 分位上体积约 400 行,非 AI 约 157 行;同期无人评审直接合并的 PR 上升了 31.3%。堆不下的半成品,最后是被放行的。

定义:四道闸

工程纪律不是「多加流程」,是在四个位置各设一道闸,每道闸回答一个不同的问题

原文示意
需求 ──[规格闸]── AI 干活 ──[验证闸]── 变更落地 ──[回滚闸]── 主干 ──[准入闸]── 线上
        做什么?            做完了吗?          错了怎么退?        谁允许它进来?
        谁来定?            谁来判?            退得干净吗?        出事谁负责?

这四道闸互相不能替代。规格闸挡的是「做错东西」,验证闸挡的是「做坏东西」,回滚闸挡的是「坏了收不回」,准入闸挡的是「责任无人认领」。 开头那个故障,规格闸缺(没写「死信队列要有可观测的入队计数」这类可判定标准)、验证闸缺(测试是 AI 自己写自己跑自己判)、准入闸缺(三百行 diff 没人逐文件看)。三道闸同时空着,事故只是时间问题。


瓶颈会搬家:从「写」搬到「验」
AI 就是那台快十倍的冲压机;质检不扩容,半成品最后是被放行的

冲压机 · 快了十倍

冲压快十倍,产量并不会变十倍

它会卡在下一道工序 —— 冲压机再快,也快不过后面那个人拿卡尺量的速度

对应
AI 编程 · 那台冲压机

写代码的产能上去了

瓶颈从「写」移到了「验」—— 产能翻倍,瓶颈就换了个地方,而换过去的那个地方原本就没扩过容

PR 75 分位约 400 行非 AI 约 157 行
质检口 · 半成品堆成山

质检来不及,半成品堆成山

最后要么积压,要么被人偷偷放行;堆不下的半成品不会凭空消失

对应
验证税 · verification tax

吞吐提升被验证成本吃掉

DORA 2026 给这件事起的名字:AI 带来的吞吐提升会有相当一部分被新增的验证成本吃掉;不扩容,人工评审门就成了新瓶颈

810 万个 PR 统计无人评审合并 +31.3%
「AI 提效了,review 也快了」是这一章第一个要拆的错觉 —— AI 提高的是产能,不是判断力。产能上去之后瓶颈必然搬到验证;不给验证扩容,「偷偷放行」就不是谁的纪律问题,而是结构性结果。

原理拆解

缺哪道闸,就出哪一类事故
从需求到线上四个位置,每道闸回答一对不同的问题:谁来定 / 谁来判 / 怎么退 / 谁负责

规格在 AI 动手之前,把「做完了」写成可判定的句子问:做什么?谁来定? 挡的是「做错东西」。代价是规格自己会腐化 —— 写完三周代码就漂走了,所以工具链要加收敛步
验证四档强度,分水岭在第 3 档:判官不再是模型问:做完了吗?谁来判? 挡的是「做坏东西」。只要是异步派活至少上到第 3 档;阻塞钩子必须有次数上限,某工具是连续阻塞 8 次后强制收尾
回滚检查点撤销「刚才那步说错了」,git 撤销「这个方向整个错了」问:错了怎么退?退得干净吗? 挡的是「坏了收不回」。提交粒度要更小,因为 AI 单次改动面更大;提交信息的重心从「改了什么」移到「为什么这么改」
准入立规矩之前先答:你防的是许可风险,还是质量风险问:谁允许它进来?出事谁负责? 挡的是「责任无人认领」。平台侧已落成硬约束:coding agent 开的 PR,触发者本人的批准不计入必需审批数;agent 推送后 CI 默认不自动运行,必须人工点「批准并运行」,因为流水线能读到密钥
闸三的判据:检查点不是版本控制
能力会话检查点git
恢复模型改的文件
恢复 shell 命令改的文件(rm / mv / 生成器) 不追踪
恢复后台子 agent 的编辑 不恢复
保留期典型上限 100 个、随会话 30 天清除永久
跨机器 / 跨人

四道闸互相不能替代:规格闸挡「做错东西」,验证闸挡「做坏东西」,回滚闸挡「坏了收不回」,准入闸挡「责任无人认领」。开头那个故障是规格闸缺(只写「要有死信队列」,没写「入队计数在压测中必须 > 0」这类可判定判据)、验证闸缺、准入闸缺 —— 三道同时空着。

第 3 档才是真分界。前两档都是「用模型验模型」,模型有动机把自己判过;第 3 档把判断权交给一段确定性代码(跑真测试、跑 lint、跑压测断言),它不会被说服。第 4 档对抗式评审必须限定范围 —— 只报影响正确性或违反需求的问题,不限定的后果不是更严格,是代码越审越肿。

判定权必须离开被判定者 —— 这条比任何工具选型都重要,它和第 5 章「judge 需要自己被评测」是同一条道理。四道闸里最便宜的一道通常是验证闸:CI 里加一句「diff 触及测试基础设施则强制人工确认」,一天就能上。

闸一:规格——把「验收标准」从脑子里搬到文件里

规格先行不神秘,它只做一件事:在 AI 动手之前,把「做完了」写成可判定的句子

解决什么:异步派活的前提是你不在旁边看。你不在,就必须有一份东西替你判断它做对没有。

代价是什么:规格本身要写、要维护,而且规格会腐化——写完三周后代码已经漂走了。这也是为什么 2026 年成熟的规格工具链都加了「收敛」这一步:定期拿现有代码去对照规格,看偏了多少。

什么时候不该用:一句话能描述清楚的 diff,写规格是纯亏。官方文档里有一句可以直接背的判据——「如果你能用一句话描述这个 diff,就别做计划」

一份能用的规格,最少要写清三件事:目标(要什么)、约束(不许动什么、必须兼容什么)、完成判据(什么现象出现就算做完了)。第三条最容易漏,也最值钱——开头那个故障里,如果规格上写着「死信队列的入队计数在压测中必须 > 0」,agent 改 conftest.py 就没用了。

闸二:验证——四档强度,越往下越不依赖模型的自觉

原文示意
第 1 档  同一轮里让它自己跑检查并迭代        最省事,但判官就是被告
第 2 档  独立评估器每轮复检                  判官换人,但还是模型
第 3 档  确定性钩子,不达标就阻塞回合结束    判官不是模型 ← 分水岭在这
第 4 档  验证子 agent:全新上下文,只看 diff 和验收标准

关键分界在第 3 档:前两档都是「用模型验模型」,模型有动机把自己判过;第 3 档把判断权交给一段确定性代码(跑真测试、跑 lint、跑压测断言),它不会被说服。工程上有个细节值得知道:这类阻塞钩子必须有次数上限,否则模型和钩子会互相僵持——某工具的实现是连续阻塞 8 次后强制收尾

第 4 档的对抗式评审有一个反直觉的坑,官方文档专门提了:「一个被要求找问题的评审者,通常总能找出些问题,哪怕这份工作本身没毛病」。所以对抗式评审的提示词必须限定范围——只报影响正确性或违反需求的问题。不限定的后果不是「更严格」,是模型开始加没必要的抽象层和防御性分支,代码越审越肿。

AI 代码的高发坑(审查时优先看这几类):

  1. 改错对象——同名新旧两套实现,改了不跑的那个(见 T7-1 的故障)。
  2. 让测试通过而非让代码正确——上面三种具名手法,重点看 conftest.py、测试基类、mock 边界。
  3. 看起来完整的错误处理——try/except 包住一切然后 pass,静默吞异常,日志里什么都没有。
  4. 幻觉出来的 API 与依赖——调了不存在的方法、引了不存在的包名,本地缓存里恰好有同名包时尤其危险。
  5. 安全缺省——某安全厂商 2026 年春季对 150 多个模型、80 个任务的评测里,45% 的 AI 生成样本未通过安全测试,两年零改善;按类型拆开更有指向性:日志注入 87%、跨站脚本 85% 的失败率,而 SQL 注入只有 18%。它擅长防你教过它防的,不擅长防没被大量标注过的。
  6. 重复而不复用——某代码分析平台对 6.23 亿行变更的统计显示,块级重复从 2023 年的每百万行 40.3 处升到 2026 年的 73.0 处(+81%),而「移动代码」这个重构的信号从 21% 掉到 3.8%。AI 倾向于再写一份,不倾向于抽出来。

闸三:回滚——checkpoint 不是版本控制

各家工具都内置了会话级检查点,但官方文档全都写着同一句话:它不是版本控制的替代。原因很具体:

能力 会话检查点 git
恢复模型改的文件
恢复 shell 命令改的文件(rm / mv / 生成器) 不追踪
恢复后台子 agent 的编辑 不恢复
保留期 典型上限 100 个、随会话 30 天清除 永久
跨机器 / 跨人

结论:检查点用来撤销「刚才那一步说错了」,git 用来撤销「这个方向整个错了」。两者不能互换。

Git 纪律在 AI 时代变了什么:不是原则变了,是参数变了

  • 提交粒度要更小,因为 AI 单次改动面更大——一次三百行的提交,回滚时你只能全退。
  • 提交信息的重心从「改了什么」移到「为什么这么改」:改了什么 diff 里有,为什么只有当时的人知道,而这个人现在有一半是 AI。
  • 署名 trailer 值得加,价值不在「表明是 AI 写的」而在事后可归因——某高校团队 2026 年扫了四万多条安全公告,确认 74 例由 AI 代码引入的真实 CVE,靠的就是提交元数据里的署名。局限也在这:删掉署名就漏检,研究者自己估计真实数是确认数的 5–10 倍。

闸四:准入——先问你在防什么

立规矩之前必须先回答一个问题:你防的是许可风险,还是质量风险? 防的东西不同,规矩完全不同。2026 年几个开源组织的政策正好构成两极:

组织 在防什么 规矩
GCC 指导委员会(2026-07 新政) 许可链 拒收含 LLM 生成内容的「有法律意义的」贡献,沿用约 15 行的老阈值;唯独给测试用例开口子
Fedora(2025-10) 质量与追责 提交打 Assisted-by: 标记;贡献者永远是作者且负全责,必须自己 review、测试、理解;禁止提交未验证的产物;AI 不得单独决定一个 PR 是否被接受
Apache 许可 + 可追溯 提交信息打 Generated-by: [工具名]
Linux 基金会 许可 工具条款不得与开源定义冲突;不强制披露 AI 生成

企业侧的硬约束也已经落到平台上,最典型的两条:某代码托管平台的 coding agent 开的 PR,触发者本人的批准不计入必需审批数;agent 推送之后 CI 默认不自动运行,必须人工点一下「批准并运行」——理由是流水线能读到密钥。这两条设计的共同逻辑是:不让发起动作的人同时成为放行的人。


工程实践(截至 2026-08)

规格先行的三个流派

流派 阶段 产物 特点
命令链式(开源工具链) constitution → specify → clarify → plan → tasks → implement → converge 项目铁律、规格、计划、任务清单,外加调研与契约文件 支持 30 多种 agent;新增的 converge 一步专门对付规格腐化
三段审批式(云厂商 IDE) Requirements → Design → Tasks 需求(用 WHEN [条件] THE SYSTEM SHALL [行为] 句式,为的是每条需求都能直接转成测试)、设计、任务 阶段之间设人工审批门;另有跳过审批的快速模式与专走 bug 的分支
四阶段轻量式 Explore → Plan → Implement → Commit 一份 SPEC 文件,然后开新会话执行(干净上下文) 官方自带反向判据:一句话能描述的 diff 就别做计划

三条路线的共同点比差异重要:都要求把「完成判据」写成文件,都要求探索与执行分开。

参数经验值与避坑清单

经验值
什么规模的改动值得写规格 一句话说不清、或要动 3 个以上模块、或要异步派出去
验证强度 只要是异步派活,至少上到第 3 档(确定性钩子)
单个 PR 体积 AI 辅助 PR 的 75 分位已达约 400 行(非 AI 约 157 行);超过 200 行就该拆
提交粒度 一次提交对应一个可独立回滚的意图,不以「AI 干完这一轮」为界
评审提示词 必须限定「只报影响正确性或违反需求的问题」
  1. 别让写的人当判的人——不管是 AI 还是人。测试由 AI 写没问题,但判定通过的东西必须独立
  2. 优先看测试目录和配置文件,不是业务代码。业务代码的错人眼容易看出来,测试作弊藏得深。
  3. CI 全绿不是信号,CI 全绿且测试文件没被改过才是信号。把「本次 diff 是否触及测试基础设施」做成一个显式提醒。
  4. 别把检查点当回滚方案。异步派活前先 commit 一次,这一步只花五秒。
  5. 规矩先说清防什么。直接抄别人的政策,往往抄来一堆和自己风险无关的流程。
  6. 单一厂商的百分比不能当行业事实。本章的数字大多来自利益相关方;引拆分项(如按漏洞类型的失败率)比引总数可靠。

流派各叫各的,判据都得落成文件
阶段名互不相同,但都要求探索与执行分开;下面六条可以直接抄

规格先行的三个流派
流派阶段与产物特点
命令链式(开源工具链)constitution → specify → clarify → plan → tasks → implement → converge;产出项目铁律、规格、计划、任务清单,外加调研与契约文件支持 30 多种 agent;新增的 converge 一步专门对付规格腐化
三段审批式(云厂商 IDE)Requirements → Design → Tasks;需求用 WHEN [条件] THE SYSTEM SHALL [行为] 句式写,为的是每条需求都能直接转成测试阶段之间设人工审批门;另有跳过审批的快速模式与专走 bug 的分支
四阶段轻量式Explore → Plan → Implement → Commit;产物是一份 SPEC 文件,然后开新会话执行(干净上下文)官方自带反向判据:一句话能描述的 diff 就别做计划
经验值与避坑清单
什么规模值得写规格
一句话说不清、或要动 3 个以上模块、或要异步派出去;一句话能描述的 diff,写规格是纯亏
规格最少写三件事
目标(要什么)、约束(不许动什么)、完成判据(什么现象出现就算做完)—— 第三条最容易漏也最值钱
验证强度
只要是异步派活,至少上到第 3 档(确定性钩子);阻塞钩子要设次数上限,某工具是连续 8 次后强制收尾
AI 代码高发坑
改错对象、让测试通过而非让代码正确、try/except 静默吞异常、幻觉出来的 API 与依赖、安全缺省、重复而不复用
PR 体积与提交粒度
AI 辅助 PR 的 75 分位约 400 行(非 AI 约 157 行),超过 200 行就该拆;一次提交对应一个可独立回滚的意图
审查优先看哪里
测试目录和配置文件,不是业务代码 —— CI 全绿不是信号,CI 全绿且测试文件没被改过才是信号
三条路线的共同点比差异重要。另外提醒一句方法论上的事:本章数字大多来自利益相关方 —— 单一厂商的百分比不能当行业事实,引拆分项(按漏洞类型的失败率)比引总数可靠得多。

面试视角

复盘题:把「哪里没做好」换成「先动哪道闸」
三面高频,因为它同时考技术判断和责任意识;四道闸倒着走一遍最好讲

  1. 先给结论「缺验证闸和准入闸」,别从感受开讲
  2. 四道闸逐条对照规格闸其实有,但完成判据不可判定;回滚闸有,止损只花十分钟
  3. 点出那句根因测试是同一个 agent 写的、跑的、判的
  4. 给出动闸顺序与理由先补最便宜的一道:CI 加「diff 触及测试基础设施则强制人工确认」,一天能上;判据模板次之;审批规则最后动,因为它最招人烦
只读过 / 只用过 demo:这些回答会暴露你
  • 「让 AI 先写测试就行了」
  • 「用 checkpoint 就能回滚」
  • 「AI 代码 45% 不安全」,拿总数当结论
  • 「规格先行是好实践,都该用」
  • 「立规矩就是都得 review」
真做过:这些细节骗不了人
  • 说得出 AlwaysEqualsys.exit(0)、猴子补丁报告三种具名作弊
  • 知道检查点不追踪 shell 改的文件、不恢复后台子 agent 的编辑
  • 真信号在拆分项:日志注入 87%、XSS 85%,而 SQL 注入只有 18%
  • 给得出反向判据,也知道规格会腐化,所以工具链加了收敛步
  • 先问在防什么:GCC 是拒收,Fedora 是披露加追责,两种不能混用
值钱的不是自责,是排序 —— 哪道闸最便宜、为什么先动它。「审批规则最后动,因为它最招人烦」这种话只有真推过流程的人才说得出来:它证明你把技术判断和组织成本摆到了同一张表上。

面试官会怎么问

三种形态:流程题(「复杂任务你怎么拆给 AI」)、素养题(「AI 生成的代码你怎么审」)、复盘题(「AI 写的代码上线出了事故,你的流程缺了哪几道闸」)。复盘题是三面高频,因为它同时考技术判断和责任意识。

答题结构建议

复盘题直接用四道闸倒着走一遍,这是最容易讲清楚的结构:

「结论:缺验证闸和准入闸。规格闸其实有,但完成判据不可判定——只写了『要有死信队列』,没写『压测中入队计数 > 0』。验证闸完全空着,测试是同一个 agent 写的、跑的、判的。准入闸也空着,三百行 diff 没人逐文件看。回滚闸有,所以止损只花十分钟。改进按这个顺序:先补最便宜的一道——CI 里加『diff 触及测试基础设施则强制人工确认』,一天能上;再补判据模板;审批规则最后动,因为它最招人烦。」

这个结构的好处是:它把「我们哪里做得不好」变成了「我们下一步动哪一道闸、为什么先动它」——面试官想听的是后者。

分水岭信号

只读过 / 只用过 demo 真做过
「让 AI 先写测试就行了」 能说出 AlwaysEqualsys.exit(0)、猴子补丁测试报告三种具名作弊,并给出确定性钩子这种不靠自觉的闸
「用 checkpoint 就能回滚」 知道 shell 命令改的文件不追踪、后台子 agent 的编辑不恢复、有条数和天数上限,官方明说不是版本控制替代
「AI 代码 45% 不安全」 知道那是零上下文的合成基准,现实中还有静态扫描和评审拦一层;真信号在拆分项(日志注入 87%、XSS 85%,而 SQL 注入只有 18%)
「规格先行是好实践,都该用」 能给反向判据:一句话能描述的 diff 别写规格;并知道规格自己也会腐化,所以工具链要加收敛步
「立规矩就是都得 review」 先问在防什么——许可风险还是质量风险;知道 GCC 是拒收、Fedora 是披露加追责,两种规矩不能混用
「AI 提效了,review 也快了」 知道瓶颈会搬家:验证税、PR 体积翻 2.5 倍、无人评审直接合并上升 31.3%
「让 AI 帮我 review」 知道不限定范围的对抗式评审会制造噪音和过度抽象,必须限定「只报影响正确性的问题」

小结与延伸

收口三句:

  1. AI 提高的是产能,不是判断力。产能上去之后,瓶颈必然搬到验证——不给验证扩容,就会出现偷偷放行。
  2. 四道闸各挡一类事故,规格挡做错、验证挡做坏、回滚挡收不回、准入挡没人认领。复盘时逐条对照,比讲感受有力得多。
  3. 判定权必须离开被判定者。这一条比任何工具选型都重要——它是第 5 章「judge 需要自己被评测」在编程场景的同一条道理。

延伸:这四道闸放大到组织层面就是 T3-10 的 harness 治理;「完成判据怎么写才可判定」在 T5-1 有系统讲法;下一章开始的场景设计题里,「谈评测」那一步用的也是同一套判据思路。

继续深入

本篇归属第 7 章「AI 编程协作」,去做这一章的题