Claude Code 团队如何做代码审查
译文整理自 Addy Osmani 的 X Article:How the Claude Code team does code review(原始帖)。插图保留原文配图。
我们此前提到过,Claude Code 约有 90% 的代码由 Claude 编写。那么在这种规模下,我们如何做代码审查?到底是谁在读代码?如果代码出了问题会怎样?
本文介绍我们 Claude Code 团队的代码审查流程,以及我们如何改进它。从六月到九月,合并进 Claude Code 代码库的 pull request 数量翻了一倍多,而不得不回滚的 pull request 占比下降了超过 40%。
我们并没有停止做代码审查。相反,我们把大部分阅读工作自动化了,并加以调优,以优化人的时间与精力。我们还大力投入,提升回滚错误的速度与便捷度。
重新思考代码审查的目标
有了代理写代码,变更量会迅速上升。在我们的 monorepo 中,每天合并的变更从五月约 2,500 次,增加到今年九月超过 30,000 次。
虽然 Claude Code 不在我们的 monorepo 里,但它同样面临很大压力。当你以那样的速度推进时,逐行手工做代码审查会越来越难,甚至不可能。
代码审查有两个目的:
- 在上线前发现并修正 bug
- 形成对代码库的共同理解
本文主要关注第一个目标,第二个目标我们会在文末讨论。
我们把「有没有人读过这段代码?」看作一个不够精确的指标,真正要问的是:「这次变更可能出什么问题,以及用哪种检查——自动化的还是人工的——最适合抓住它?」
这个问题也改变了代码审查的时机。传统上,代码审查是事后检查:代码写完、PR 提交后,再等人来看一眼。如今我们把代码审查融入工作流,更像你写作时持续开启的拼写检查。
绝大多数变更在请人过目之前,至少已经被 Claude 审查并修正过一次。这样我们能拦住大部分常规 bug,把人的注意力留给更高层的考量。
人的时间与注意力
我们希望把人的时间与注意力留给只有人能处理的事,同时确保有足够的自动化覆盖其余部分。即便按我们现在的节奏,仍有海量工作需要人来做,而且团队几乎每天都会遇到新的、前所未见的挑战。
因此,人的时间是双边成本。我们不仅统计人们做代码审查花的时间,也统计他们修复劣质代码引入的 bug 所花的时间。如果只减少前者而不减少后者,其实并没有真正节省人的时间。
所以,我们的目标是:Claude Code 各仓库(CLI、桌面与 Web 应用、以及移动应用)中的大多数 pull request,应在最多一人介入(可以是作者本人)的情况下合并,且回滚或事故不增加。
我们用人均审批数的中位数(以及第 95 百分位)、人工评论数、以及 PR 等人处理的时长来衡量人的时间。我们把回滚率和事故率当作护栏:如果这些指标上升,说明我们并没有减少人的时间,只是把它挪到了别处。
一次改动要走怎样的旅程?
一次典型改动——无论来自工程师的笔记本,还是 Slack 里的 Claude 会话——都会经过多层审查。

上图是一次典型的 Claude Code 改动,从作者环境到生产。这一过程大部分已自动化,人的注意力集中在有风险的部分。
我们有六层检查,外加一套回滚机制,用来处理漏网之鱼。

