跳到正文
Claude.dev 开发者博客· Addy Osmani, Morgan Westlee Lunt, and Qing Wang·· 16 小时前精选AI 评分75

Claude Code 团队如何做代码审查

How the Claude Code team does code review

AI 导读

Anthropic 的 Claude Code 团队公开了其代码审查流程:从 6 月到 9 月,合并的 PR 数量翻倍以上,而需要回滚的比例下降超过 40%。流程分六层,包括提交前让 Claude 自验证、每个 PR 由 Claude 先审、可阻断的安全审查、自动化检查、按风险分级的人工批准和合并队列,多数 PR 最多只需一名人工参与。

推荐理由

Anthropic 团队公开了六层自动化代码审查流程与风险分级规则,可迁移到自建 Agent 工作流。

正文 · AI 翻译

我们之前说过,Claude 编写了 Claude Code 自身约 90% 的代码。那么,在如此庞大的产出量下,我们如何审查代码?现在还有人读代码吗?如果出了问题,谁来发现?

这篇文章介绍了 Claude Code 团队的代码审查流程及其演变过程。从六月到九月,合并到 Claude Code 代码库的拉取请求数量翻了一倍多,而需要回滚的比例下降了 40% 以上。

我们并没有取消审查。但我们把大部分阅读工作交给了机器,以优化人类的时间和注意力,并大力投入让撤销错误变得快速而简单。

重新思考代码审查的目的

当智能体编写代码时,变更数量会迅速增长。在 Anthropic 的 monorepo 中,每天落地的变更从今年五月的约 2,500 个增加到九月的 30,000 多个。

Claude Code 位于独立的代码库中,与 monorepo 分开,但它也面临着巨大的压力。当你以如此快的速度交付时,手动逐行审查代码即使并非不可能,也是极其困难的。

代码审查有两个作用:

  1. 在发布前发现并修复问题
  2. 在团队中建立共享背景和代码库理解

本文主要关注发现和修复问题,但我们会在结尾回到第二个作用。

我们认为,“是否有人读过代码?”并不能精确地代表“这个变更可能出什么问题,哪种检查——自动的还是人工的——才是发现它的正确方式?”

提出这个问题也改变了审查发生的时机。以前,审查是道路尽头的关卡:写代码、开 PR、等同事。

现在,审查持续进行,更像是写作时的拼写检查。大多数变更在请求人工查看之前,已经由 Claude 至少审查和修复过一次。这能捕获大多数常规错误,并将团队注意力留给更高层次的问题和审查。

稀缺资源:人类的时间和注意力

我们希望将人类的时间和注意力保留给只有人类才能解决的问题,并确保自动化检查能捕获其余问题。以我们目前的变更速度,人类仍有大量工作要做,我们的团队几乎每天都会遇到新的、前所未有的挑战。

人类时间涵盖审查成本的两个方面:人们花在审查上的时间,以及他们花在修复劣质代码所造成问题上的时间。如果削减前者只是把时间转移到后者,那就没有帮助。

因此,目标是 Claude Code 代码库(CLI、桌面和 Web 应用以及移动应用)中的大多数拉取请求在合并时,最多只需一个人参与,这个人可以是作者,且回滚或事故不增加。为了衡量人类时间,我们追踪每个 PR 的人工批准数(中位数和第 95 百分位数)、人工评论数,以及 PR 等待某人的时长。回滚率和事故率是护栏:如果它们上升,我们就没有节省人类时间,只是转移了它。

一次变更的生命周期

一次典型的变更,从工程师的笔记本电脑(或 Slack 中的 Claude 会话)出发,经过多层代码审查。

一次变更的生命周期

一次典型的 Claude Code 变更,从作者的机器到用户

图 A大部分路径是自动化的;人的注意力用在风险所在之处

逐层解析

层层把关,而非单一关卡

六层检查,其下还有回滚机制

图 B每一层都能捕获一些问题,也会漏掉另一些。很少有变更能通过所有层,剩下的由回滚处理。

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. 可阻止合并的安全审查

安全也有自己的自动审查。只要 bug 审查或安全审查中还有任何未解决的发现,PR 就不能合并。你要么修复它,要么用简短的理由关闭讨论串,这就是清除误报的方式。

如果后续提交修复了该问题,该发现会自动清除。你可以用开源安全审查 GitHub Action 或 /security-review 命令设置同样的机制。设置方法见 Claude Code 中的自动安全审查。

4. 可阻止合并的自动化检查

常规的那些:lint、类型检查、各平台上的测试,以及构建。(我们写过如何为这种规模扩展 CI,见此处。)一个典型的 CLI pull request 在任何人查看之前可能会运行几十项检查。PR 模板会询问该变更如何测试以及如何撤销。Claude 可以填写这些内容,但提出该变更的人要签字确认。

5. 按风险分级的人工批准

文档修复和自动更新器变更的风险不同,因此审查方式也不同。

