Claude Code 团队如何做代码审查
How the Claude Code team does code review
Anthropic 公开 Claude Code 团队的代码审查流程:从 6 月到 9 月,合并的 PR 数量翻倍以上,被回滚的比例下降超过 40%,同时审查并未取消,而是把大部分阅读交给机器。
我们之前说过,Claude 编写了 Claude Code 自身约 90% 的代码。那么,面对如此庞大的代码产出量,我们如何进行代码审查?现在还有人读代码吗?如果出了问题,谁来发现?
本文介绍 Claude Code 团队的代码审查流程及其演变过程。从 6 月到 9 月,Claude Code 代码库合并的拉取请求数量增加了一倍多,而需要回滚的比例下降了 40% 以上。
我们并没有取消审查。但我们确实将大部分阅读工作交给了机器,以优化人类的时间和注意力,并大力投入让撤销错误变得快速而简单。
重新思考代码审查的目的
当智能体编写代码时,变更数量会迅速增长。在 Anthropic 的 monorepo 中,每天落地的变更从今年 5 月的约 2,500 个增加到 9 月的 30,000 多个。
Claude Code 拥有独立的代码库,与 monorepo 分开,但它也面临着巨大的压力。当以如此快的速度交付时,手动逐行进行代码审查极其困难,甚至不可能。
代码审查有两个作用:
- 在发布前发现并修复问题
- 在团队中建立共享背景和代码库理解
本文主要关注发现和修复问题,但我们会在结尾回到第二个作用。
我们认为,“是否有人读过代码?”并不能精确地代表“这个变更可能出什么问题,哪种检查——自动的还是人工的——才是发现它的正确方式?”
提出这个问题也改变了审查发生的时机。以前,审查是道路尽头的关卡:编写代码,打开 PR,等待同事。
现在,审查持续进行,更像是写作时的拼写检查。大多数变更在请求人工查看之前,已经由 Claude 至少审查和修复过一次。这能发现大多数常规错误,并将团队注意力留给更高层次的问题和审查。
稀缺资源:人类的时间和注意力
我们希望将人类的时间和注意力保留给只有人类才能解决的问题,并确保自动化检查能发现其余问题。以我们目前的变更速度,人类仍有大量工作要做,我们的团队几乎每天都会遇到新的、前所未有的挑战。
人类时间涵盖审查成本的两个方面:人们花在审查上的时间,以及他们花在修复劣质代码所造成问题上的时间。如果削减前者只是把时间转移到后者,那就没有帮助。
因此,目标是 Claude Code 各代码库(CLI、桌面和 Web 应用以及移动应用)中的大多数拉取请求在合并时,最多只需一个人参与,这个人可以是作者,且回滚或事故不增加。为了衡量人类时间,我们跟踪每个 PR 的人工批准数(中位数和第 95 百分位数)、人工评论数,以及 PR 等待某人的时长。回滚率和事故率是护栏:如果它们上升,我们就没有节省人类时间,只是把它转移了。
一个变更的生命周期
一个典型的变更,从工程师的笔记本电脑(或 Slack 中的 Claude 会话)出发,经过多层代码审查。
一个变更的生命周期
一个典型的 Claude Code 变更,从作者的机器到用户
逐层解析
是层层把关,而非一道关卡
六层检查,其下还有回滚机制
1. 工作成果在其他人查看之前就已得到验证
现在大多数审查都发生在 PR 存在之前。我们给 Claude 一些可以运行的东西——比如测试、构建或与设计对比的截图——并要求它展示输出结果,而不是说它完成了。然后一个子代理用全新的上下文审查 diff。这两个习惯都来自我们的最佳实践指南。
在打开 PR 之前,我们中的许多人还会运行一些内部技能:一个查找 bug,一个简化 diff,一个端到端检查行为。UI 更改也会对照我们的设计指南进行检查。
创建 Claude Code 的 Boris Cherny 曾表示,给 Claude 一种验证其工作的方法可能是获得好结果最重要的事情。他估计这能让最终结果好上两到三倍,并写道:“验证在每个领域看起来都不同。它可能简单到运行一个 bash 命令,或运行一个测试套件,或在浏览器或手机模拟器中测试应用。”
当自动审查器不断标记同一件事时,我们从源头修复它:在技能中、用 lint 规则,或更新指导性文件,例如:
CLAUDE.md告诉 Claude 项目是什么:技术栈、约定、目标和非目标。每次审查都会加载它,所以在大型代码库中我们保持它简短,并从那里指向其他文档。审查器还会标记违反其中约定的代码,以及使其中某一行过时的更改。REVIEW.md由代码所有者编写,告诉审查器他们那部分代码中什么重要。我们单独检查审查器是否真的遵循它。好的那些都很简短。它们说明该仓库中失败是什么样子(对文档来说是“它撒谎”,对配置来说是“它错误路由”),限制琐碎问题的数量,列出要跳过的路径,并要求提供文件和行号作为证据,而不是根据名称猜测。它们还要求提供以计数开头的摘要,并在没有需要修复的内容时明确说明。
2. 每个拉取请求都进行 AI 审查
每个拉取请求在有人查看之前都会得到 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 是值得的。
发现会在人类审查之前由其他代理验证。多个代理同时查找 bug。然后一个单独的组对每个发现进行投票,只有当足够多的代理同意它是真实的时,它才会被发布。仅关于风格、诊断或清理的发现会被丢弃。我们在自己的 PR 上对这些过滤器进行了 A/B 测试,然后才保留它们。剩下的内容以按严重程度排序的行内评论形式出现。每个都被标记为 Important、Nit 或 Pre-existing,这样 PR 没有引入的 bug 就不会看起来像是作者的错。
每个发现都必须得到回应。你要么修复它,要么带着理由解决该讨论串。通常智能体会在夜间接手修复,所以作者回来时会看到一个已经过另一轮处理的 PR。
3. 可阻断的安全审查
安全也有自己的自动审查。只要缺陷审查或安全审查中还有任何未解决的发现,PR 就不能合并。你要么修复它,要么用简短的理由关闭讨论串,这就是清除误报的方式。
如果后续提交修复了该问题,该发现会自动清除。你可以用开源安全审查 GitHub Action 或 /security-review 命令设置同样的机制。设置方法见Claude Code 中的自动安全审查。
4. 可阻断的自动检查
常规的那些:lint、类型检查、各平台上的测试,以及构建。(我们写过如何为这种规模扩展 CI,见此处。)一个典型的 CLI 拉取请求在任何人查看之前可能会运行数十项检查。PR 模板会询问该变更如何测试以及如何撤销。Claude 可以填写这些内容,但提出该变更的人要签字确认。
5. 按风险分级的人工批准
文档修复和自动更新器变更的风险不同,因此审查方式也不同。
| 风险 | 示例 | 人工批准 |
|---|---|---|
| 低 | 文档、文案、仅内部功能、标志位后的增量变更 | 一旦自动审查和安全检查通过,无需批准 |
| 中 | 普通产品变更,以及对敏感区域的变更,如缓存、自动更新器或系统提示词 | 一人 |
| 高 | 最高风险的代码,以及一小部分始终需要两人的路径 | 两人 |
变更决定层级,而非作者。一个分类器读取变更并选择其风险层级。第二个分类器询问这个特定变更是否需要另一个人,即使其层级表明不需要。某些路径始终需要一个人,包括所有者列为敏感的任何内容以及任何 CI 工作流文件。
只有受信任的作者才能走更轻的路径。只有仓库受信任列表上的作者才能走更轻的路径,主要是拥有该仓库的团队。其他所有人都需要第二个人批准。智能体的批准也从不计为人的批准。自动审查可以清除低风险变更,但无法填补需要人工的位置。
谁提示了该变更,谁就要对它负责。在智能体编写的 PR 上,指挥智能体的人算作所需审查者之一,就像他们自己输入了代码一样。
一次批准只覆盖一个特定提交。如果新的提交落地且系统无法为其担保,例如智能体的推送或有人手动解决的合并,则必须重新给予批准。
6. 合并队列、标志位和逐步发布
合并队列会在应用该变更的情况下针对 main 重新运行所有检查,因此两个单独通过的 PR 不会合并成损坏的 main。新行为通常先在标志位后向 Anthropic 员工发布,我们的重度使用往往会在用户之前发现回归。公开发布先进入 latest 渠道。stable 渠道随后跟进。
7. 快速检测,快速回滚
有些错误仍会漏过,所以最后一层是关于快速捕获它们。标志位无需部署即可关闭。Claude Code 有每周轮值的 on-call,事故复盘会询问哪一层本应捕获该问题。
发现糟糕的合并仍然依赖于作者和值班人员,以及回滚和事故仪表盘。我们还没有在那些数字变动时收紧审批的熔断机制;这里的工程师希望在更多代码转向零人工合并之前拥有它们。
一位同事说,放慢速度确实会降低错误率,但主要是因为你在所有事情上做得更少。我们更愿意在发现和解决问题上变得更快。
我们如何让审查者变得更好
我们的代码审查流程在循环中不断改进。
任何事故现在都成为一项评估。团队收集了过去导致事故的 PR,连同它们的修复推进和回滚,并让了解该代码的工程师确认每个 bug 及其所在位置。审查者每天针对该集合运行。
我们的事故就是评估集
由过去的事故和回滚构建,每天运行
我们通过观察人们对评论的反应来衡量噪音。如果你不介意标记大量非 bug,就很容易捕获更多 bug,所以我们需要对此进行检查。我们根据 PR 上的人如何回应来对审查者留下的每条评论进行分类:他们修复了它、说它是错的、说该行为是有意为之,或者认为它无关紧要。我们还在已知干净的 PR 上运行审查者,并统计它报告会导致某人做出有害更改的情况的频率。我们写下的优先事项是:首先捕获真正的 bug,其次减少审查轮次。
当作者是代理时,噪音的代价更高。一个人可以在几秒钟内挥手打发一个小问题。代理会修复它,这意味着又一次提交和又一轮审查。
审查必须收敛。代理作者和代理审查者可以让彼此无限期地忙碌下去。一个 CLI PR 在一夜之间经历了五十多轮审查和修复,直到其作者叫停。
当我们对审查者一直标记的内容运行 git blame 时,大约 59% 是自审查者第一轮以来就存在的代码。审查者很少发现新 bug,它每轮都在发现一些更旧的 bug。
我们自己让它变得更糟。我们已经习惯于默认运行多轮,因为每一轮都会发现新东西。这在有风险的更改上可能值得,但不是每个 PR 都值得。团队现在在召回率之外还跟踪通过所需的轮次,并改变了重新审查:
- 轮次上限。三轮之后,审查者要求作者退后一步,重新考虑方法。
- 前几轮之后仅对差异进行重新审查。
- 标记 bug 类别,以便作者修复每个实例,而不是一行。
- 不重复已发布的发现。
审查代理还会每晚对现有代码运行,帮助我们在旧 bug 出现在其他地方之前捕获它们。
收敛的审查
内部拉取请求,在收敛更改之前和之后
人类留在环中的地方
把一位资深工程师从深度工作中拉出来去捕获一个常规错误,其代价远高于自动审查。在 Anthropic,我们的工作已从阅读每个差异转变为处理机器不擅长的决策:
- 我们到底该不该做这件事?方向、品味和范围。有一个团队宣称其审查瓶颈已解决,但仍然对来自团队外部的变更保留人工审查,因此会有人问“我们到底该不该做这件事?”
- 高风险代码,例如计费、自动更新器和 CI 工作流。
- 架构,会为他人树立可效仿的模式。
- 阅读证据。测试输出、运行过的命令及其返回结果、截图、审查者的发现。如果你说不出这些检查会漏掉什么,那就要求一次真正的审查,而不是快速批准。
- 对结果负责。每一次上线的变更都要有人负责,无论代码是谁写的。
由人决定的地方
五项决策仍由人来做;其余所有地方都运行检查
在团队中共享上下文
代码审查的第二项职责一直是传播对代码库的理解。阅读队友的 diff 是你了解发生了什么变化以及各部分如何组合的方式。如果大部分阅读都由机器完成,那大家还怎么学习代码?
我们没有为此设立正式流程。团队里没有人脑中保有 Claude Code 的完整心智模型,我们也认为没人需要这样。当有人想理解代码库的某一部分时,他们会请 Claude 专门为那一部分写一份讲解。这只需几分钟,而且反映的是代码当下的样子。

