跳到主要内容

评审 Agent PR 是一项不同的工作,而不是更快捷的工作

· 阅读需 11 分钟
Tian Pan
Software Engineer

一位资深工程师打开了一个由 Agent 编写的 PR。Diff 非常整洁。测试通过了。命名规范一致。他们大致扫了一眼,点了个赞,然后合并。两个月后,另一位资深工程师正在重写那个模块,因为该模块引入的抽象在三个调用点悄悄泄露了状态,而测试套件从未发现这一点,因为它只断言了代码在做什么,而不是规范(Spec)的要求。

这种模式是 2026 年代码审查(Code Review)中占主导地位的失败模式。那些适用于人类编写 PR 的审查直觉——探究作者的意图、寻找他们没想到的 Bug、检查测试是否反映了设计——在 Agent PR 上失效了,因为 Bug 聚集在不同的地方,且审查者看到的产物不再是真正重要的产物。

数据支持这一直觉。CodeRabbit 在 2025 年 12 月对 470 个 GitHub PR 的分析发现,AI 协作编写的代码产生的问题大约是人类编写代码的 1.7 倍,其中逻辑和正确性错误是 1.75 倍,安全发现是 1.57 倍,算法和业务逻辑错误是人类的 2.25 倍。严重问题增加了 1.4 倍,重大问题增加了 1.7 倍。Diff 读起来很流畅,而这种流畅性恰恰就是问题所在。

Bug 特征发生了翻转

人类工程师引入 Bug 源于不完整的心理模型。修复通常是补上缺失的分支、考虑未周全的边界情况、未转换的单位,或者是作者未曾预料到的竞态条件。经过多年人类 PR 磨炼的审查者对这些有着“第六感”——“如果这个列表为空会发生什么?”、“你考虑时区了吗?”、“这是线程安全的吗?”——这些问题之所以奏效,是因为它们直击作者理解中的空白。

Agent 引入 Bug 的来源则完全不同:误读 Prompt、幻觉产生的 API,以及自负且错误的抽象选择。Bug 不是缺失的分支——而是一个连贯的、看起来合情合理的错误实现。Agent 调用了 response.json().getField("name"),因为这种模式出现在它的训练数据中,即使所使用的库返回的是类型化对象。Agent 提取出了一个“看起来可复用”的辅助函数,却耦合了三个本应保持独立的关注点。Agent 编写了一个断言代码行为而非规范要求的测试,因为同一个模型同时生成了两者,它们有着共同的盲点。

CodeRabbit 对此的数据非常引人注目。并发控制问题在 Agent 代码中出现的频率高出 2.29 倍。XSS 漏洞出现的频率高出 2.74 倍。过度的 I/O 操作则高出近 8 倍。这些不是人类审查者通过阅读 Diff 就能训练出的找 Bug 能力——它们是需要不同阅读策略的系统性模式。

审查者看到的 vs 真正重要的

人类 PR 的审查者通过 Diff,结合提交信息、PR 描述和周围的代码来推断意图。意图存在于作者的脑海中,但 Diff 是该意图的高保真信号,因为作者必须自觉地、逐行地进行转换。

Agent PR 的审查者看着 Diff,并试图从……同样的 Diff 中推断意图。实际的意图存在于 Prompt 中——即工程师输入到 Claude Code、Cursor 或 Devin 中的规范——而该 Prompt 几乎从未附加到 PR 中。审查者正在阅读实现,并试图重建它所实现的规范,这完全是本末倒置。

这就是为什么流畅的 Agent 代码如此危险。对于人类作者,流畅的代码是作者理解问题的证据。对于 Agent,流畅的代码只是模型生成了连贯文本的证据;无论模型是否理解问题,它写出来的代码都是一个样。审查者所信任的视觉信号——“这看起来像是懂行的人写的”——已经与其追踪的底层属性脱节了。

三种产物,而非一种

