审查 AI 生成代码,别只看 PR 大小:用影响半径分配审查精力
一套面向创始人的 AI 生成代码审查方法:不再只看行数,而是根据用户影响、可逆性、可观测性和灰度风险决定审查深度。
一个 AI 编码 Agent 为新的新用户引导流程提交了 1900 行 PR。第一眼看上去很吓人。但这个功能默认关闭,只增加兼容旧版本的字段,可以只对一个内部账号开启,也能不重新部署就关闭。同一周,另一个人提交了 14 行改动,修改计费 webhook 的签名校验方式。这个 PR 很整洁,却可能在部署后立刻影响所有客户:一旦逻辑出错,伪造请求就可能改写订阅状态。
哪一个更值得投入更长的人工审查?
PR 大小能够反映理解成本:审查者需要读懂多少材料。它却很难准确反映失败成本:一个缺陷在被发现和控制之前,能影响多少用户、记录、权限或商业承诺。AI 编码 Agent 可以用远快于人工阅读的速度生成跨前端、后端、数据层的完整功能,这让两个概念之间的差别再也无法忽略。
本文适合正在用 AI app builder 或编码 Agent 开发真实产品的非技术创始人和小团队。核心判断是:仍然要让变更保持可理解,但审查精力和发布控制应按影响半径分配,不能只按行数分配。读完你会得到一组清晰术语、一张可复用的变更风险卡、一个完整上线案例、低中高三档审查规则、一套渐进式发布阶梯,以及一次 60 分钟演练。
这套方法不会让大 PR 天然变安全,也不能替代专业安全审查,更不允许团队发布无人理解的生成代码。它适用于能够测试、观测、限制暴露范围并执行恢复的产品。涉及监管决定、不可逆数据损失、安全关键系统或重大资金权限时,需要更严格的领域控制。
Y Build 的合并证据包解决的是“这个确定版本在合并前必须证明什么”。本文处理下一步更窄的问题:有限审查时间应该花在哪里,以及现有证据只配获得多大的生产暴露范围。如果 AI Agent 已能执行破坏性动作,还要使用单独的英文恢复边界框架。
Rootly 案例真正说明了什么
本文的直接触发点来自 Rootly。2026 年 5 月,这家事故管理公司解释了为什么取消严格的小 PR 规则。按照它的第一方复盘,AI Agent 越来越常一次生成完整功能,包括 migration、数据模型、服务、测试和界面。把一项完整工作人为拆成多个 PR 后,审查者反而要在多个页面之间重新拼接依赖。Rootly 因此用风险标签、强制回滚计划、生产验证和功能开关下的渐进式发布,取代了单纯的行数代理指标。
这里最值得学的并不是“大 PR 更好”,而是一个流程指标已经不能回答团队真正关心的问题。过去,小 diff 往往对应一小段人的思考过程,也更容易 revert。Agent 能跨层生成一项完整功能后,行数仍能预测阅读负担,却不再可靠地预测功能抵达用户时是否安全。
Rootly 还说,审查者会把主要精力放在上下文、共享边界、migration、安全敏感行为和 rollout 路径上。这个方向合理,但它仍然只是一家公司的运营经验,不是通用证明。Rootly 团队有事故响应专长和内部自动审查系统,两人创业团队未必具备同样基础。创始人应该复制它提出的问题——“如果这里出错,什么会坏?”——而不是照搬它对大 PR 的容忍度。
也要保留反方向的证据。Google SRE 指南认为,小而自包含的发布制品能降低回滚成本,也有利于自动化交付。其小流量试运行指南并没有为任意大批量变更背书,而是主张把变更只暴露给一部分流量、限定观察时间,并与控制组比较信号。把两边放在一起,结论更稳健:
- 尽量让逻辑变更完整、连贯、可理解。
- 尽量让每一步的暴露单元小于潜在失败范围。
- 根据后果、不确定性和恢复能力分配审查时间,而不是只看生成了多少行。
先把术语说清楚,再贴风险标签
团队常把“小”“安全”“可逆”“有 feature flag”当成令人安心的形容词。真正上线时,它们必须有可操作的定义。
Diff 大小是源代码变更的体量。最常见的代理指标是变更行数,但生成文件、lockfile、snapshot、格式化和文件移动都会扭曲这个数字。它主要影响一个提案有多难检查。 逻辑变更是一项完整业务或技术结果的最小闭环。例如,“在新用户引导中询问公司规模并保存答案”是一项逻辑变更。单独一个数据库 migration 未必是完整变更,因为线上应用可能还无法安全读取新结构。 影响半径(blast radius)是缺陷被发现和停止之前,可信的最大伤害范围。范围可能由用户数、租户数、记录、金额、密钥、外发消息、生产容量或信任损失衡量。它既包括谁会被暴露,也包括这项变更有权影响什么。 暴露单元是每一步 rollout 实际接收新行为的人群或资源。它可以是一个内部账号、五个知情试用客户、5% 的无状态请求、一个队列消费者,也可以是 migration 触及的所有既有记录。 可逆性是指团队能在已知时间内恢复之前的安全行为,而不是事故发生后临时发明修复方法。关掉 feature flag 也许能恢复旧代码路径,但不会自动找回已删除字段、撤回邮件、收回泄露密钥或取消已经发生的付款。 可观测性是指团队能否及时把候选版本的重要结果与控制组分开,并据此采取行动。如果 dashboard 只有全站总量,无法按版本和 cohort 区分错误、延迟、转化或错误写入,它就不足以支持灰度判断。 审查预算是用于理解意图、检查高风险路径、核验证据并决定是否扩大 rollout 的稀缺人工注意力。即使 diff 很短,只要后果或不确定性上升,审查预算就应该上升。这些定义可以阻止一种常见的分类错误:一项变更可能很好读但发布很危险,也可能很难读但能被严密限制。审查流程必须同时看到这两个轴。
保留两个坐标轴:理解成本与失败成本
不要用模糊的“风险驱动”口号替换“小 PR”。把决策画成两个坐标轴:
| 失败成本较低 | 失败成本较高 | |
|---|---|---|
| 理解成本较低 | 快速审查,运行常规自动检查 | 深查敏感路径,独立批准,限制 rollout |
| 理解成本较高 | 重组内容、补充证据或按完整边界拆分,再做小范围试用 | 在进入审查前先停下并重构变更或发布方案 |
左上格最日常,例如一处文案调整或隔离良好、测试明确的组件修复。右上格最能暴露“只看行数”的问题:一行权限通配符、一个很短的支付路由改动,或者一个可能锁住关键表的小 migration。
左下格在生成代码中很常见。一个新的内部报告可能同时改动 API 类型、视图、测试和 fixture,diff 很大,但只读且只对一个内部账号开放。不能因此草率通过。团队应提供架构说明,把机械生成文件单独呈现,增加契约测试,在适合时提供截图,并给审查者一张阅读地图,先降低理解成本,再把暴露范围保持在很小的圈内。
右下格不是“更努力读代码”能解决的问题。一项覆盖全部租户的身份系统重写,如果同时改动持久数据、没有按版本区分的信号、又不能独立关闭,就应先重构设计。把它拆成十个 PR 或许方便逐段阅读,却可能仍然保留一次全局且不可逆的生产切换。反过来,把所有代码塞进一个 PR,也不能让互不相关的业务结果自动变成一项完整逻辑变更。
可理解性仍然是安全控制,但它和影响控制不是同一种控制。
读 diff 前,先填写变更风险卡
提出变更的人应该填写这张卡。对于 AI 生成工作,不要让 Agent 编造商业动机或可接受损失。Agent 可以收集证据,但为什么要改、公司愿意承担什么后果,必须由人类负责人写明。
每个维度从 0 到 3 打分。使用“最可信的严重后果”,而不是演示中最顺利的情况。
| 维度 | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 用户覆盖 | 仅本地或合成数据 | 内部用户 | 少量具名试用用户 | 所有用户或范围未知 |
| 权限与数据 | 仅展示层 | 只读非敏感数据 | 客户数据或有限写入 | 身份、密钥、资金、删除、对外发布 |
| 状态变化 | 无持久状态 | 增量且隔离的状态 | 共享契约或可修复 migration | 破坏性或单向变化 |
| 可逆性 | 立即关闭且无残留 | 15 分钟内有明确回滚 | 需要人工修复或恢复 | 不可逆、未演练或恢复时间未知 |
| 发现能力 | 发布前有确定性测试 | 数分钟内有版本级告警 | 只能靠间接或延迟业务信号 | 没有可靠信号或无法归因 |
| 耦合范围 | 单个隔离组件 | 已知内部接口 | 多服务、任务或供应商 | 消费方未知或可能跨租户 |
接着记录证据,不能只留数字:
change: "在新用户引导中保存公司规模"
owner: "Mina"
business_reason: "为用户选择正确的引导路径"
generated_scope: "表单、API 路由、增量字段、测试、分析事件"
scores:
user_reach: 1
authority_and_data: 2
state_transition: 1
reversibility: 1
detection: 1
coupling: 1
exposure_unit: "员工账号,然后是 10 个知情的新注册用户"
success_signal: "按发布 cohort 观察完成率和有效 company_size 写入"
stop_signal: "schema 错误、完成率下降超过 2 个百分点、或写入错误租户"
stop_action: "关闭开关;保留增量字段;切回旧引导流程"
recovery_owner: "Mina"
evidence_links: ["测试运行", "dashboard", "migration 计划", "停止演练"]
unknowns: ["有一个 CRM 同步消费方尚未覆盖测试"]
可以采用以下简单决策规则:
- 低风险:没有维度为 3;最多一个维度为 2;有确定的验收测试和立即关闭路径。
- 中风险:两个或更多维度为 2;或者一个维度为 3,但暴露范围能够限制在内部或具名试用用户。
- 高风险:两个维度为 3;存在未知的破坏性状态变化;或广泛影响身份验证、密钥、支付、删除、租户隔离或公开沟通。
3 且恢复未知,比多个无害的 1 更值得关注。
比较一项大型功能和一处微小安全改动
假设一个小型 B2B 产品正在用 AI 编码 Agent 改进新用户引导。
变更 A:1900 行的新用户引导功能
Agent 增加了公司规模问题、一个允许为空的增量数据库字段、验证 schema、新引导分支、分析事件和测试。功能默认关闭,员工账号可以主动开启,现有用户完全看不到。旧路由仍保留,发布 dashboard 能区分候选组和控制组。
这个 diff 的理解成本很高。审查者不能通过快速扫一眼假装已经理解。团队可以把机械生成的 snapshot 分开,提供六个变更边界的阅读地图,运行契约和端到端测试,人工检查 migration 与 tenant key,再明确审查旧路由 fallback,从而让它变得可审查。
它最初的失败成本仍可很低。只有员工被暴露;migration 是增量的;旧应用能容忍新 nullable 字段;开关可以关闭行为;分析事件失败不会阻塞引导。当内部 cohort 通过后,再让十个知情的新注册用户试用,同时监控完成率和写入有效性。
不能仅因为“有开关”就批准 A。必须证明 happy path 和 error path 都正确检查了开关,migration 与旧版本兼容,观测系统能区分 cohort,并且有人实际执行过停止动作。
变更 B:14 行的 webhook 校验修改
第二个 PR 修改一个依赖库调用,并接受计费供应商的一种新 header 格式,附带一个单元测试。它非常容易读懂,却作用于把签名支付事件转换为所有租户订阅状态的端点。
这项变更在权限、覆盖范围、耦合和发现不确定性上都得高分。缺陷可能拒绝正常续费,也可能接受伪造输入。一次全量部署会立刻暴露所有人。即使回滚代码,也未必能修复已经被错误事件改写的订阅记录。
B 需要独立核验供应商的签名消息契约,准备所有支持事件版本的固定 fixture,测试重放和时间戳,检查 fail-closed 行为与租户映射,增加版本级告警,并准备 reconciliation 查询。如果流量不能安全镜像或缩小,团队应选择有人值守的发布窗口,并准备快速关闭端点或切换为排队模式。
这个对比给出一条创始人能真正使用的规则:可读性决定一项变更是否能被审查;影响半径决定它需要多少证据、独立性与 rollout 保护。14 行也可能比 1900 行需要更多上线工作。
按风险等级分配审查工作
风险卡必须改变团队的实际动作,不能只多一个标签。
低风险:核对意图与自动化证据
一名负责人可以完成审查。确认预期结果与 diff 一致,测试覆盖验收条件,没有混入无关文件,disable 或 revert 路径确实存在。只要用户覆盖仍然很窄、监控已经建立,常规部署即可。
中风险:检查边界并证明可控
要求未参与生成变更的第二个人,审查分数最高的维度。重点检查 migration、授权、租户过滤、外部调用、队列、定时任务、配置和 feature flag 行为。在 staging 实际执行一次 rollback 或关闭开关。先从内部或具名 cohort 开始,并等待足够时间,让选定信号真正出现。
GitHub environment 可以要求指定 reviewer、防止自审、限制部署分支、在批准前不释放 environment secrets,并把自定义保护规则连接到可观测性或变更管理系统。官方部署与环境文档列出了这些能力。但只有在发起者无法绕过规则、审批者又能看到风险卡和证据时,它们才真的形成职责分离。
高风险:先重构风险,再引入独立权力
不要把一个不受控制的高风险变更扔进“逐行英雄式审查”。先降低覆盖范围、权限、状态耦合或不可逆性。把破坏性清理从增量 migration 中分开;增加只读或 shadow 模式;把外部动作放入队列;增加 off path 已测试的开关;建立版本级信号。如果后果仍然重大,应按情况引入合格的安全、数据、法律、财务或运营审查。
AWS Well-Architected Framework 建议采用安全部署策略,包括 feature flag、one-box 或 canary、不可变发布、流量切分和蓝绿部署。对创始人来说,重点不是一次上齐所有技术,而是让发布控制与失败机制匹配。
把最终闸门从 merge 移到受控暴露
Merge 审查回答“这份提案是否可以进入代码库”;rollout 回答“这个新行为是否已经赢得更大的用户暴露”。两者应当是两个独立决定。
普通 Web 功能可以使用以下阶梯:
- 仅构建:完成编译、静态检查、单元测试、依赖检查和生成文件审查。
- 合成环境:用 fixture 跑端到端流程,不携带生产权限或客户数据。
- 内部使用:只暴露给具名员工账号,验证开关 on/off 两条路径。
- 具名试用:开放给少量知情客户,他们的预期工作流应当已知。
- 比例 cohort:只有在指标能独立识别候选版本时,才继续扩大比例。
- 全面发布:观察窗口覆盖重要延迟效应后,再升到 100%。
- 清理:用单独、受审查的变更移除临时兼容路径和过期开关。
Google SRE 的 canary 指南正好说明了这个测量问题:候选 cohort 很小,即使自身错误率很高,也可能只让全站平均值轻微变化。因此候选信号和控制组必须能分开。它还指出,限制暴露可以限制被置于风险中的 error budget;canary 不能证明正确,但能降低学习成本。
Cloudflare Workers 的渐进式部署文档提供了一个当前实现:流量可在版本间切分,指标可按版本观察,也可以回滚。文档同时提醒 version skew:同一用户的连续请求或不同 Worker 的 service binding 可能抵达不同版本,并提供 version affinity 和 override 方案。渐进式发布会带来自己的失败模式,不能把“切了百分比”误当成真正隔离;发布计划必须测试混合版本契约。
把 feature flag 和 rollback 当成待验证声明
“有开关”不等于“安全”。只有当所有会造成后果的路径都检查开关、off 状态保留旧行为、事故中的操作人有权修改它,而且不可避免的副作用不会在检查前发生时,开关才真正缩小影响范围。
遇到单向状态时,feature flag 尤其脆弱。如果新代码写入旧代码无法读取的格式,关掉界面也恢复不了兼容性;如果 migration 已删字段,开关不能把字段变回来;如果功能已经发信或付款,off 只能阻止未来动作,无法逆转过去动作。
共享 schema 可使用 expand-and-contract:先增加兼容的新结构;发布能同时容忍新旧状态的代码;带着观测做 backfill;验证后切换读取;最后再删除旧结构。Prisma 官方的扩展—收缩 migration 指南展示了这种模式,并建议在生产数据副本上测试和提前备份。不同数据库命令会不同,原则都是把可逆的引入阶段与破坏性清理阶段分开。
Cloudflare 的回滚文档明确写出了平台边界:代码可以回到旧版本,连接的资源不会随之回滚,数据结构变化还可能让旧代码出错。因此,风险卡中的每一个 rollback 声明都要回答两个问题:
- 哪一部分代码或配置会恢复到已知正常版本?
- 哪些持久副作用仍会保留,又准备如何 reconciliation、恢复或接受?
衡量交付结果,不要奖励“小 diff”表象
团队会优化负责人公开表扬的东西。如果创始人只表扬 PR 数量和小 diff,人和 Agent 都会不断拆分工作,直到指标看起来健康。结果可能是依赖栈、重复的审查准备和虚假的安全感,而生产后果并没有变小。
可以改为记录少量结果指标:
- 需要立即人工干预的发布占比。
- 从停止信号出现到恢复安全服务的时间。
- 为修复前一次发布而进行的非计划部署占比。
- 中高风险变更中,真正演练过停止动作的比例。
- rollout 中能把候选信号与控制组分开的比例。
- 实际影响半径超过风险卡预测的事故数量。
仍然可以保留 diff 大小,但把它当诊断指标。变更不断变大可能说明边界含糊、范围失控或审查过载。不要把它变成安全分数。应当回看自己的发布历史,判断大型生成变更是否真的与漏检缺陷相关,再调整阅读地图和审查方法。
避免六种虚假安全感
“AI reviewer 给了 5/5”
自动 reviewer 能发现模式并总结 diff,但可能与生成者共享盲点、缺少业务上下文,或看不到未记录的消费方。把它当证据收集器,不要当独立验收者。
“CI 全绿”
CI 只能证明已有检查在测试环境通过。它无法自动证明测试代表真实客户行为、生产权限、混合版本、真实数据形态、供应商故障或延迟任务。风险卡每一个高分都应对应具体证据。
“我们已经把大 PR 拆成五个”
只有每一块都完整、兼容、可独立测试且能按顺序安全部署时,拆分才有帮助。如果一组 PR 只有放在一起才能理解,它可能增加审查开销,却仍保留一次大规模发布事件。
“这只是配置”
配置也能扩大公开访问、路由全部流量、关闭验证、改变保留规则或暴露密钥。判断实际效果,不要看文件后缀或行数。
“随时 revert 就行”
Revert 是源代码操作。真正恢复可能还需要修数据、通知客户、吊销凭证、对账、清缓存或向前修复。必须明确列出残留副作用。
“Canary 通过了,所以安全”
Canary 可能没有覆盖稀有账号类型、延迟续费、大数据集、特定地区或权限组合。只有 cohort 和观察窗口真正触发了风险机制,才应扩大。有些故障更适合 shadow traffic、合成探针、契约测试或专门的 migration 演练,而不是百分比 rollout。
运行一次 60 分钟影响半径演练
从 staging 中选择一项待发布的 AI 生成变更。不要故意破坏生产,也不要使用客户数据。
0–10 分钟:说明影响。由人类负责人写下商业原因、受影响的用户承诺和最可信的严重缺陷。列出持久写入、外部调用、凭证、migration、队列、开关与定时任务。 10–20 分钟:填写风险卡。给六个维度打分并附证据。团队意见不一致时,先采用更高分,直到测试能解决不确定性。指出最可能让风险标签失真的那一个维度。 20–35 分钟:找两个反例。找出一个体量大但可控的部分,以及一处体量小但后果严重的改动。验证审查方案确实把更多精力给了后者的后果,同时也让前者变得可理解。 35–45 分钟:演练暴露控制。给一个合成身份或员工账号打开功能,确认能识别候选版本。测试一条 happy path 和一条 failure path。关闭功能或移除候选流量,过程中不能让原编码 Agent 临时发明处理办法。 45–55 分钟:检查残留状态。停止后检查数据库、队列、外部 sandbox、缓存和日志。记录哪些状态没有恢复,并对合成状态运行预先写好的 reconciliation 或 restore 步骤。 55–60 分钟:做决定。三选一:进入下一个受限 cohort、因缺少证据暂停、或重构设计以降低某项分数。给每个未知项分配负责人和截止时间。把风险卡留在 PR 中,发布后再用实际结果回填。另一名成员能够解释后果、找到候选信号、执行停止动作并核对残留状态,才算通过。如果安全依赖原 Agent session 或作者在线,演练失败。
明确适用范围与边界
这套方法适合普通 SaaS 功能、内部工具、内容工作流和 AI 构建的 Web 产品,前提是发布能分组并被观测。Solo founder 也可以用一张表、发布日志、一个 feature flag 和一名可信 reviewer 执行。重点是有纪律的判断,不是企业级仪式。
不要用这张矩阵为医疗设备、工业控制、关键基础设施、受监管资格判断、大额资金流动或其他安全关键系统辩护。通用 checklist 给出的 low 不能覆盖法律义务、验证过的工程流程或合格领域审查。
有些产品无法按用户比例 canary。Schema migration 会触及共享存储;移动端旧版本可能保留几个月;隐私政策改变的是法律承诺;加密密钥轮换可能是全局事件。此时应通过兼容性、shadow 验证、分阶段资源、dual read/write、离线演练、备份或单独审批边界来缩小影响,而不是假装存在一个 1% 开关。
当工作本身具有天然独立边界时,小 PR 仍然很有价值。一个聚焦的 bug fix 往往比一组互不相关的修复更容易读懂和回滚。本文不是鼓励不可读的输出,而是阻止团队把整洁 diff 误认为安全发布。
使用创始人上线闸门
在批准下一项 AI 生成变更前,必须能清楚回答:
- 什么用户或商业结果使这项变更值得做?
- 哪些内容是生成、机械变化或移动,哪些路径需要人类判断?
- 逻辑变更是否完整、连贯,不需要从人为拆分的 stack 中重新拼接?
- 缺陷在发现和控制前,最大可信影响半径是什么?
- 风险卡是否用证据覆盖用户范围、权限、状态、可逆性、发现能力与耦合?
- 哪些短短几行承载了不成比例的后果?
- 哪些大段代码只提高理解成本,并没有提高失败成本?
- 暴露是否能从合成、内部或具名试用用户开始?
- 候选结果能否按版本或 cohort 与控制组分开?
- 哪个明确信号会停止 rollout,谁负责,多久能行动?
- 客户接触功能前,是否实际执行过停止动作?
- 代码回滚后,还会留下哪些数据、消息、支付、缓存或外部效果?
- 混合版本和延迟任务路径是否兼容?
- 独立 reviewer 是否检查了风险最高的边界,而不是平均扫过每一行?
- 后果高而控制弱时,团队是否真的会暂停或重构?
代码仍要可理解,暴露范围要更小,最深的审查要放在产品真正可能伤害用户的位置,而不是放在 diff 最长的位置。
参考资料
- Rootly,为什么取消小 PR 规则,触发本文分析的第一方运营复盘。
- Google SRE Workbook,Canarying Releases,关于部分部署、控制组比较、版本级信号、回滚和 error budget 暴露。
- GitHub Docs,Deployments and Environments,关于指定 reviewer、防止自审、分支限制、environment secret 与自定义部署保护。
- AWS Well-Architected Framework,Employ Safe Deployment Strategies,关于 feature flag、canary、流量切分、蓝绿部署、监控和发布后测试。
- Cloudflare Workers Docs,Gradual Deployments,关于流量切分、版本观测、version skew、affinity 与 override。
- Cloudflare Workers Docs,Rollbacks,关于代码版本恢复,以及资源和数据变化造成的回滚限制。
- Prisma Documentation,Expand-and-Contract Migrations,关于兼容 schema 演进、生产数据副本测试、备份与 migration 监控。
- DORA,Software Delivery Performance Metrics,关于交付吞吐、change fail rate、failed deployment recovery time 与 deployment rework rate。
- Martin Fowler,Feature Toggles,关于开关生命周期、决策点、canary cohort 与运营取舍的详细分类。