每一层都会拦住一些 bug,也会漏掉一些。很少有 bug 能穿过所有层;即便有漏网的,我们也有回滚机制。
1.PR 创建前的验证:
我们大部分审查是在创建 PR 之前完成的。我们要求 Claude 做可运行的事,比如跑测试、构建,或把截图与设计稿对比。不是说「任务完成了」就算完,而是让它把结果展示给我们。然后,一个子代理用全新上下文审查 diff。这两种策略都写在我们的最佳实践指南里。
打开 PR 之前,我们许多人还会跑一批内部 skill——搜 bug、缩小 diff、端到端验证,以及对照设计规范检查 UI 改动。
据创建 Claude Code 的 Boris Cherny 所说,给 Claude 配备一套验证流程,大概是提升产出质量最关键的一环。
他估计,验证流程能把 Claude 产出的质量提升两到三倍。
不同领域的验证流程可以大不相同:
有时简单到跑一条 bash 命令。有时是跑一套测试。有时是在浏览器或手机模拟器里测应用。
如果自动化审查员一再标出同类问题,我们就在源头修——改 skill 本身、加 lint 规则,或更新这类文档文件:
CLAUDE.md —— 项目描述文件,用来给 Claude 提供项目上下文(技术栈、约定、目标、非目标)。Claude Code 每次审查都会拉入这个文件,所以对大型代码库我们保持它简短,并把其余文档在此引用。当代码违反该文件中的约定,或某次更新导致其中内容过时,审查员就会标出来。
REVIEW.md —— 由代码所有者告诉审查员,他们那部分代码里什么最重要。我们会单独核查审查员是否真的在遵守这些指引。好的指引简短,并聚焦于:
界定项目级失败(文档不得撒谎;配置不得误路由);限制抠细节;定义忽略路径;要求给出文件 + 行号引用,而不是猜文件名;要求顶层摘要,包含问题数量,并明确写清「无问题」。
2. 每个 pull request 都做 AI 审查
每个 PR 在人工审查之前都会先过一遍 Claude 审查。
diff 会对照整个代码库以及 PR 作者声明的意图来分析。它会检查:改动是否真正解决了问题;改动是否融入更大系统;改动是否破坏代码库其他部分。
审查 bug 修复时,bot 会尝试找到根因。
我们的公开产品 Code Review for Claude Code 现已向所有 Team 与 Enterprise 客户开放。本地也有更轻量的版本——/code-review。
自发布研究预览以来,我们内部 PR 中收到实质性审查评论的比例从 16% 升至 54%。Code Review 会在大多数超过 1,000 行的 PR 上检出问题,并在多数较小 PR 上给出干净结果。管理员可为仓库配置 Quick、Standard 或 Deep 模式。当漏掉一个 bug 的代价高于花在审查上的时间时,Deep 很有用。
在人工审查之前,发现项还会由多个其他代理核查:
多个代理并行搜 bug
单独一轮投票决定某发现是有效还是误报,只确认票数足够的发现
仅与风格/诊断/清理相关的发现会被过滤掉(这些过滤器我们先在自己的 PR 上做了 A/B 测试,再推广)
剩余发现以行内评论呈现,按严重级别排序,并标记为:
Important、Nit、Pre-existing(这样不会因 PR 并未引入的既有 bug 而不公平地惩罚作者)
所有发现都必须处理——修好,或以说明关闭该讨论串。很多情况下,代理会在夜间把问题修好,作者回来时 PR 已经又过了一轮审查。
3. 可拦截的安全审查
我们还会跑自动化安全审查。只要还有未关闭的发现(来自代码审查或安全审查),PR 就不能合并。作者可以修问题,也可以用简短理由关闭讨论串(我们处理误报的方式)。
若后续 commit 已解决问题,发现会自动关闭。你可以用开源的 security review GitHub Action,或 /security-review 命令搭同样的流程。参见 Claude Code 中的自动化安全审查,了解如何配置。
4. 可拦截的自动化检查
标准检查:lint、类型检查、全平台测试、构建。(我们写过如何扩展 CI。)一次典型的 CLI PR 在任何人看之前,就可能已经跑了几十项检查。PR 模板里有关于如何测试该改动、以及如何回滚的问题。Claude 可以帮你填,但作者有责任审一遍。
5. 按风险缩放的人工审批
有些改动比其他改动风险更高(例如修文档 vs. 改自动更新器),因此需要不同级别的审查。

