2026/10/15 收录

How the Claude Code team does code review

#code review#Claude Code#AI agents#automation#software engineering
/

我们之前说过,Claude Code 中约 90% 的代码是由 Claude 自己编写的。那么,面对如此庞大的代码产出量,我们是如何进行代码审查的呢?现在还有人在读代码吗?如果出了问题,又是谁来发现的呢?

本文介绍了 Claude Code 团队的代码审查流程及其演进过程。从六月到九月,合并到 Claude Code 代码库的拉取请求(Pull Request)数量增加了一倍多,而需要回滚的拉取请求占比则下降了超过 40%。

我们并没有移除评审环节。但我们确实把大部分阅读工作交给了机器,从而优化了人类的时间和注意力,并大力投入让快速、轻松地撤销错误成为可能。

重新思考代码评审的目的

当智能体(Agent)编写代码时,变更数量会迅速攀升。在 Anthropic 的单体仓库(monorepo)中,每天合入的变更从五月的约 2,500 个增长到九月的超过 30,000 个(今年)。

Claude Code 位于它自己的仓库中,与 monorepo 分开,但它同样承受着巨大的压力。当交付速度如此之快时,逐行的人工代码审查即使不是完全不可能,也是极其困难的。

代码审查承担两项任务:

1. 在问题上线之前发现并修复它们

2. 在整个团队中建立共享的上下文和对代码库的理解

本文主要关注发现和修复问题,但我们会在接近尾声时回到第二项任务。

我们认为,「是否有真人阅读了代码?」是「这次变更可能出什么问题,以及哪一种检查——自动化还是人工——才是捕捉它的正确手段?」的一个不精确的替代指标。

提出这个问题也改变了代码评审发生的时机。过去,评审是路途尽头的一道关卡:写完代码,提交 PR,然后等待同事评审。

现在,评审持续进行,更像是你在写作时的拼写检查。大多数改动在请人查看之前,已经由 Claude 至少评审并修正过一次。这能捕获大部分常规错误,并把团队的注意力留给更高层次的问题和更深入的审视。

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

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

人类时间涵盖了代码审查(review)成本的两个方面:人们花在审查上的时间,以及人们花在修复糟糕代码所造成的问题上的时间。如果节省下来的时间只是转移到了后者,那么削减前者并没有帮助。

因此,目标是让 Claude Code 代码仓库(CLI、桌面端和 Web 应用、以及移动端应用)中的绝大多数 Pull Request(PR)在最多一个人参与的情况下合并,这个人可以是作者本人,同时回滚率和事故率不升高。为了衡量人力时间,我们跟踪每个 PR 的人工批准次数(中位数和 95 分位数)、人工评论数,以及 PR 等待人工处理的时长。回滚率和事故率是护栏指标:如果它们上升,说明我们并没有节省人力时间,只是把时间挪了个位置。

一个变更的一生

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

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

逐层构建

图 B每一层都能捕获部分问题,但也会遗漏其他问题。很少有问题能穿过所有层,剩下的交给回滚处理。

1. 在他人查看之前,工作已经过验证

如今大多数代码审查发生在 PR 创建之前。我们会给 Claude 一个它可以运行的东西——比如测试、构建,或者与设计稿对比的截图——并要求它展示输出结果,而不是仅仅声称已完成。然后由一个子代理以全新上下文审查 diff。这两个习惯都源自我们的最佳实践指南。

在提交 PR 之前,我们很多人还会运行几个内部技能(skill):一个负责寻找 bug,一个负责简化 diff,还有一个负责端到端地检查行为。UI 变更还会对照我们的设计规范进行检查。

Claude Code 的创建者 Boris Cherny 曾表示,让 Claude 有能力验证自己的工作是获得好结果最重要的事情。他估计这能让最终结果好上两到三倍,并写道:"每个领域的验证方式都不尽相同。它可能简单到只是运行一条 bash 命令,或者运行测试套件,又或者在浏览器或手机模拟器中测试应用。"

当自动审查工具反复标记同一个问题时,我们就从源头上解决它:在技能(skill)中解决,通过 lint 规则解决,或者更新以下这类说明性文件:

  • CLAUDE.md 告诉 Claude 这个项目是什么:技术栈、代码规范、目标和非目标。每次审查都会加载它,所以在大型代码库中我们会保持它简短,并从这里指向其他文档。审查工具还会标记违反其中规范的代码,以及会导致其中某一行内容过时的改动。
  • REVIEW.md由代码所有者撰写,告诉评审者他们负责的那部分代码中哪些内容是关键的。我们会另行检查评审者是否真正遵循了这份文档。好的 REVIEW.md 都很简短。它们说明了在该仓库中失败是什么样的(对文档来说是「内容失实」,对配置来说是「路由错误」),对吹毛求疵的数量设上限,列出可以跳过的路径,并要求提供文件和行号作为证据,而不是仅凭文件名猜测。它们还要求给出一份以数量开头的总结,并在没有需要修复的问题时明说。