风险示例人工批准
低文档、文案、仅内部功能、标志位后的增量变更一旦自动审查和安全检查通过,无需批准
中普通产品变更,以及对缓存、自动更新器或系统提示等敏感区域的变更一人
高最高风险的代码,以及一小部分始终需要两人的路径两人

变更本身决定层级,而非作者。一个分类器读取变更并选择其风险层级。第二个分类器询问该特定变更是否需要另一个人,即使其层级表明不需要。某些路径始终需要一个人,包括所有者列为敏感的任何内容以及任何 CI 工作流文件。

只有受信任的作者才能走更轻的路径。只有仓库受信任列表上的作者才能走更轻的路径,主要是拥有该仓库的团队。其他所有人都需要第二个人批准。智能体的批准也永远不算作人的批准。自动审查可以清除低风险变更,但无法填补需要人工的位置。

谁提示了该变更,谁就要对它负责。在智能体编写的 PR 上,指导智能体的人算作所需审查者之一,就像他们自己输入了代码一样。

一次批准只覆盖一个特定提交。如果新提交落地且系统无法为其担保,例如智能体的推送或有人手动解决的合并,则必须重新批准。

6. 合并队列、标志位和渐进式发布

合并队列会在应用变更的情况下针对 main 重新运行所有检查,因此两个单独通过的 PR 不会合并成一个损坏的 main。新行为通常先通过标志位发布给 Anthropic 员工,我们的重度使用往往会在用户之前发现回归。公开发布先进入 latest 渠道。stable 渠道随后跟进。

7. 快速检测,快速回滚

有些错误仍会漏过,所以最后一层是关于快速捕获它们。标志位无需部署即可关闭。Claude Code 有每周轮值的 on-call,事故复盘会询问哪一层本应捕获该问题。

发现糟糕的合并仍然依赖于作者和值班人员,以及回滚和事故仪表盘。我们还没有在那些数字变动时收紧审批的熔断机制;这里的工程师希望在更多代码转向零人工合并之前拥有它们。

一位同事说,放慢速度确实会降低错误率,但主要是因为你在所有事情上做得更少了。我们更愿意在发现和解决问题上变得更快。

我们如何让审查者变得更好

我们的代码审查流程在一个循环中不断改进。

任何事故现在都成为一项评估。团队收集了过去导致事故的 PR,连同它们的修复推进和回滚,并让了解那段代码的工程师确认每个 bug 及其所在位置。审查者每天针对该集合运行。

我们的事故就是评估集

由过去的事故和回滚构建,每天运行

图 C评估集随着每次事故而增长,对审查者的每一次更改都会针对全部评估集进行评分。

我们通过观察人们如何处理评论来衡量噪音。如果你不介意标记大量非 bug,就很容易捕获更多 bug,所以我们需要对此进行检查。我们根据 PR 上的人如何回应来对审查者留下的每条评论进行分类:他们修复了它、说它是错的、说该行为是有意为之,或决定它无关紧要。我们还在已知干净的 PR 上运行审查者,并统计它报告会导致某人做出有害更改的情况的频率。我们写下来的优先事项是:首先捕获真正的 bug,其次减少审查轮次。

当作者是智能体时,噪音的代价更高。人可以几秒钟内挥开一个吹毛求疵的意见。智能体会修复它,这意味着又一次提交和又一轮审查。

审查必须收敛。智能体作者和智能体审查者可以让彼此无限忙碌。一个 CLI PR 在一夜之间经历了五十多轮审查和修复,直到其作者叫停。

当我们对审查者不断标记的内容运行 git blame 时,大约 59% 是自审查者第一遍以来就存在的代码。审查者很少发现新 bug,它每轮都在发现一些更旧的 bug。

我们自己让它变得更糟。我们已经习惯于默认运行几轮,因为每一遍都会捕获一些新东西。这在有风险的更改上可能值得,但不是每个 PR 都值得。团队现在将通过轮次与召回率一起跟踪,并改变了重新审查:

  • 轮次上限。三轮之后,审查者要求作者退后一步,重新考虑方法。
  • 仅差异重新审查,在前几遍之后。
  • 标记 bug 类别,以便作者修复每个实例,而不是一行。
  • 不重复已发布的发现。

审查智能体还会每晚对现有代码运行,帮助我们在旧 bug 出现在其他地方之前捕获它们。

收敛的审查

内部拉取请求,在收敛更改之前和之后

图 D收敛更改后,每个内部拉取请求的审查轮次更少

人类留在环中的地方

