Newshot

我们不逐行阅读,却把 AI 代码的审查量提升到 4 倍

Translation(model translation, not the source's own text)

你需要读完 AI 生成的每一行代码,才能信任它吗?

不一定。相反,要检查五件事:改动背后的意图、它的验收标准、它不能破坏的不变量、过程中做出的决策,以及它能正常工作的证据。

在 Aviator,这一转变让同样的九名工程师合并了 4 倍多的 pull request,合并时间中位数从 2.1 天降到 3.4 小时,回滚减少了 40%。每个 PR 仍然由人签字确认。改变的是这个人读什么。

“决策需要人来做,而 diff 是做决策最糟糕的地方。”

我们是通过整理自己的评审评论得到这个洞察的。评审者在 PR 上写的内容,大多要么是他之前已经写过的规则,要么是一个决策。规则应该每次都由机器检查。决策需要人来做,而 diff 是做决策最糟糕的地方。

问题:代码评审无法随 AI 一起扩展

我们的代码从“人写、AI 辅助”翻转成了“AI 生成、人辅助”。每周合并的 PR 从大约 100 个增加到 400 多个。我们由 AI 生成的 PR 行数中位数达到 640 行,远超 400 行——这被普遍认为是缺陷检出率明显下降的界限。

捕捉 bug 从来就不是代码评审的主要目的。在 Microsoft 2013 年的研究(Bacchelli & Bird)中,只有 14% 的评审评论与缺陷有关。评审是工程师共享知识、让各自对系统的心智模型保持最新的方式,而这才是值得保护的部分。当 agent 写下大部分代码时,这也是风险最大的部分。

“捕捉 bug 从来就不是代码评审的主要目的。评审是工程师共享知识、让各自对系统的心智模型保持最新的方式,而这才是值得保护的部分。”

自从我提出代码评审已死,我听到最常见的反驳是:“所以你们就不评审了?”不。我们停止的是评审 diff。

那么,什么没起作用?

  • 一个 AI 评审器。在我自己的一个 PR 上,它开出了 18 条讨论串中的 16 条:魔法数字、用数组索引作 React key、一个运行过久的组件。只有一条讨论串抓到了一个真实的竞态条件。真正重要的两条评论——都来自队友的设计决策——被琐碎的意见淹没了。
  • 四小时的评审 SLA。我们没法增加评审人,于是加了一条规则。首次评审变快了,批准也变得更空洞,因为评审者为了赶时间匆匆扫过,而他们自己的工作却停滞了。
  • 一个按我们的约定调过的自我评审 skill。它发现的问题比通用机器人好得多。但它仍然是在代码写完之后才去读 diff,而这场交互中最有用的部分——它争论了什么、我们决定了什么——死在了聊天窗口里。

这三者都在试图更好地读 diff。但 diff 恰恰是代码评审中最不重要的部分。它只显示改了什么,从不显示为什么。

为了看清评审里实际都有什么,我回头翻了一个我在 2025 年评审过的 PR。它有 14 条讨论串。八条来自机器人,只抓到一个真实 bug。我六条评论中的三条是我已经在别的 PR 上写过的规则,比如“Use GraphQLRetryableException so Celery retries on it.”。只有两条是真正的决策,比如“No comments extracted:我们要不要在 PR 上告诉用户?”

信息图:九名工程师停止阅读 AI 生成的 diff 之后发生了什么。
信息图:九名工程师停止阅读 AI 生成的 diff 之后发生了什么。

什么起作用了:验证意图,而不是行

代码评审过去同时承担好几项工作:捕捉 bug、执行团队约定、敲定设计决策,以及让每个人对系统的理解保持最新。我们把这些工作拆开,给每一项找了个更好的归宿。

在 PR 存在之前先争论。我们的评审 agent 会盘问作者的 agent——它运行在不同的模型上——并记下每一处分歧。在最近的一个 PR 上,两个 agent 提出了四处分歧,其中三处带着明确理由达成了结论。留给人的只有一处命名决定。

我们不逐行阅读,也能审查多 4 倍的 AI 代码

捕获意图与验收标准。这不是作为前置规格,而是从与智能体的编码会话中捕获。每当工程师纠正智能体或回答它的问题时,我们就创建一条标准。过去,会话结束时我们会把这些丢掉。意图回答我们为什么要做这次变更;验收标准回答它应该如何表现。没有标准的意图无法检查,没有意图的标准无法判断。

“意图回答我们为什么要做这次变更;验收标准回答它应该如何表现。没有标准的意图无法检查,没有意图的标准无法判断。”

把重复出现的评论固化为不变量。我们分三轮挖掘了一年的审查历史:剔除噪声(机器人摘要、只有“LGTM”的评论),把每条评论归类为规则、建议、一次性修复或问题,然后合并重复项。11,400 条评论变成了 212 条候选规则和 64 条已批准的不变量。每条都有范围、验证方法、来源和负责人。

以“每次配置变更都写入一条审计日志条目,且仅在确实发生变化时写入”为例。它覆盖写入配置的 GraphQL mutation 和 API handler,通过一次预览运行来验证,该运行保存两次并读取审计日志;它从 17 个 PR 的 23 个审查讨论串中挖掘而来,归平台团队所有。

让模型在每个 PR 上检查每条不变量很慢,而且无法完全重复,因此在可能的情况下,智能体会把不变量编译成 ast-grep 规则,让这些规则在模型旁边以影子模式运行,直到两者结果一致。我们曾在九个 PR 上留下的评论“加个超时,这挂住了一个 worker”,现在是一条八行规则。十九条不变量以确定性方式运行,耗时 0.3 秒。

用证据证明每一条标准。每条标准都会变成一个场景。智能体启动一个预览环境,像用户一样操作它,并记录截图、请求和日志。对于审计日志不变量,它会保存一个设置,确认新增一条日志条目;在没有任何变化的情况下再次保存,并确认仍然只有一条。

后半部分正是审查者在阅读 diff 时永远不会检查的内容。并非每条标准都需要浏览器:API 契约由记录下来的请求和响应证明,代码规则由 ast-grep 匹配或文件与行号引用证明。选择能解决问题的最便宜证明。CI 检查通过只能说明你想到的测试通过了。

对决策进行辩论。决策来自

The translation is machine-generated and individual terms may be off. Nothing is rewritten or cut; the original is authoritative.

Published by HN AI
This site only summarises and aggregates; copyright stays with the original author. Headlines and summaries follow the source — where they differ, the original wins.
Read the original ↗