2. 每个拉取请求(Pull Request)都进行 AI 评审

每个拉取请求(pull request)都会先经过 Claude 的审查,然后才由人工查看。它会结合整个代码仓库和 PR 中声明的意图来阅读代码差异(diff),并追问几个问题:这个改动是否解决了它要解决的问题?是否与系统整体相契合?是否会破坏其他功能?

面对缺陷修复(bug fix),它会进一步追查根本原因。其公开版本,Claude Code 的代码审查,现已在 Team 和 Enterprise 套餐中正式可用,此外 /code-review 可以在本地运行一个轻量版。

当我们发布研究预览版时,获得实质性评审意见的内部 PR(Pull Request)比例从 16% 上升到 54%。超过 1,000 行的 PR 基本都能发现问题,而小型 PR 大多直接通过。管理员可以为每个仓库设置 Quick、Standard 或 Deep 三档模式。如果一个漏掉的 bug 造成的损失高于额外的评审时间成本,那么 Deep 模式就物有所值。

发现的问题会先由其他智能体(Agent)验证,然后才交由人工审查。 多个智能体会同时查找缺陷(Bug)。随后,另一个独立的小组会对每条发现进行投票,只有当足够多的成员一致认为它确实存在时,该发现才会被发布。仅涉及代码风格、诊断信息或清理工作的发现会被丢弃。在保留这些过滤器之前,我们先在自己的 PR(Pull Request,合并请求)上进行了 A/B 测试。最终留下的发现会以行内评论的形式呈现,并按严重程度排序。每条评论都会被标记为「重要(Important)」「细节(Nit)」或「已有问题(Pre-existing)」,这样即使是 PR 并未引入的缺陷,也不会被误认为是作者的过错。

每一条发现都必须得到回应。你要么修复它,要么给出理由关闭该讨论。通常会有智能体(agent)在夜间接手修复,所以作者回来时,PR 已经又经历了一轮审查。

3. 可以阻断合并的安全审查

安全审查也有自己的自动化流程。只要漏洞审查或安全审查中还有任何未处理的发现,PR 就无法合并。你要么修复它,要么给出简短理由关闭讨论,这也是消除误报的方式。

如果后续的提交修复了该问题,这条发现会自动消失。你也可以使用开源的安全审查 GitHub Action 或 /security-review 命令来实现同样的效果。具体设置方法请参阅 Claude Code 中的自动化安全审查。

4. 阻断式自动化检查

老一套:lint、类型检查、每个平台上的测试,以及一次构建。(我们曾撰文介绍如何为这种规模扩展持续集成(CI),见此处。)一个典型的命令行工具(CLI)拉取请求(pull request)在任何人查看之前,可能已经跑完几十项检查。PR 模板会要求说明这项改动是如何测试的,以及如何回退。Claude 可以把这部分填写好,但最终要由提出该改动的人来签字确认。

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

文档修复和自动更新器改动所承担的风险不同,因此适用的评审流程也不同。

风险示例人工审批低文档、文案、仅限内部使用的功能、在功能开关(flag)保护下的增量改动当自动化审查和安全检查全部通过后,无需人工审批中常规产品改动,以及对缓存、自动更新器或系统提示(system prompts)等敏感区域的改动一人高风险最高的代码,以及少量始终需要两人审批的路径两人

变更决定风险层级,而非作者。 分类器会读取变更并确定其风险层级。第二个分类器则判断该变更是否需要另一个人参与,即便其层级显示不需要。某些路径始终需要人工参与,包括所有者标记为敏感的内容以及任何 CI 工作流文件。

只有受信任的作者才能走更轻量的审批路径。 只有仓库受信任名单上的作者才能走更轻量的审批路径,通常就是负责该仓库的团队。其他所有人都需要第二个人来审批。智能体(agent)的审批永远不算作人工审批。自动化审查可以放行低风险变更,但无法填补需要人工参与的审批环节。

谁发起的变更,谁就要为之负责。 在智能体(agent)编写的 PR 上,指挥智能体的人算作必需的评审者之一,与他们自己亲手写下这些代码并无二致。

一次批准只覆盖一个特定的提交(commit)。 如果有新的提交落地,而系统无法为其背书,比如智能体的推送,或者有人手动解决的合并,那么就必须重新给出批准。

6. 合并队列、功能开关与渐进式发布

