当智能体(agent)以这样的规模产出代码时,你要如何做代码审查?在 Claude Code 团队,当我们具备了较高的测试覆盖率和较深入的审查能力之后,开始朝着"在不增加回退和故障次数的前提下,所需要的最少人工审查时间"这一目标来优化。
我们之前说过,Claude Code 自身的代码中,大约 90% 是由 Claude 编写的。那么,面对我们产生的这种代码量,我们究竟是如何做审查的?真的还有人读代码吗?一旦出问题,又由谁来兜底?
本文将介绍 Claude Code 团队的代码审查流程,以及它是如何一步步演进到今天的。从六月到九月,Claude Code 代码库的合并拉取请求(PR)数量翻了一倍多,而其中不得不回退的比例下降了超过 40%。
我们并没有取消审查。但我们确实把"读代码"这件事的大部分交由机器去做,把人的时间和注意力留给最关键的环节,并投入了大量精力,让"撤销错误"这件事变得既快又轻松。
重新审视代码审查的目的
当智能体开始写代码,变更会以惊人的速度增加。在 Anthropic 的单体仓库中,每天落库的变更数量,从今年五月的约 2,500 条增长到了九月后的三万余条。
Claude Code 位于独立的代码仓库,与单体仓库分离,但也承受着同样的压力。当交付节奏如此之快时,逐行的人工代码审查即便不是不可能,也极其困难。
代码审查承担着两件事:
- 在变更发布前发现并修复问题;
- 在团队内部建立共享的背景认知和对代码库的理解。
本文主要聚焦在第一件事——发现并修复问题——但我们会在文末再回到第二件事。
我们认为,"是否有人读过这段代码?"是一个粗糙的代理指标,它并不等同于"这个变更可能会出什么问题,以及哪一类检查——自动化的还是人工的——才是发现它的正确手段?"。
把这个问题真正问出来,也改变了审查发生的时机。以前,审查是流程末端的一道闸门:写代码,开 PR,等同事看。现在,审查变成了一项持续进行的工作,更像边写边检查的拼写校对。大多数变更在人类被请来审阅之前,已经至少被 Claude 自己审过并修改过一轮。这能拦下大部分常规错误,从而把人类宝贵的注意力留给更高层面的审视。
稀缺资源:人的时间与注意力
我们希望把人类的时间和注意力留给只有人类才能解决的问题,并让自动化的检查去覆盖剩下的部分。以我们目前的变更节奏,仍然有大量工作需要人来完成,团队几乎每天都会遇到新的、棘手的挑战。
这里所说的"人的时间"涵盖审查本身的两个维度:人花在审查上的时间,以及人花在修复糟糕代码造成的后果上的时间。如果只削减了前者,时间却以另一种形式从后者冒了出来,那并没有真正节省时间。
因此,我们的目标是:Claude Code 各个仓库(CLI、桌面与 Web 应用、移动端应用)中的绝大多数 PR,至多只需要一位人类把关——这位把关者也可以是作者本人——同时回退率和故障率都不会上升。为了衡量人类所花的时间,我们追踪每个 PR 上的人工批准次数(中位数与第 95 百分位)、人工评论数量,以及 PR 在人这一侧等待的时间。回退率与故障率是衡量成败的底线:如果它们上升,那就说明我们并没有真正节省时间,只是把时间挪到了别处。
一个变更的生命周期
一次典型的变更,从工程师的笔记本(或 Slack 中的一个 Claude 会话)出发,要穿过多层代码审查。
%%IMG1%%
一个典型的 Claude Code 变更,从作者本机一路走到用户手中。
逐层展开
%%IMG2%%
六层检查,底下还有一层"回滚"托底。
1. 在请别人看之前,先把工作"验"过一遍
如今,大多数审查是在 PR 出现之前完成的。我们给 Claude 一个可执行的方式来确认结果——比如跑构建、跑测试,或者拿一张截图与设计稿对比——并要求它把输出结果展示出来,而不是简单地说"做完了"。接下来,一个子智能体(subagent)会以全新的上下文再审一遍 diff。这两个习惯都来自我们的 最佳实践指南。
在开 PR 之前,我们中的许多人还会跑一些内部技能(skill):一个用来排查缺陷,一个用来精简 diff,还有一个用来端到端核对行为是否符合预期。涉及 UI 的变更还会对照设计规范做一次检查。
Claude Code 的创始人 Boris Cherny 曾指出,给 Claude 一种验证自己产出结果的方法,可能是最重要的一件事。他估计它能让最终结果好上两到三倍,并写道:"验证的方式因领域而异。它可能简单到只是跑一条 bash 命令,也可能是跑一个测试套件,或在浏览器或手机模拟器里把应用测一遍。"
当自动审查器反复标同一类问题时,我们会回到源头去修。 具体的做法是修改技能(skill)、补充 lint 规则,或者更新类似下面这些说明性文件:
CLAUDE.md告诉 Claude 项目本身的情况:技术栈、规范、目标与非目标。每一次审查都会加载它,所以在一个大型代码库里,我们会把CLAUDE.md写得简短,并在其中指向其他文档。审查器也会标出违反其中规范的代码,以及会让其中某些条目变得过时的变更。REVIEW.md由代码负责人(code owner)撰写,告诉审查器在他们负责的那部分代码中什么才是重要的。我们会另外检查审查器是否真的按照它执行。写得好的REVIEW.md都是简短的:先描述在该仓库里"失败"长什么样(文档类仓库是"它撒谎",配置类仓库是"它错误地路由了"),再对吹毛求疵的细节点设上限,列出可以跳过的路径,并要求审查器给出文件和行号作为证据,而不是仅凭命名瞎猜。最后,它还要求审查器在总结里先给出一个数量统计,并明确说明如果没有需要修复的就直说。
2. 每个 PR 都有一轮 AI 审查
在任何人看到之前,每个 PR 都会先经过一轮 Claude 的审查。它会对照整个仓库以及 PR 自己声明的目标来阅读 diff,并自问:这个变更是否解决了它要解决的问题?是否契合整个系统?是否会破坏其他地方?
在 bug 修复中,它会去追根因。公开发布的版本 Code Review for Claude Code 目前已在 Team 与 Enterprise 套餐中正式上线,本地的精简版可以通过 /code-review 指令运行。
在我们上线研究预览版时,内部 PR 中获得实质性审查评论的比例从 16% 提升到了 54%。超过 1,000 行的 PR 大多都会被查出问题,而大多数较小的 PR 则基本干净地通过。管理员可以按仓库把审查强度设为 Quick(快速)、Standard(标准)或 Deep(深度)。在那些"漏掉一个 bug 的代价高于多花一些审查时间"的场景下,Deep 模式是值得的。
审查发现会被其他智能体先交叉验证,然后再交给人去审。 多个智能体会同时查找缺陷;之后,再由另一组智能体对每条发现进行投票,只有在足够多的智能体一致认为它是真问题时,这条发现才会被贴出来。仅涉及风格、诊断信息或清理类的发现会被直接丢掉。我们先在内部 PR 上对这几条过滤规则做了 A/B 测试,确认有效后才保留下来。剩下的内容会以行内评论的形式按严重程度排序呈现,每条都会打上 Important(重要)、Nit(瑕疵)或 Pre-existing(早已存在)的标签,这样一来,那些并非本次 PR 引入的问题就不会被错算到作者头上。
每一条审查发现都必须被处理。 你要么修复它,要么给出一条理由并关闭这条评论线程。很多时候,一个智能体会在夜间接手修复,第二天作者回来时,看到的 PR 已经又跑过一轮审查了。
3. 安全审查可以一票否决
安全审查同样有自己独立的自动审查。在 bug 评审或安全审查中发现的任何问题,只要还挂着未处理,PR 就不能合并。你要么修复它,要么用一句简短的理由关闭这条线程——这正是清理误报的方式。
如果后续一次提交解决了问题,这条发现会自动消除。你也可以用开源的安全审查 GitHub Action,或 /security-review 指令来配置同样的能力。具体的接入方式详见在 Claude Code 中配置自动安全审查。
4. 一票否决式的自动化检查
这是常规的那一套:lint、类型检查、每个平台上的测试,以及一次构建。(关于如何为这种规模的代码量扩展 CI,我们之前写过一篇,详见这里。)一个典型的 CLI PR,在任何人看到它之前,可能要跑几十项检查。PR 模板会要求填写:这次变更是怎么测的,以及如何回退。Claude 可以代为填写,但最终由发起这次变更的人来签字确认。