必须确立的准则是将 Agent PR 视为三个独立的产物:

  1. Prompt —— Diff 应该实现的规范。
  2. Diff —— 具体实现。
  3. 测试计划(Test plan) —— Agent 声称涵盖的行为。

独立审查每一个产物只是工作的一半。另一半是发现任何两两之间的差距:

  • Prompt vs. Diff:Agent 解决的是你真正要求的问题,还是一个相关的问题?微妙的范围偏移很常见。你要求“验证电子邮件格式”,结果得到了一个完整的邮件可送达性检查,每次请求都会访问外部 API。
  • Diff vs. 测试计划:测试计划是否真正测试了 Diff 所声称的行为?同义反复的测试—— assertEqual(format(x), format(x)) ——不需要证明任何东西就能通过。由编写实现的同一个 Agent 编写的测试会共享盲点;两者都编码了同样的误解。
  • Prompt vs. 测试计划:测试是否涵盖了规范的要求,还是仅仅涵盖了实现碰巧完成的功能?规范要求“处理空输入”。实现却在空输入时崩溃。测试只运行了正常路径(Happy path)。这三个产物彼此达成一致,却与现实相悖。

如果你团队的审查工具只显示 Diff(大多数工具都是如此),那么审查者在结构上就无法完成这项工作。将 Prompt 作为 PR 描述发布,将 Agent 的测试计划作为独立文件附加,并同时审查这三者,这是在确立准则之前必须实现的流程变革。

“为什么 Agent 没有提问?”

审查 Agent PR 时最有用的一级启发式方法:一个自信、流畅的 diff,但在对话历史中没有任何澄清性问题,这是一个危险信号。真实的规范(specifications)都存在模糊性。如果让一名资深工程师“为用户查询添加缓存”,他会问:用哪个缓存?失效策略是什么?TTL(过期时间)多久?租户间隔离怎么处理?现有的缓存层工具合适吗,还是我们需要一个新的?

当 Agent 没有问这些问题时,它其实是直接选了一个答案。这个答案就在 diff 中,但工程师原本会提出的备选方案却没有体现。审查者的工作是重新构建 Agent 本该提出的问题,并验证 diff 是否符合团队会给出的答案。

这可以总结为一个人类很少产生的故障模式清单:

  • 幻觉 API:对于每一个新引入的库或方法调用,都要验证该方法是否存在于 package.jsonrequirements.txt 中指定的版本里。方法签名必须完全一致。Agent 会根据训练数据合成看似合理的 API;如果你的 IDE 对类型检查比较宽松,这些调用能在 IDE 中编译通过,但在运行时就会崩溃。
  • 过度重构:Agent 喜欢“改进”变更附近的某些代码。一个两行的 Bug 修复可能会变成一个涉及 30 个文件的 PR,包含了统一的代码风格修改、变量重命名以及提取了一个无关的抽象。虽然 diff 在技术上是正确的,但影响范围(blast radius)是错的;审查者的工作是缩减范围,而不仅仅是验证正确性。
  • 套套逻辑测试(Tautological tests):断言内容只是镜像了实现细节而非规范。常见形式:assert sort(input) == [item for item in sorted_using_same_algorithm(input)]。这种测试永远会通过,但证明不了任何东西。
  • 迷之自信的错误抽象:Agent 抽离了一个基类、一个上下文管理器或一个通用助手函数。它看起来很整洁,但它所抽象的三个调用点其实有着显著不同的不变性(invariants),而这些差异被抽象层掩盖了。几个月后,当第四个调用点需要略有不同的行为时,整个抽象层都必须拆除。

没人察觉到的成本维度

Stripe 内部的 “minions” Agent 现在每周提交大约 1,300 个 PR。Intercom 报告称其 93% 的 PR 是由 Agent 驱动的,其中 19% 的 PR 在没有人类审查的情况下直接合并。GitHub 的 Octoverse 报告指出,约 41% 的新代码是 AI 辅助生成的。行业数据表明,重度 AI 使用者人均提交的 PR 数量增加了 98%,而每个 PR 的审查时间却激增了 91% —— 且交付速度并无提升。