合并队列(merge queue)会在应用变更后针对 main 分支重新运行每一项检查,因此两个单独通过的 PR 无法合起来导致 main 分支损坏。新功能通常先通过功能开关(flag)推送给 Anthropic 员工,我们密集的使用往往能在用户之前发现回归问题。公开发布则首先进入 latest 渠道。stable 渠道则紧随其后。

7. 快速发现,快速回滚

总有一些错误会漏过去,所以最后一层的关键在于快速发现并拦截它们。功能开关(Feature Flag)可以在不部署的情况下直接关闭。Claude Code 设有每周轮值的待命(on-call)制度,事故复盘时会追问本应由哪一层来拦截这个问题。

发现一次糟糕的合并,目前仍依赖于代码作者和值班人员,以及回滚和事故仪表盘。我们还没有能在这些指标恶化时自动收紧审批的熔断机制(Circuit Breaker);这里的工程师们希望在更多代码转向零人工合并之前,把这类机制建立起来。

一位同事说,放慢节奏确实能降低出错率,但主要是因为你做的每件事都变少了。我们更愿意做的是,更快地发现和修复问题。

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

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

现在,任何事故都会成为一个评测(eval)。 团队收集了过去曾引发事故的 PR,包括它们的前向修复(fix-forward)和回滚(revert),并让熟悉相关代码的工程师逐一确认每个缺陷及其所在位置。审查者每天都会在这组数据集上运行。

图 C评估集会随着每次事故不断增长,而对审查者的每一处改动都会基于全部数据进行评分。

我们通过观察人们如何对待这些评论来衡量噪声。 如果你不介意把大量非 bug 也标记出来,就更容易抓到更多 bug,所以我们需要对此加以约束。我们会根据 PR 负责人对审阅者所留每条评论的回应方式来进行分类:他们修复了、说这条评论是错的、说该行为是有意为之,或者认为无关紧要。我们还会在已知没有问题的 PR 上运行这个审阅工具,统计它有多少次会报告出足以导致他人做出有害改动的问题。我们白纸黑字写下的优先级是:首先抓到真正的 bug,其次减少审阅轮次。

当作者是智能体(Agent)时,噪音的代价更高。人可以在几秒钟内对一个小问题一笑了之,而智能体会去修复它,这意味着又多了一次提交和一轮评审。

评审必须收敛。 智能体作者和智能体评审者可以无限期地互相折腾下去。有一个 CLI 的 PR 在一夜之间经历了五十多轮评审和修复,直到其作者主动叫停。

当我们对评审者反复标记的内容运行 git blame 时,其中约 59% 是从评审者第一轮起就一直存在的代码。评审者很少发现新的 bug,它只是每一轮再多找出几个旧问题而已。

这其实是被我们自己搞糟的。我们已经习惯了默认跑好几轮评审,因为每一轮总能发现新问题。这种做法在高风险改动上是有价值的,但并非每个 PR 都需要如此。现在团队会跟踪「通过所需轮数(rounds-to-pass)」和召回率,并改进了复审流程:

  • 轮数上限。三轮之后,评审者会请作者退一步,重新审视整体方案。
  • 仅针对差异的复审,在前几轮之后进行。
  • 标注缺陷的类别,这样作者会修复所有同类问题,而不仅仅是一行代码。
  • 不重复报告已提交过的发现。

审查智能体(Review agent)还会每晚对现有代码运行一遍,帮助我们在老 bug 在别处冒头之前就把它们揪出来。

图 D收敛改动后,每个内部 Pull Request 的审查轮次减少了

人类主导的环节

把一位资深工程师从深度工作中拉出来去发现一个常规错误,代价远高于一次自动化评审。团队中的人员仍需负责:

  • 决定是否要做这件事。 方向、品味与范围。有一个团队宣称其评审瓶颈已解决,但仍对来自团队之外的变更保留人工评审,以便有人能问一句"我们到底该不该做这个?"
  • 评审高风险代码,例如计费、自动更新器和 CI 工作流。
  • 评审架构,尤其是那些会被他人照搬的模式。
  • 审视证据。 测试输出、实际执行的命令及其返回结果、截图、审查者的发现。如果你说不清这些检查会遗漏什么,就应当请求一次真正的审查,而不是走个形式快速批准。
  • 对结果负责。 每一个发布出去的变更都必须有专人负责,无论代码是谁敲进去的。

在团队间共享上下文

代码审查的第二个作用一直是帮助团队成员理解代码库。阅读同事的代码差异是了解变更内容以及各部分如何协同工作的方式。如果机器承担了大部分的阅读工作,那谁还能学习代码呢?