层级由改动决定,而不是由作者决定。一个分类器根据改动判定风险级别。另一个分类器判断某次改动是否即便层级未要求也仍需额外审批。有些路径永远需要另一人审批——所有者标记为敏感的任何内容,以及任何 CI workflow 文件。
只有仓库可信名单上的作者才能享受放宽的审查要求,一般就是拥有该仓库的团队。其他人都需要第二人批准。代理的批准不算人工批准。自动化审查可以放行低风险改动,但在需要人的时候,它不能替代人。
改动的作者对其负责,因此若代理创建了 PR,操作该代理的人始终算作所需审查者之一。一次 PR 批准只对一个 commit 有效。若有不可信的新 commit 进来(例如代理推了东西,或有人手动解决了合并冲突),PR 必须重新批准。
6. 合并队列、功能开关与分阶段发布
合并队列确保检查是在把改动应用到 main 的状态下跑的。这能避免两个各自成功的 PR 合并后把 main 弄坏。通常,新功能会挂在功能开关后面推出,Anthropic 员工先获得访问。因为我们大量使用自己的产品,往往在用户之前就发现回归。
公开发布时,改动先上 latest 通道,stable 通道随后跟上。
7. 快速反馈与回滚
总会有一些糟糕的合并漏网。这是我们的最后一道防线,重点是尽快发现它们。挂在功能开关后的改动可以在不部署的情况下关掉。
Claude Code 有每周轮值的 on-call,任何事故复盘都会回头看哪一层本该拦住问题。除了盯回滚与事故仪表盘,仍要靠作者和 on-call 发现糟糕合并。我们还没有根据这些指标自动调整审批要求的断路器机制,但随着我们推进「合并时更少人工介入」,这是我们正在考虑的方向。
有位团队成员指出,放慢速度、减少产出其实能提高准确率,但那主要是因为总体工作量下降了。我们真正的优先事项,是提升快速发现并纠正问题的能力。
我们如何把审查员做得更好
我们的代码审查流程是持续改进的循环:
我们把事故当作评估指标。团队收集了导致事故的 PR、它们的 fix-forward 与回滚,并请了解代码库的工程师核实每个 bug 的位置与正确性。审查系统每天对照这批样本做评估。

每一起事故都会加入样本集,审查系统的每一次改动都会对照整套样本评估。
为了衡量噪声,我们观察人对审查评论的反应。如果我们愿意报告大量非 bug,要提高找 bug 率很容易,所以必须加以约束。我们把每条审查评论按 PR 上的人如何处理来分类:修好了、驳回了、澄清为有意为之、或判定无关紧要。此外,我们还会在已知干净的 PR 上跑审查系统,观察它报告「若照做会造成有害改动」的频率。
我们公开的优先顺序是:第一,检出真实 bug;第二,减少审查轮次。
当作者是代理时,处理一条审查评论的成本更高。人关掉一条 nit 只要一秒,但代理要处理它就会再产生一次 commit,以及又一轮审查。
审查过程必须收敛。代理作者与代理审查员有可能永远循环下去。我们观察到 CLI 项目里有一个 PR 一夜间循环了五十多次,就是代理作者与代理审查员来回拉锯。这次循环是人工停下的,但它本可以无限继续。
我们对审查系统持续标出的内容跑了 git blame,约 59% 是从第一遍起就一直在那儿的代码。本质上,审查系统很少在找新 bug,而是每轮多找出一点旧的。
我们还把情况弄得更糟,因为我们养成了默认跑多轮审查的习惯——每一轮都可能找到不同的 bug。对高风险改动迭代多轮审查可能有用,但并非每个 PR 都需要。团队开始在召回率之外跟踪「通过所需轮次」,并更新了重新审查的方式:
限制轮次。三轮之后,审查系统会要求作者重新评估方案。初始轮次之后,重新审查只看 diff。指明 bug 类别,让作者一次改完同类问题,而不是只改一行。避免重复报告已见过的问题。审查代理也会在夜间对当前代码库跑一遍,帮助我们在历史 bug 扩散之前发现它们。

引入 Convergence 后,内部 pull request 的平均审查轮次有所下降。
人在回路中
让一位资深工程师停下手里的工作去审查一个常见错误,相比把该流程自动化,代价很高。人工审查员对某些任务仍然必不可少:
- 我们该不该做这个?决定要不要做某件事,以及产品的愿景、品味与目标。
有一个声称已解决代码审查瓶颈的团队,对外来团队的改动仍做人工审查,以确保那确实是该做的事。
- 审计危险代码(计费、自动更新器、CI workflow)。
- 架构审查,因为这些选择会定下其他人遵循的约定。
- 核实证据(测试输出、跑过的命令、截图、审查评论)。如果你说不清这些检查会漏什么,就别只求一个 👍,你需要真正的审查!
- 承担责任。每一个上线的改动都有人负责,无论是谁敲的字。
团队上下文
代码审查一直有双重作用:传达代码库的变化。读同事改动的 diff,通常是人们理解发生了什么、以及代码库如何运作的方式。如果大部分阅读由机器完成,那学习代码库的方式又变成什么?
我们对此没有正式机制。团队里没有人脑子里装得下 Claude Code 的完整心智模型,我们也不认为谁需要那样。相反,任何人想了解代码库的某一块,就让 Claude 针对那一块生成一份讲解。只要几分钟,而且讲解永远是最新的。