我们中有些人更进一步,让 Claude 构建一个小型产物,把那部分代码可视化,并按那个人喜欢的学习方式来讲解。
如果目标是把人的注意力花在刀刃上,这比逐行阅读琐碎的 diff 要好。一行文案改动几乎教不了你什么。而为你即将修改的模块写一份讲解,能教给你很多。我们默认在开放的 Slack 频道中工作的文化也有帮助,因为你能在别人构建时看到他们在做什么。
“你合并,你负责”
如果你合并了一个小型或中型变更,而之后仍然出了问题,团队惯例通常是由你来修复。有几件事可以防止情况变糟:
- 变更很小,因此易于审查、调试和回滚。
- 一切皆可逆。功能开关、回滚和分阶段发布能在几分钟内撤销大多数错误。
- 影响范围决定标准。代价高昂的代码需要更多人、更多检查。
- 回归问题会很快浮现,通过遥测和内部使用。
- 这不是追责。负责修复意味着你掌握最多上下文;事故复盘看的是系统。
责任也是共享的。团队中很多人工作在开放频道中,任何人都能看到别人在构建什么、加入讨论,或让 Claude 去填补某个空白,反馈也来自并不拥有该代码的人。这种开放性是质量得以保持高水平、而无需对每一行都设关卡的重要原因。
当我们改变方向时
智能体让启动事情变得很便宜,所以有些工作不该合并。通常频道里会有人问为什么、指出早先的决策,或建议一条更简单的路径,然后作者关闭或重塑这个 PR。
既然代码写起来很快,关闭 PR 就不会让人觉得是损失。诀窍是在讨论串中尽早提出不同方向,而不是在一个已完成的 PR 上作为阻塞性评论提出。
你如何采用这套流程
与你的团队一起做这件事所需的大部分组件今天都已存在。
在拉取请求之前
- 给你的 agent 一些它可以运行的检查,列在一个简短的
CLAUDE.md中,再加上运行格式化和 linter 的钩子。 - 在本地运行
/code-review和/security-review,或者让一个全新上下文的子 agent 进行审查。 - 添加一个
REVIEW.md,并把重复出现的审查意见移入其中。
在每个 pull request 上
- 要求 CI,并把 "Testing"、"Risk" 和 "How to revert" 加入你的 PR 模板。
- 在一个仓库上添加 AI 审查者(Code Review for Claude Code,或 Claude Code GitHub Action),调优
REVIEW.md几周,然后再扩大范围。 - 添加自动化安全审查,并要求每个审查线程在合并前都已解决。
- 让审查力度与风险匹配:对常规变更快速过一遍,对漏掉 bug 代价高昂的地方深入审查(Code Review 中的 Quick、Standard 或 Deep)。
- 限制审查轮数;前几轮之后,只重新审查新的 diff。
批准
- 写下风险层级,根据变更而非作者来设定;从严开始,有证据后再放宽。
- 对你信任的作者保留更轻量的批准路径。
- 使用 CODEOWNERS 和分支保护,让 auth、billing、CI 和发布工作流以及安装程序始终需要真人参与。
- 绝不让 bot 的批准替代必需的人工批准;在新提交上撤销批准。
合并及之后
- 使用合并队列、功能开关、先内部使用、分阶段发布和一步回滚。
- 把事故和回滚转化为 eval 集,并在审查者的提示、工具或模型变化时重新评分。
- 衡量人工时间,以回滚率和事故率作为护栏。
未来走向
Code Review 的 公告 表示,批准 pull request 仍然是人的决定;该产品发布的是发现,而非批准。我们自己的仓库走得更远,让所有者决定哪些低风险变更仅凭自动化检查即可合并,而这条界线还在不断移动。
当审查漏掉某些东西时,我们会问模型当时眼前缺了什么,并把修复放进 CLAUDE.md、skill 或新的检查中。目标没有改变:每次变更消耗更少的人工时间,且回滚不比以前多。
如果你的团队让 agent 提交 pull request,我们想听听你自动化了哪些检查、哪些仍然需要真人,以及你认为我们哪里做错了。
感谢 Emma Webb、Michael Segner 和 Amie Rotherham 的审阅。
来源:Hacker News · claude.dev