我们没有针对这一点的正式流程。团队中没有任何人能够在脑海中完整地构建 Claude Code 的全貌,我们也不认为有人需要这样做。当有人想理解代码库的某个部分时,他们会请 Claude 为那部分代码撰写一份说明文档。这只需要几分钟,而且反映的是代码当前的实际状态。

Diagram titled

我们中的一些人更进一步,让 Claude 构建一个小的 artifact,把那部分代码可视化出来,并以这个人喜欢的学习方式来讲解它。

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

"你提交的代码,你负责"(YOU LAND IT, YOU OWN IT)

如果你提交了一个中小型变更后仍然出了问题,按照团队的惯例,通常由你来修复。有几点可以防止事情变得更糟:

  • 变更都很小,因此易于审查、调试和回滚。
  • 一切都可以回滚。功能开关(Feature Flag)、回滚(Revert)和分阶段发布可以在几分钟内撤销大多数错误。
  • 影响范围决定标准。高风险的代码会配备更多人员和更多检查。
  • 回归问题会迅速暴露,通过遥测(Telemetry)数据和内部使用即可发现。
  • 这不是追责。主动认领修复意味着你掌握着最充分的上下文;而事故复盘审视的是整个系统。

所有权同样是共享的。团队中许多人都在公开频道里工作,任何人都能看到别人正在构建什么、接手某个任务,或者让 Claude 去填补某个缺口;反馈也来自那些并不拥有这些代码的人。这种开放性是质量能够在无需逐行把关的情况下依然保持高水平的重要原因。

当我们改变方向时

智能体(Agents)让启动工作变得成本很低,因此有些工作本就不该继续推进。通常频道里会有人提出疑问,指出之前的某个决策,或者建议一条更简单的路径,然后作者就会关闭或重新调整这个 PR。

由于代码写起来很快,关闭 PR 并不会让人觉得损失了什么。关键在于尽早在线程中提出不同的方向,而不是在一个已经完成的 PR 上留下阻塞性的评论。

如何在团队中采用这套流程

要用这套流程与团队协作,所需的大部分工具如今已经具备。

发起 Pull Request 之前

  • 为你的智能体提供它可以运行的检查,列在一个简短的 CLAUDE.md 中,再加上运行格式化工具和代码检查工具的钩子(hooks)。
  • 在本地运行 /code-review 和 /security-review,或者使用全新上下文的子智能体进行审查。
  • 添加一个 REVIEW.md,并把重复出现的审查意见移入其中。

在每个拉取请求(Pull Request)上

  • 强制要求 CI,并在你的 PR 模板中加入「测试(Testing)」「风险(Risk)」和「如何回滚(How to revert)」部分。
  • 先在一个仓库上接入 AI 审查员(Claude Code 的 Code Review,或 Claude Code GitHub Action),花几周时间打磨 REVIEW.md,然后再扩大范围。
  • 加入自动化安全审查,并要求所有审查讨论在合并前都得到解决。
  • 审查力度要与风险相匹配:常规改动快速过一遍,漏掉一个 bug 代价高昂的场景则进行深度审查(在 Code Review 中可选择 Quick、Standard 或 Deep)。
  • 限制审查轮数;前几轮之后,只重新审查新增的 diff。

批准(Approval)

  • 把风险等级写成文,并根据变更内容而非作者身份来确定等级;初期从严格起步,再根据证据逐步放宽。
  • 为你信任的作者保留更轻量的审批流程。
  • 使用 CODEOWNERS 和分支保护,确保涉及鉴权、计费、CI 与发布工作流以及安装程序的改动始终需要人工审核。
  • 绝不能让机器人的审批替代必需的人工审批;当有新提交时,应撤销原有审批。

合并及之后

  • 使用合并队列(merge queue)、功能开关(feature flag)、先在内部使用、分阶段发布以及一步式回滚。
  • 把事故和回滚案例转化为评测集(eval set),并在评审器的提示词、工具或模型发生变化时重新为其打分。
  • 以人工耗时作为衡量指标,并以回滚率和事故率作为护栏。

未来方向

代码审查(Code Review)的发布公告中提到,批准一个拉取请求(pull request)仍然是由人来决定的;产品提供的是审查发现,而不是批准结果。而我们自己的代码仓库走得更远,允许所有者决定哪些低风险变更仅凭自动化检查即可合并,而且这条界线还在不断向前推移。

当某次审查有所遗漏时,我们会追问模型当时缺少哪些上下文,并把修复写入CLAUDE.md、一个技能(skill)或一项新的检查。目标始终未变:让每个变更占用的人力时间更少,同时回滚次数不比以前更多。

如果你的团队允许智能体(agent)发起拉取请求(pull request),我们很想了解你已经自动化了哪些检查,哪些仍需人工介入,以及你认为我们有哪些地方做得不对。

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