
Aviator分享AI代码审查法:不逐行阅读,合并效率提升4倍
来源标题:How we review 4x more AI code without reading every line
Aviator团队通过改变代码审查方式,在不逐行阅读AI生成代码的情况下,让9名工程师合并的PR数量提升4倍,合并中位时间从2.1天降至3.4小时,回滚率下降40%。其方法是将审查重点转向五项检查:变更意图、验收标准、不可破坏的不变量、过程中的决策以及可运行的证据。人工仍对每个PR签字确认,但审查内容发生了改变。
以下正文由 AI 翻译自 The New Stack(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
要信任 AI 生成的代码,你需要逐行阅读吗? 未必。你可以改为核查五件事:变更背后的意图、它的验收标准、它不能破坏的不变量、过程中做出的决策,以及它确实有效的证据。 在 Aviator,这一转变让同样的九名工程师合并了 4 倍多的 pull request,将合并中位时间从 2.1 天缩短到 3.4 小时,并将回滚减少了 40%。每个 PR 仍由人签字确认。改变的是这个人读什么。 “决策需要人来定,而 diff 是做决策最糟糕的地方。” 我们是通过对自己 review 评论进行分类得到这一洞见的。reviewer 在 PR 上写的大部分内容,要么是他们以前写过的规则,要么是一个决策。规则应当每次都由机器检查。决策需要人来定,而 diff 是做决策最糟糕的地方。
问题:代码 review 跟不上 AI 的规模
我们的代码从“人写、AI 辅助”变成了“AI 生成、人辅助”。每周合并的 PR 从大约 100 个增加到 400 多个。AI 生成的 PR 中位数达到 640 行,远超 400 行——400 行被普遍认为是 bug 检出率开始下滑的界限。 捕捉 bug 从来就不是代码 review 的主要目的。在 Microsoft 2013 年的研究(Bacchelli & Bird)中,只有 14% 的 review 评论与缺陷有关。Review 是工程师分享知识、保持对系统心智模型更新的方式,而这才是值得保护的部分。当 agent 编写大部分代码时,这也是风险最大的部分。 “捕捉 bug 从来就不是代码 review 的主要目的。Review 是工程师分享知识、保持对系统心智模型更新的方式,而这才是值得保护的部分。” 自从我提出代码 review 已死以来,听到最多的反对是:“所以你们就不 review 了?”不。我们不再 review diff。
那么,哪些做法没有奏效?
- 一个 AI reviewer。在我自己的一个 PR 上,它在 18 个 thread 中开了 16 个:魔法数字、用数组索引做 React key、一个运行过长的组件。只有一个 thread 抓到了一个真正的竞态条件。真正重要的两条评论——都来自队友的设计决策——被淹没在细枝末节之下。
- 四小时 review SLA。我们无法增加 reviewer,于是加了一条规则。首次 review 变快了,批准却变得更空洞,因为 reviewer 为了赶时钟草草浏览,自己的工作也被耽误了。
- 一个按我们约定调优的 self-review 技能。它的发现远比通用 bot 好。但它仍然是在代码写完之后读 diff,而交流中最有用的部分——它争论了什么、我们决定了什么——死在了聊天窗口里。 这三种做法都试图更好地读 diff。但 diff 本来就是代码 review 中最不重要的部分。它展示改了什么,从不展示为什么。 为了看清 review 实际包含什么,我回溯了 2025 年我 review 过的一个 PR。它有 14 个 thread。八个来自 bot,抓到了一个真正的 bug。我的六条评论中有三条是我已经在其他 PR 上写过的规则,比如“使用 GraphQLRetryableException,这样 Celery 会重试”。只有两条是真正的决策,比如“未提取到评论:要不要在 PR 上告诉用户?”
哪些做法奏效了:核查意图,而非行数
代码 review 过去同时承担好几项工作:捕捉 bug、执行团队约定、敲定设计决策、让每个人对系统的理解保持更新。我们把这些工作拆开,给每一项找了更好的归宿。 在 PR 存在之前先争论。我们的 review agent 用另一个模型对作者的 agent 进行交叉质询,并记录下每一处分歧。在最近的一个 PR 上,agent 提出了四处分歧,其中三处以陈述的理由解决。留给人的只剩一处命名决定。 捕获意图和验收标准。不是作为前置 spec,而是从与 agent 的编码会话中捕获。每当工程师纠正 agent 或回答它的问题时,我们就创建一条标准。过去会话结束时我们把这些丢弃了。意图回答我们为什么要做这个变更;验收标准回答它应当如何表现。没有标准的意图无法核查,没有意图的标准无法判断。 “意图回答我们为什么要做这个变更;验收标准回答它应当如何表现。没有标准的意图无法核查,没有意图的标准无法判断。” 把重复的评论固化为不变量。我们分三遍挖掘了一年的 review 历史:去掉噪音(bot 摘要、光秃秃的“LGTM”),把每条评论归类为规则、提议、一次性修复或问题,然后合并重复项。11,400 条评论变成了 212 条候选规则和 64 条获批的不变量。每条都有范围、验证方法、来源和负责人。 以“每次配置变更都写入一条审计日志记录,且仅在确有变更时”为例。它覆盖写入配置的 GraphQL mutation 和 API handler,通过一次预览运行来验证——保存两次并读取审计日志——来自 17 个 PR 的 23 个 review thread,归属平台团队。 让模型在每个 PR 上检查每条不变量既慢又无法完全可重复,所以在可能的情况下,agent 会把不变量编译成 ast-grep 规则,在模型旁边以 shadow 模式运行,直到两者一致。我们曾在九个 PR 上留下的一条评论——“加个超时,这拖垮了一个 worker”——现在是一条八行的规则。十九条不变量以确定性方式运行,耗时 0.3 秒。 用证据证明每条标准。每条标准变成一个场景。agent 启动一个预览环境,像用户一样操作它,并记录截图、请求和日志。对于审计日志不变量,它保存一个设置,确认新增一条日志记录,在没有任何变更的情况下再次保存,并确认仍然只有一条。 后半部分正是阅读 diff 的 reviewer 永远不会检查的。并非每条标准都需要浏览器:一个 API 契约通过记录下来的请求和响应来证明,一条代码规则通过 ast-grep 匹配或文件与行号引用来证明。选择能解决问题的最便宜的证明。CI 检查变绿只能说明你想到的测试通过了。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。