最后一个数字才是重点。如果没有配套的成本项,所谓“Agent 编写了我们 70% 的代码”这种效率主张就毫无意义。这个成本项是:“审查这些代码所花费的工程师工时比以前增加了百分之多少。”大多数组织并没有衡量第二个数字。他们衡量 PR 吞吐量、发布率和人均代码行数;他们不衡量审查者在每个 PR 上投入的深度,尤其不衡量六个月后当那个“迷之自信的错误抽象”不得不拆除时,资深工程师的重写成本。

诚实的核算是,按要求的深度审查 Agent PR 比审查人类 PR 要 更慢,因为审查者必须:

  1. 根据 diff 重新构建 Prompt。
  2. 对照实际的库文档交叉检查每一个 API 调用。
  3. 独立审计测试计划,而不是盲目相信“测试通过”就意味着“行为正确”。
  4. 抵制人类不会产生的范围蔓延(scope creep)。
  5. 探究 Agent 默默做出的抽象选择。

如果团队像对待人类 PR 一样对待这项工作,并分配相同的预算时间,抽象质量就会衰减。如果团队诚实地评估审查工作量,吞吐量的数据就会大打折扣。没有第三种选择 —— 高质量的审查成本就是这么高。

分级审查与自动批准的局限性

一些团队正通过分级审查系统来应对:自动检查幻觉 API 和安全反模式;由另一个 AI 审查者对每个 PR 进行结构化评分;人类的判断力则留给架构、范围和抽象。Cloudflare 和 Microsoft 已经发布了这种方案的变体 —— 多 Agent 审查系统,由专门的 Agent 负责安全、性能和代码质量,并由一个 Agent 协调将发现的问题汇总到一条评论中。

这有所帮助,但并不能消除瓶颈。AI 审查者能做好的工作,正是那些失效模式局部化且符合模式匹配的工作。而仍然需要人类的工作 —— 这个抽象是否属于这里?这是否属于范围蔓延?这个测试是否反映了规范? —— 则是最难扩展的工作。这也是那些错误代价最高的工作,代价往往在六个月后显现,而那时编写代码的 Agent 可能已经换了模型版本,当初的 Prompt 也不复存在。

19% 的 PR 自动批准(Intercom 的数据)仅在变更类型确实属于低风险的情况下才有效 —— 例如格式修复、依赖项升级、带有强契约测试的明确界限的重构。将自动批准推向模糊地带是在透支未来的审查预算。其利率就是“资深工程师重写”,而且会产生复利。

瓶颈并未消失

AI 编程代理厂商在过去两年里一直承诺要消除代码审查瓶颈。瓶颈依然存在。它转移了,但并未消失,其根本原因是结构性的:代码审查的工作量并不取决于代码是如何被编写出来的。它取决于代码本身——它改变了什么,什么依赖于它,以及它如何与周围系统交互。智能体改变了在生成代码以及规模扩展的速度。它们并没有改变“决定代码是否应当合并”这一核心工作。

那些悄悄取得成功的团队,并不是拥有最花哨 AI 审查工具的团队。而是那些将 prompt 视为一等公民(first-class artifact)、诚实地评估审查预算,并训练审查者去寻找那些在人类编写的代码中不常出现的失效模式的团队。而那些悄悄走向失败的团队,则是在以人类 PR 的速度批准那些表达流畅的 diff,并不断积累那种隐蔽且错误的抽象——这些问题在任何仪表盘上都不会显现,直到某位资深工程师不得不花上一周时间将其拆除。

审查者的直觉才是核心资产。现在的任务是针对新的 Bug 特征重新校准这种直觉,而不是让它退休。

References:Let's stay in touch and Follow me for more thoughts and updates