把一位资深工程师从深度工作中拉出来去捕获一个常规错误,代价远高于自动化审查。在 Anthropic,我们的工作已从阅读每个差异转变为机器不擅长的决策:

  • 我们到底该不该做这件事?方向、品味和范围。一个宣称已解决审查瓶颈的团队,对于来自团队外部的变更仍然保留人工审查,所以有人会问“我们到底该不该做这件事?”
  • 有风险的代码,例如计费、自动更新器和 CI 工作流。
  • 架构,它会树立一个别人会效仿的模式。
  • 阅读证据。测试输出、运行的命令及其返回结果、截图、审查者的发现。如果你说不出这些检查会漏掉什么,那就要求一次真正的审查,而不是快速批准。
  • 对结果负责。每一个上线的变更都由某个人负责,无论代码是谁敲的。

由人做决定的地方

五项决定仍由人来做;其余所有地方都运行检查

图 E人们从阅读每一处 diff 转向机器不擅长的那些决策

在团队中共享上下文

代码审查的第二项职责一直是传播对代码库的理解。阅读队友的 diff 是你了解改了什么、各部分如何拼合的方式。如果大部分阅读都由机器完成,那大家还怎么学习代码?

我们没有为此设立正式流程。团队里没有人脑中保有 Claude Code 的完整心智模型,我们也认为没人需要这样。当有人想理解代码库的某一部分时,他们会请 Claude 专门为那一块写一份讲解。这只需几分钟,而且反映的是代码当下的样子。

Diagram titled "If machines do most of the reading, how does anyone learn the code?" On the left, a grid stands for the codebase, with a few squares highlighted as managed settings, the part you want to understand; nobody keeps a complete mental model of it in their head. An arrow labeled "Ask Claude about exactly that slice", with the example question "How does Claude Code retrieve managed settings?", leads to two outcomes: Claude writes an explainer, which takes minutes and reflects the code as it is today; and, for some, Claude builds a small artifact that visualizes that part of the code and teaches it the way that person likes to learn. Along the bottom: reading trivial diffs line by line, a one-line copy change teaches you almost nothing; an explainer for the module you are about to change teaches you a lot.

我们中有些人更进一步,让 Claude 构建一个小型产物,把那部分代码可视化,并按那个人喜欢的学习方式来讲解。

如果目标是把人的注意力花在刀刃上,这比逐行阅读琐碎的 diff 要好。改一行文案几乎学不到什么。为你即将修改的模块写一份讲解则能学到很多。我们默认在公开 Slack 频道里工作的文化也有帮助,因为你能在别人构建时看到他们在做什么。

“你合入,你负责”

如果你合入了一个小型或中型变更,而之后仍然出了问题,团队惯例通常是由你来修复。有几件事能防止这变得糟糕:

  • 变更很小,所以容易审查、调试和回滚。
  • 一切都是可逆的。功能开关、回滚和分阶段发布能在几分钟内撤销大多数错误。
  • 影响范围决定门槛。代价高昂的代码需要更多人、更多检查。
  • 回归问题会很快浮现,通过遥测和内部使用。
  • 这不是追责。负责修复意味着你掌握最多上下文;事故复盘看的是系统。

责任也是共享的。团队中很多人都在公开频道里工作,任何人都能看到别人在构建什么、接上一个话题,或让 Claude 去填补某个缺口,反馈也来自并不拥有这段代码的人。这种开放性是质量得以保持高水平、而无需对每一行都设关卡的重要原因。

当我们改变方向时

智能体让启动事情变得很便宜,所以有些工作不该合入。通常频道里会有人问为什么、指出早先的决定,或建议一条更简单的路径,然后作者关闭或重塑这个 PR。

既然代码写得很快,关闭 PR 并不会让人觉得是损失。诀窍是在话题里尽早提出不同的方向,而不是在已完成的 PR 上作为阻塞性评论提出。

你如何采用这套流程

与你的团队一起做这件事所需的大部分组件如今都已具备。

在拉取请求之前

  • 给你的 agent 提供它可以运行的检查项,列在一个简短的 CLAUDE.md 中,再加上运行格式化和 linter 的 hooks。
  • 在本地运行 /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 的批准替代必需的人工批准;在新提交上撤销批准。

合并及之后

  • 使用 merge queue、feature flags、先内部使用、分阶段发布和一步回滚。
  • 把事故和回滚转化为 eval set,并在审查者的 prompts、工具或模型变化时重新评分。
  • 衡量人工时间,以回滚率和事故率作为护栏。

未来走向

Code Review 的 announcement 表示,批准 pull request 仍是人工决定;该产品发布的是发现,而非批准。我们自己的仓库走得更远,让 owner 决定哪些低风险变更仅凭自动化检查即可合并,而这条界线还在不断移动。

当审查漏掉某些东西时,我们会问模型当时眼前没有什么,并把修复放入 CLAUDE.md、skill 或新的检查中。目标没有改变:每次变更花费更少的人工时间,且回滚不比以前更多。

如果你的团队让 agent 打开 pull request,我们想听听你自动化了哪些检查、哪些仍需要人工,以及你认为我们哪里做错了。

感谢 Emma Webb、Michael Segner 和 Amie Rotherham 的审阅。

来源:Claude.dev 开发者博客 · claude.dev