我们中有些人还会多走一步,让 Claude 生成一个小型制品,把这块区域可视化,并用我们偏好的风格来讲解。
这比逐行读琐碎 diff(比如一行文案改动)更能把人的注意力用在刀刃上——琐碎 diff 教给你的很少。为你即将改动的模块写一份讲解,能让你学到很多。
此外,我们默认开放:在公开的 Slack 频道工作,边做边看到别人在建什么。
「你合入,你负责」
如果你合并了一个小或中等改动,出了问题,一般预期是你通常自己来修。这之所以不会失控,有几条原因:
- 改动小,易于审查、调试和回滚。
- 一切都可以回滚。功能开关、回滚与分阶段发布能在几分钟内撤销大多数错误。
- 爆炸半径设定门槛。越昂贵的代码,越多人看、越多验证。
- 回归会通过遥测与内部使用快速浮现。
- 这不是甩锅游戏。修问题的人拥有它,因为他们上下文最多。事故复盘看的是系统。
- 另外,团队很多人通过在公开频道工作来分担责任。任何人都能看到别人在建什么、加入讨论,或让 Claude 找缺口。反馈也会来自非代码所有者。这种开放性,是质量在无需对每一行设关卡的情况下仍能保持的重要原因。
改弦更张
有了代理,启动新工作很便宜,但有时你不该启动。典型情况是:频道里有人指出拟议改动是无效路径(引用既往决策,或提出更好路径),作者要么关掉 PR,要么改实现。
因为一开始写代码就很容易,关掉 PR 也不会觉得像损失。关键是在讨论串早期就转向,而不是等到最终版 PR 再甩一条拦截评论。
如何落地
这套方法的大多数组件,你的团队已经可以用上。
Pull request 之前
- 给代理一份它能跑的检查清单。把这些检查写进简短的 CLAUDE.md
- 配置代理通过 hooks 调用格式化工具与 linter
- 本地跑
/code-review与/security-review,或让一个全新上下文的子代理审查改动 - 创建 REVIEW.md,用来跟踪反复出现的审查问题
每一个 pull request
- 强制执行 CI
- 在 PR 模板中加入「Testing」「Risk」和「How to revert」
- 先在一个仓库加上 AI 审查员(Code Review for Claude Code,或 Claude Code GitHub Action),用几周迭代你的 REVIEW.md,再推广到更多仓库。
- 加上自动化安全审查
- 要求合并前解决所有审查讨论串
- 按风险决定审查严格程度:常规改动快速过一遍,高风险区域(bug 代价高)做彻底审查。Code Review 有 Quick、Standard 和 Deep 级别。
- 限制审查轮次,几轮之后只审查新的 diff。
审批
- 定义风险级别,按改动设定,不按作者。先严后松,有证据再逐步放宽。
- 把宽松审批路径留给可信作者。
- Bot 的批准不能用来满足必需的审批。有新 commit 推入时,撤销既有批准。
- 指定人作为审批者,负责控制认证、计费、CI、发布工作流以及安装器的代码与策略。用 CODEOWNERS 和分支保护来落实。
合并与合并后
- 搭建合并队列
- 尝试功能开关
- 先对内部用户发布
- 分阶段推出
- 建立一键回滚机制
- 通过记录事故与回滚来构建评估集
- 只要改了审查员的提示词、工具或模型,就重新打分
- 跟踪人力投入,用回滚与事故率作护栏
走向何方
Code Review 发布时的意图是:最终审批决定仍由人来做。产品所做的只是贴出发现。但在我们自己的仓库里,我们走得更远:所有者正在决定哪些低风险改动可以在自动化检查通过后自动合并。这条边界还会继续演化。
所以每当审查员漏掉了什么,我们就问自己:模型上下文里缺了什么,然后把它变成 CLAUDE.md、一个 skill 或一项新检查。我们的目标没有变:降低每次改动的人力投入,同时把回滚率维持在不高于现在的水平。
如果你也允许代理创建 pull request,请告诉我们你自动化了哪些检查、哪些仍需要人,以及我们哪里做得不对。
对我们原文的改写文章,并用 Pangram 做过检查。
