几个月前,我在审核一个新增了三个API端点的拉取请求。代码差异部分非常清晰,测试也通过了,生成该请求的脚本甚至还编写了合理的授权检查逻辑。按照我通常依赖的所有标准来看,这个请求完全可以直接合并到代码库中。
然而问题直到我发现该脚本使用了哪种认证中间件时才显现出来。我们的代码库中实际上存在两种认证中间件:一种是基于MongoDB的v1版本,另一种则是基于MySQL的v2版本,而我们在前一个季度一直在努力完成这两种系统的迁移工作。
按照计划,新的API端点应该使用v2版本的认证中间件,但该脚本却对所有三个端点都使用了v1版本。测试之所以能通过,是因为用户记录仍然存在于这两个数据库中(这正是进行系统迁移的目的),而v1版本的认证中间件也能正常完成对这些记录的认证工作。所以代码表面上看是能够运行的,但实际上,我们发布的每一个新端点都在继续使用那些我们原本试图在几个月内淘汰掉的旧版认证机制。
我在第二次审阅时发现了这个问题。在工程师修改错误并重新提交请求后的20分钟内,这个问题就已经得到了解决。如果第三位审核人员来审阅这个请求,很可能就会忽略这个错误。因为关于系统迁移的时间安排信息记录在六个月前的一条Slack讨论记录中,而“新端点应使用v2版本”这一规定也只存在于我的记忆中罢了。
这种问题的发现过程,其实反映了人工智能技术如何逐渐改变了我的工作方式。代码自动生成的速度变快了,但我的审核工作量却反而增加了。最棘手的那些审核案例,往往是那些表面上看上去没有任何问题的请求,而真正的问题往往隐藏在团队共同的记忆中,而不是体现在代码差异部分。
这本手册记录了我们为了解决这些问题所采取的措施。它讲述了我们是如何从被一堆看起来毫无问题的拉取请求淹没,逐渐发展到使用定制的人工智能工具来帮助审核这些请求的过程——这种工具能够在任何人介入之前就发现其中的大部分错误。最终证明,解决这个问题的关键并不在于购买更先进的工具,而在于将团队共同的记忆转化为人工智能能够理解的形式。
无论你的团队使用的是Claude Code、Cursor、Cline、GitHub Copilot,还是其他任何工具组合,这些经验都是值得借鉴的。在这里,工具本身的重要性其实不如相应的组织结构和流程重要得多。
目录
-
所使用的技术栈(编程语言、开发框架、包管理工具)
-
项目结构,尤其是对于我们的单仓库项目来说这一点尤为重要
-
共享的工具、组件和辅助功能的存放位置,以及新代码在创建新版本之前应优先重用这些资源的原则
- 该项目遵循的架构模式,并附上相应的文件路径示例
- 应该避免出现的错误做法,以及替代方案
- 测试规范及相关的优秀范例
- 当需要更多详细信息时,可以参考哪些更深入的文档资料
-
该服务的架构结构(例如四层架构模型、目录布局等)
-
该服务特有的命名规范
-
测试流程以及相关的优秀示例
-
该服务所遵循的业务规则
-
其他服务与该服务之间的交互机制
-
指向`docs/`目录下更详细文档的链接
-
“经验总结”部分,我会在后续关于循环结构的内容中再次提到这一点
旧的瓶颈,以及人工智能带来的改变
要理解为什么需要这种改进措施,先回顾一下几年前代码审核的工作流程会有所帮助。
那时,审核流程中最耗时的环节发生在提交合并请求之前。当一个任务被提交后,在有人能够开始处理之前,首先需要花费大量时间来收集相关背景信息。
初级工程师需要时间来理解这些变更的具体目的;而高级工程师则必须解释业务规则和架构设计决策。这些任务会在“待处理”状态中停留好几天,直到有具备相应知识的人能够开始处理它们。而且编写代码本身也需要花费时间——因为直接编写代码的速度,显然比撰写注释要慢得多。
当团队开始认真运用人工智能辅助开发工具后,这一瓶颈在很大程度上得到了缓解。工程师们可以利用这些工具来阅读代码库、提出疑问、制定实施计划,并且能在几小时内就创建出一个可运行的分支。这样一来,任务的处理速度大大提高了。初级工程师也能更快地完成工作,而不会因为等待高级工程师的空闲时间而耽误进度。从表面上看,这似乎是一个显而易见的胜利。
但实际上,这个瓶颈并没有消失,只是发生了转移。
在人工智能被广泛应用的几周内,我的代码审核任务数量翻了一番,随后又增加了一倍。工程师们提交合并请求的速度快得让我根本来不及阅读它们。
这些合并请求本身的格式都很规范:变量命名合理、测试通过率也很高,而且由人工智能生成的描述文字比大多数人工编写的描述还要清晰易懂。
表面上看,这似乎是一件好事。但实际上,它却带来了另一种麻烦。作为熟悉哪些代码模式是重要的、哪些开发路径才是正确的资深工程师,我反而成了这个流程中的瓶颈。整个团队的工作效率现在被我的阅读速度所限制了。
CircleCI发布的2026年软件交付状况报告证实,我并不是个特例。该报告基于超过22,000家机构的2800多万次持续集成工作流程数据,指出功能分支的处理效率同比增加了59%,这一增幅是CircleCI有记录以来最大的。然而在同一时期,对于大多数团队来说,主代码分支的实际交付效率却下降了7%;代码构建的成功率也降到了70.8%,这是五年来最低的水平。
这种现象在整个行业都是普遍存在的。人工智能加快了代码编写的速度,但系统的其他部分则不得不承担由此带来的额外负担。
因此,作为技术负责人,我面临的一个具体问题就是:如何在不降低工作标准的前提下,解决这个瓶颈问题呢?
新的代码审核流程实际是怎样的
在解释具体的改进措施之前,先了解一下当时究竟有哪些问题在不断累积会很有帮助。这些问题并不严重,也不会导致系统出现故障。它们都是一些小问题、反复出现的问题,乍看之下似乎也挺合理。
就拿我最常遇到的一个例子来说吧:有时候会有工程师要求人工智能工具在新页面上添加一个删除按钮,而这个按钮需要调用我们现有的后端删除接口。然而,这些工具并没有重用团队已经为该接口准备好的处理逻辑,而是直接编写了相应的代码来实现这个功能。
代码运行正常,测试也通过了。但一周后,当有人改变了后端响应的结构时,只有两个调用点中的一个得到了更新。
这种重复性在代码审查中往往不会被发现,除非审查者恰好记得存在这样的代码段。
我还经常看到另一个例子:某个开发人员直接将状态字段与字面字符串"completed"进行比较,而没有使用其他服务所使用的Status_completed枚举类型。代码可以正常运行,测试也能通过,但在后续对枚举类型的重构中,这个错误被忽略了。几天后,人们会花半天的时间去调试那个状态机,而其实这个问题本来是可以轻易解决的。
这些错误一旦被发现,只需要两分钟就能修复,但每次在审查代码时,我发现发现它们都需要花费一定的时间。问题不在于修复的难度,而在于这种重复性。
这种模式在更复杂的问题中也会出现。
有一次,我让某个开发人员制作一个事件创建向导。这个向导需要几个下拉列表和一个新的组件。
我们有一个专门存放共享UI组件的文件夹,团队也有一个简单的规则:先在这个文件夹里查找所需的组件,如果需要新建组件,也要将其注册到那里。
但那个开发人员并不知道这个规定,他只加载了向导本身的文件,因此从未打开过那个共享组件文件夹。结果他直接生成了新的下拉列表,使用的API与我们已有的API几乎完全相同;新组件也被直接添加到了向导中,而没有被放入共享组件文件夹里。代码编译通过,向导也能正常使用,但我们是在人工审查时才发现这种重复性的问题的——而这完全取决于某个知道这个共享组件文件夹存在的审查者。
在我查看的一个后端架构仓库中,也出现了同样的问题。后端架构遵循严格的四层结构:路由层、控制器层、应用层和数据存储层。控制器绝对不能直接调用数据存储层的函数,这一规则能够确保权限控制机制的集中性、业务逻辑的可测试性,以及数据库相关问题的独立性。
有一次我审查了一个代码提交,发现开发人员直接从控制器层调用了数据存储层的函数,完全跳过了应用层。代码可以运行,测试也能通过,因为开发人员也为这种新的调用方式编写了测试用例。但这种做法破坏了团队多年来建立起来的规范。如果这个代码提交被接受了,后续的AI辅助代码审查工具可能会将其作为模板来使用,从而导致整个架构层次结构的混乱。
这些错误的共同点在于:所有这些问题其实都有相应的记录,要么存在于代码中,要么记载在Slack聊天记录里,要么被某位资深工程师记在脑子里——这些信息本来是可以防止这些错误发生的。问题就在于开发人员没有看到这些信息。
为什么我没有直接购买工具来解决问题
显然,下一个可行的解决办法就是使用那些在2026年市场上大量出现的AI辅助代码审查工具。我对比了几种工具。Anthropic在2026年3月推出了Claude Code Review,该服务的收费依据是用户使用的代币数量,平均每项代码审核服务需要15到25个代币。CodeRabbit Pro提供年度订阅服务,每位开发者的每月费用为24美元;或者也提供按月订阅服务,此时每位开发者的每月费用为30美元,不过这些费用是针对那些真正提交了代码审查请求的开发者而言的。Greptile在2026年3月改用了按使用量计费的模式,每个账户每月的费用为30美元,其中包含50次代码审核服务;超过这个数量后,每次额外的代码审核服务需要额外支付1美元。GitHub宣布,所有Copilot套餐都将在2026年6月1日转为按使用量计费的模式,从那天起,进行代码审核时既会消耗AI信用点数,也会消耗GitHub Actions的运行时间。
对于一个规模较小、提交代码的数量不多的团队来说,这些因素中的任何一个都不会成为决定性障碍。但对于那些进行大量人工智能辅助开发的较大团队而言,这些成本会迅速累积。例如,一个由10人组成的团队,如果每个人每天都要提交5次代码审查请求,那么他们在一周内就会消耗完Greptile所提供的免费审核服务。CodeRabbit Pro每名开发者需支付24美元的费用,其费用与开发者的数量呈线性增长;而高级版的Claude Code Review则按每次代码审查请求收取15到25美元的费用,按每次审查计算的话,这是最昂贵的选择。
虽然我仔细研究了这些工具的成本,但实际上成本并不是决定性因素。真正的问题在于:这些工具根本无法发现我刚才列举的那些问题。
普通的审核人员是无法发现v1/v2中间件的问题的,因为他们根本不知道v2才是正确的实现路径;普通的审核人员也无法发现重复出现的下拉菜单问题,因为他们不了解我们的设计规范;同样的,他们也无法发现那些被绕过的架构设计,因为他们不清楚控制器绝对不能直接调用代码库中的功能。
只有那些能够让审核人员识别出这些问题信息,才能真正帮助他们完成工作——而这些信息其实存在于团队成员的脑海中,而不是任何工具的默认提示中。
评价较高的工具都支持自定义规则设置,正是这一点让我开始意识到问题的本质。一旦你开始配置这些自定义规则,你就意味着你已经认同了“规则才是真正的价值所在”,而工具本身只不过是用来执行这些规则的工具罢了。
这就引出了另一个问题:如果规则本身就是产品的核心组成部分,那么为什么还要为使用这些规则的工具按座位数或按每次审查请求来付费呢?
正是这个想法让我改变了思考方向。
领悟:将规则直接融入代码库
一旦我开始把规则视为产品的核心组成部分,前进的道路就变得清晰起来了。
我问了自己一个简单的问题:在代码审查过程中,我究竟在做些什么,而人工智能却无法做到呢?答案其实是相同的——每一次,我都在编写那些记录了团队知识经验的评论。
“请使用Status枚举类型,而不是字符串字面量。”“在/hooks/useDeleteItem中已经有了处理这个功能的钩子。”“控制器绝对不能直接从代码库层导入功能,应该通过应用层来处理这些请求。”“在创建新组件之前,请先查看设计系统文件夹。”
所有这些评论其实都包含着团队成员的知识积累,而它们都是通过一次次的代码审查请求才被记录到代码库中的。然而,下次当人工智能生成类似的代码审查请求时,它却无法获取这些信息。
因此,解决问题的方法并不是购买更智能的审核工具,而是应该把这些规则明确地写下来,让团队中的每一位成员在开始任何代码审查之前都能看到这些规则。
如果我在三份不同的代码审查请求中都写了“请使用枚举类型”,那么这个规则就应该被人工智能所掌握;如果我第四次提到了设计系统文件夹,那这也应该被视为一条规则;同样,如果我在评论中两次解释了四层架构的设计原则,这同样也是一条规则。
<我需要一个地方来存放这些规则。事实上,做出这个决定比我预想的要困难一些。>
两个改变了一切的文件:AGENTS.md和CLAUDE.md
如果你开始研究如何为人工智能代理提供持续的项目上下文信息,几乎会立刻遇到两种相互竞争的做法。
第一种是AGENTS.md,这是一种已经获得了广泛发展的开放标准。根据InfoQ的报告,到2025年年中,已经有超过20,000个GitHub仓库采用了这种格式,它被视作对传统文档的补充——一种机器可读取的上下文信息,与像README.md这样的面向人类的文档共同存在。
该标准的相关网站显示,目前已有超过60,000个开源项目在使用这一格式,而且该标准的维护工作现在由隶属于Linux Foundation的Agentic AI基金会负责。OpenAI Codex、GitHub Copilot、Google Gemini、Cursor以及Windsurf等工具也都支持这种格式。
第二种是CLAUDE.md,这是Anthropic为Claude Code制定的文档格式。Claude Code的文档中描述了两种互补的记忆系统:一种是你自己编写用于存储持续上下文信息的CLAUDE.md文件,另一种则是自动记忆机制,该机制能够让Claude记录下自己在修改代码过程中观察到的规律和注意事项。默认情况下,Claude Code会读取CLAUDE.md文件,而不会读取AGENTS.md文件。
这种分歧对我们来说非常重要,因为团队中有一半的人使用Claude Code,另一半人则使用Cursor。我们面临两个实际的选择:要么保持这两个文件的内容完全一致(从而避免重复),要么将其中一个文件的路径设置为另一个文件的符号链接,这样两种系统就能引用同一个信息源。最终我们选择了后者,因为这样可以减少出错的可能性。
接下来要考虑的问题是,到底应该在这些文件中写入哪些内容。经过几次尝试后,我们确定了以下内容结构:可以将这些文件视为为那些从未接触过代码、也没有看过任何Slack讨论记录的新工程师准备的简报文档。最低限度需要包含以下信息:
在开始使用这些文件后的第一个月里,我们总结出了两条实用的原则:
保持文件内容简洁:过长的指令列表反而会导致一些反直觉的问题:代理程序不会只是跳过文件末尾的新内容,而是会降低对所有内容的关注程度。因此,应该尽量让文件保持简洁,如果某个部分的描述超过了简短的几段文字,就应该将其单独放在另一个文档中,并通过链接的方式引用它。
规则应被视作强制性的要求,而非可追求的目标: “控制器不得直接调用数据存储层,所有请求都必须通过应用层进行处理”这一规定显然比“尽量简化控制器的结构”更为有效。前者是可以被验证其正确性的,而后者则仅仅是一种建议而已。
这就是我们的起点。但对于一个包含多个服务和前端的应用程序来说,仅使用一个根目录级别的文件显然是不够的,因此我们不得不做出下一个决定。
各服务对应的配置文件的作用
如果在一个单体仓库的根目录下只放置一个《AGENTS.md》文件,那么这个文件很快就会因为内容过于冗长而变得难以管理。我们代码库中的每个服务都有自己独特的架构、编码规范和业务规则,试图将所有这些信息都整合到同一个文件中,最终会导致文件内容过长,而代理工具也会将这些内容视为无用的背景信息,从而再次引发之前提到的文件臃肿问题。
最终我们采用了这样的解决方案:每个服务或应用程序都在其根目录下拥有自己的《AGENTS.md》文件,而项目级别的《AGENTS.md》文件则充当一个索引,用来链接这些服务对应的配置文件。
每个服务对应的《AGENTS.md》文件会包含以下内容:
同样的简洁原则依然适用:文件内容要简短明了,要提供具体的示例,并将指导性建议表述得像命令一样直接。
这种机制之所以有效,是因为代理工具会自动加载与当前任务相关的配置文件。当工程师要求代理工具修改`backend/`目录下的某个文件时,代理工具会先读取项目级别的《AGENTS.md》文件,然后知道应该使用`backend/AGENTS.md`文件来指导相应的操作,从而加载该文件;而不会去加载前端服务的《AGENTS.md》文件,因为那部分内容与当前任务无关。这样一来,上下文窗口始终会聚焦在相关的内容上。
如果不采用这种分层结构,就会面临两个糟糕的选择:要么把所有内容都放在根目录下的一个文件中,但这样代理工具大部分内容都会忽略;要么根本不在根目录下放置任何配置文件,但这样的话代理工具就完全无法了解各个服务的具体需求。而采用服务分级结构,既能保证信息的完整性,又能确保代理工具能够准确理解所需操作的内容。
不过,这些配置文件只有在其所链接的详细文档确实存在的情况下才能发挥作用,而这正是系统中接下来要讨论的部分。
这些文件在磁盘上的存储结构
在继续讲解之前,先了解一下整个系统的整体结构会很有帮助。以下是我们最终确定的单体仓库的结构框架。文件夹的命名遵循Claude Code的规范:如果使用Cursor工具,文件夹名为`.cursor/`;如果使用Cline工具,则为`.clinerules`——不过这两种命名规则所对应的文件结构是完全相同的。
project-root/
├── AGENTS.md # 指向CLAUEMD的符号链接
├── CLAUDE.md # 核心配置文件
├── README.md # 供人类用户阅读的项目说明文档
│
├── .claude/ # 与特定工具相关的配置文件夹
│ ├── README.md # 介绍 `.claude/` 文件夹的结构
│ ├── settings.json # 配置权限及安全规则
│ ├── agents/ # 专用子代理程序(可选)
│ ├── commands/ # 工程师使用的命令行工具
│ │ ├── review-pr.md # 用于代码审查的命令
│ │ └── plan-feature.md # 实施计划制定相关命令
│ ├── hooks/ # 生命周期管理钩子(可选)
│ ├── pr-rules/ # 代码审查规则文件
│ │ ├── common.md | 适用于所有代码提交的通用规则
│ │ ├── frontend.md | 前端开发相关规则
│ │ ├── backend.md | 后端开发相关规则
│ │ ├── service-a.md | service-a服务的相关规则
│ │ └── service-b.md | service-b服务的相关规则
│ └── skills/ # 可复用的工作流程模板
│
├── frontend/
│ ├── AGENTS.md # 前端开发规范文件
│ ├── docs/
│ │ ├── overview.md
│ │ ├── architecture.md | 系统架构说明
│ │ ├── design-system.md | 设计系统参考资料
│ │ └── testing.md | 测试相关规范
│ └── src/
│
├── backend/
│ ├── AGENTS.md # 应用的四层架构模式
│ ├── docs/
│ │ ├── overview.md
│ │ ├── architecture.md | 路由处理、控制器、应用层及数据存储层的结构
│ │ ├── auth.md | 用户认证中间件相关规则
│ │ └── business-rules.md | 业务逻辑规则
│ └── integrations.md | 系统集成相关内容
│ └── src/
│
├── service-a/
│ ├── AGENTS.md
│ ├── docs/
│ │ ├── overview.md
│ │ ├── business-rules.md | service-a服务的相关规则
│ │ └── integrations.md | 系统集成相关内容
│ └── src/
│
└── service-b/
├── AGENTS.md
├── docs/
│ ├── overview.md
│ ├── business-rules.md | service-b服务的相关规则
│ └── integrations.md | 系统集成相关内容
└── src/
有几点需要特别说明:
.claude/文件夹采用了标准的子文件夹命名规则:commands、agents、hooks、skills。这些命名方式遵循Claude Code的插件模型,而大多数现代AI开发工具也采用类似的结构。遵守这些规范可以让团队中的任何人都能理解文件结构,从而降低日后更换开发工具时可能遇到的麻烦。
pr-rules/文件夹并不符合标准的命名规则。我们创建这个文件夹是为了存放针对特定区域的审查规则,以便PR审核功能能够根据需要选择性地加载这些规则。其实这个文件夹的名字并不重要,关键是要确保所有审查规则都能被集中保存在一个地方。
AGENTS.md文件以及docs/文件夹是每个服务都必备的。根目录下的AGENTS.md文件内容简短,主要起到索引的作用——它会告诉相关组件:“如果你要修改backend/目录中的文件,请先阅读backend/AGENTS.md。”而针对具体服务的文档则会根据需要进一步引用这些详细信息。
作为副产品生成的文档
在为每个服务编写AGENTS.md文件的过程中,我发现了一个一直被我回避的问题:我们大多数服务的文档都很不完善。这里说的不是API参考资料(那些信息本来就存在于代码中),而是关于“这个服务具体做什么、遵循哪些业务规则、输入什么数据、输出什么结果”这类高层次的信息——这些信息除了原始开发者之外,几乎没有人能够准确掌握。
说实话,手工编写这类文档从来都不值得花费那么多时间。等到文档写完的时候,其中一半的内容就已经过时了。
于是我尝试了一种之前从未考虑过的方法:利用AI技术为每个服务生成初稿。我让AI系统阅读相应服务的代码,并要求它生成结构规范的docs/文件夹,其中应包括概述、业务规则列表、集成说明、领域模型以及任何需要特别说明的特殊细节。AI系统会读取代码、追踪函数调用路径,然后生成初稿。
之后我会手动审核这些初稿,纠正其中出现的错误,并将最终版本提交到代码库中。最初的几份初稿的正确率大约在70%到80%之间,剩下的20%到30%则是AI系统做出了看似合理但实际上错误的推断,而正是这些地方需要人工审核来确保准确性。
生成的文档实际上服务于两个群体:一方面,AI系统在处理代码变更时会参考这些文档,这样它就能准确了解所修改服务的具体功能,而不会仅凭本地文件进行猜测;另一方面,新员工在入职第一天就会使用这些文档,这大大缩短了他们的培训时间。
过去我们编写的手册往往会在几个月内就过时了,但现在利用AI生成的文档能更好地保持时效性。因为每次有新的PR提交时,AI系统都会重新阅读这些文档,如果其中的内容已经过时,AI系统就会给出错误的建议,从而及时暴露问题。
有效的做法是保持每个服务对应的《agents.md》文件简短,并让其指向相关文档,而不是重复这些文档的内容。《agents.md》文件是一个会被始终加载的索引文件,而`docs/`目录中则存放着具体的详细信息。当任务需要时,代理会根据需求自动加载相应的文档。
既然规则和文档都已经准备好了,那么我就可以开始构建实际的评审工具了。
构建PR评审工具
这个工具直接解决了我工作中遇到的诸多阻碍。
这个命令并不是凭空出现的。它最初只是我在每次查看PR时在脑海中列出的检查清单。我会手动审查每一处变更,留下相同的评论,标记出相同的问题模式。后来,我把这份清单写下来,并参考了各服务相关的文档,对其中较为复杂的规则进行了补充,最终将其发展成了一个团队中的任何人都可以使用的工具。
之后,我将这个工具交给了工程师们,并修改了相关规则:要求他们在将PR标记为“可供评审”之前,先在自己的分支上运行这个工具进行检查。这一改变使得工作流程从PR提交后的环节提前到了提交前。现在,工程师们可以在自己的机器上发现90%到95%的潜在问题、需要改进的地方以及一些有用的功能,他们会先在本地解决这些问题,然后再将修改内容推送到代码仓库中。
PR描述中包含了人工智能生成的总结信息,因此当有人打开PR时,他们甚至在阅读差异对比内容之前,就能看到评审工具给出的“通过”提示。
这样一来,GitHub的代码库就保持得非常整洁了。人们在PR讨论中只会探讨那些确实需要人工处理的问题,而那些团队已经知道如何解决的重复性问题就不会被再次提及。
这个工具的脚本保存在.claude/commands/review-pr.md文件中。下面是一个通用版本的脚本格式。虽然你们使用的工具可能具有不同的命令结构,但核心逻辑是相同的。
# 审核PR
审核当前分支中的PR。请直接说明问题,务必引用具体的文件行号。对于真正存在的问题,请如实指出,不要添加无关内容。
## 1. 查看差异对比结果
按以下顺序执行命令:
gh pr view --json number,title,body,headRefName 2>/dev/null || true
git fetch origin main
git log --no-merges origin/main..HEAD --oneline
git diff origin/main...HEAD --stat
git diff origin/main...HEAD
阅读PR的描述内容,注意其中提到的修改目的。所有的变更都应该与这个目的相符。如果发现有任何变更不符合修改目的,请将其标记出来。
在差异对比时使用“…”,这样脚本会将与合并基准分支相比的结果显示出来,同时排除因合并主分支而引入的变更。
## 2. 查阅规则文件
务必先阅读`.claude/pr-rules/common.md`文件,然后再查看PR中涉及的各个工作区对应的规则文件:
| 工作区路径 | 规则文件 |
| -----------------| ------------------------------- |
| `frontend/**` | `.claude/pr-rules/frontend.md` |
| `backend/**` | `.claude/pr-rules/backend.md` |
| `service-a/**` | `.claude/pr-rules/service-a.md` |
| `service-b/**` | `.claude/pr-rules/service-b.md` |
对于较为复杂的变更,请参考规则文件中提供的文档链接(例如`backend/AGENTS.md`、`backend/docs/architecture.md`)。
将规则文件中“经验总结”部分列出的所有检查项都执行一遍。
## 3. 输出结果
请使用以下格式输出结果:
## 总结
该PR具体做了什么,是否符合修改目的>
## 阻碍因素
- [文件行号]:存在的问题及其原因
## 需要修改的内容
- [文件行号]:需要修复的问题
## 可以考虑添加的功能
- 其他值得注意的问题
## 已验证的事项
- 已经检查过的内容,确认没有问题
如果没有任何阻碍因素,就直接说明这一点。不要无端制造问题。
如果你发现某个问题在未来处理PR时可能会再次出现,建议将这个注意事项添加到相关规则文件的“经验总结”部分中。请不要自行修改规则文件,这些工作应该由人工来完成。
在这个系统中,某些设计决策的重要性超出了我的预期。
这种结构化的输出格式(摘要、存在的障碍、需要解决的问题、有用的功能、已验证的内容)使得审核过程更加便于阅读,也便于将审核结果复制到Pull Request的描述中。在这五种信息中,“已验证”这一项往往被忽视:它告诉人工审核者人工智能已经检查了哪些内容,这样他们就可以把注意力集中在其他需要审核的地方。如果没有这一项,人工审核者就会重复进行同样的检查。
要求人工智能的反馈要直接、避免冗余的信息这一点确实非常有效。如果不规定这一点,人工智能生成的审核结果往往会显得过于繁琐,从而让工程师们认为这些结果并不值得重视,进而忽略这些自动生成的审核提示。而明确要求人工智能在没有发现障碍时说明“没有障碍存在”,确实大大提高了输出信息的实用价值。
最后一条“建议为规则文件添加条目”这一指令是整个系统的核心所在,我会在讨论循环优化机制的部分详细解释其原因。这里的关键在于:人工智能只是提出建议,最终是否采纳这些建议仍由人工审核者来决定。只有当人工审核者认为这些建议具有普遍性、适合被纳入规则文件时,才会将其添加进去。这个人工审核的环节正是确保规则文件内容精炼、避免冗余的关键。
对于每一个Pull Request来说,无论是人类手动修复了某些问题,还是人工智能提出了建议,这些信息都会被记录到MD文件中,从而帮助我们不断优化未来的自动化审核系统。这样的改进效果会迅速累积起来。
还有一点需要说明:所有用于查看代码差异的命令都只具有读取权限。这些命令不应该具备提交修改、编辑Pull Request或关闭任何操作的功能。这也是该系统的另一个重要组成部分。
安全限制:默认仅限读取权限
如果给人工智能系统过多的访问代码库的权限,就会带来安全隐患。即使你相信这个模型会按照预期行事,但大型语言模型偶尔也会出现不可预测的行为,而一个在无限制环境下运行的自动化审核工具,可能在短短几秒钟内造成严重的破坏。
为了解决这个问题,我们可以在`.claude/`目录下的`settings.json`文件中明确指定人工智能系统可以执行哪些操作、不能执行哪些操作。在这里,禁止列表比允许列表更为重要,一个合理的禁止列表应该根据四类风险来进行制定。
第一类风险是与敏感信息及配置文件相关的操作。任何试图读取这些文件的尝试都会被阻止。这包括所有版本的`.env`文件、《npmrc》文件、《netrc》文件、《pgpass》文件、`id_rsa`文件、`id_ed25519`文件、所有的`.pem`文件、`.key`文件、`.p12`文件,以及`**/credentials.json`文件、`**/secrets.json`文件、`**/.aws/**`文件夹、`**/.ssh/**`文件夹、`**/.gcloud/**`文件夹和`**/.kube/**`文件夹。此外,所有用于输出环境变量的命令也会被阻止,例如`env`、`printenv`、`set`和`export`等命令。人工智能系统没有任何正当理由去读取或显示这些内容。
第二点是具有破坏性的Git操作。该代理可以读取Git历史记录,但无法对其进行修改或推送。被禁止的操作包括:git push、git commit、git revert、git cherry-pick、git merge、git rebase、git reset --hard、git tag。被允许的操作包括:git fetch、git status、git log、git diff、git show、git branch、git rev-parse、git merge-base、git config --get。
第三点是对PR和问题的修改操作。该代理可以查看你在GitHub上的相关状态,但无法对其进行任何操作。被禁止的操作包括:gh pr create、gh pr edit、gh pr merge、gh pr close、gh pr comment、gh pr review、gh issue create、gh issue edit、gh issue close、gh issue comment、gh release create、gh repo create、gh repo edit、gh repo delete。被允许的操作包括:gh pr view、gh pr list、gh pr diff、gh pr checks、gh issue view、gh issue list、gh release view。
第四点是工作流程与自动化控制相关功能。如果这些功能被恶意利用或被错误配置,那么代理可能会造成严重的破坏。被禁止的操作包括:gh workflow run、gh run rerun、gh run cancel、gh secret、gh variable、gh auth、gh ssh-key、gh gpg-key,以及不受限制的gh api。
对于那些代理确实需要执行的shell命令,比如构建和测试命令,我们可以允许特定的操作模式。例如:pnpm test、pnpm lint、pnpm format:check、pnpm build、pnpm vitest。任何不在允许列表中的命令都需要人工确认才能执行。这些设置都是你可以根据自身需求来调整的——我只是分享了我个人偏好的配置方式而已。
原则很简单:默认情况下,代理只具有读取权限;只有那些你明确批准的具体命令,它才被允许进行写入操作。该代理可以负责调查、规划并提供建议,但它无法直接执行任何修改操作。
在建立了这样的架构并设置了相应的限制之后,系统开始发挥作用了。让我没想到的是,在接下来的几个月里,它的效果竟然会变得如此显著。
带来真正改变的复合效应
在刚开始使用这个AI审核工具时,它确实有一定作用,但并没有产生颠覆性的影响。它能发现一些明显的问题,却也会遗漏很多细微的错误,同时还会产生不少干扰性信息。
第一个月,我负责审核的工作量减少了35%。用来检查PR的时间几乎减少到了原来的三分之一。这个效果还算不错,但并不能说彻底改变了我的工作方式。
随着时间的推移,真正发生变化的并不是这个工具本身,而是我们设定的规则和限制。
每当PR创建者或审核人员发现AI遗漏了某些问题时,我们就会在相关的规则文件中添加相应的条目。而每当AI指出某些有用的信息,而这些信息后来被证实属于反复出现的模式时,审核人员在审核结束后提出的建议也会被记录到该文件中。
几天后,这些规则文件已经包含了团队在评审过程中积累的许多有价值的信息,而这些信息都被记录在一个所有团队成员都会阅读的地方。
错误检测率提高了,不必要的评论也减少了,因为这些规则明确指出了哪些行为是可接受的,哪些问题已经被认为已经得到解决。新加入团队的工程师在提交他们的前三份代码审查请求时,不会再收到同样的反馈意见,因为人工智能系统会先识别出这些问题。新成员无需通过长达六个月的评审过程来逐渐了解这些规范,他们只需安装相关工具,在编辑器中打开项目文件,人工智能系统就会自动知道该怎么做。
这就是大多数团队在评估人工智能代码审查工具时所忽略的一点。他们只看当前的错误检测率,就决定这个工具是否值得购买。但实际上,当前的这个数字并不具有参考意义。真正有意义的数字应该是六个月后的数据——那时规则文件已经汇总了你们团队曾经犯过的所有重复性错误。
今天制定的一条规则虽然能节省少量的评审时间,但在处理上百份代码审查请求时,这种节省效果就会更加明显。一年后,这些规则文件实际上就成为了技术负责人多年实践经验的结晶。在这段时间里,我们先后使用过Claude Code、GitHub Copilot CLI以及Cursor等工具来完成不同的任务。虽然人工智能工具会不断更新,但仓库中的规则文件却始终保持不变。
让这一切得以顺利运作的关键在于将规则文件视为一种“动态文档”。任何重复出现的评审意见都应该被考虑纳入这些规则文件中。如果你发现自己会在两份不同的代码审查请求中重复编写同样的反馈内容,那么这条规则就应该被添加到`pr-rules/`目录里。评审命令中的“建议添加项目符号”这一选项使得这个过程变得可行:人工智能负责完成文本的生成工作,而人类则负责判断这些规则是否合适。
也正是这一点让我意识到,建立这样一个系统确实值得花费时间和精力。单凭代码审查命令本身来说,虽然有用但并不特别突出;真正让它发挥重要作用的关键在于这种循环反馈机制。
在现有项目的基础上从零开始构建
如果你读到了这里,并且认为你的项目与我所描述的内容之间还有很大的差距,那么这种想法是非常常见的。但实际上,这种看法并不正确。
一个空白的`AGENTS.md`文件可能会让人感到望而却步,尤其是在处理现有的代码库时。你知道自己的团队有一整套规范和习惯,因此编写上千条规则听起来像是一个需要花费数周时间才能见到成效的项目。
坦白地说,你不可能一开始就写出所有的规则,也不应该试图这么做。这些规则文件的第一个版本只需要花一个下午的时间来编写,而不需要进行长时间的迭代开发。
以下是我实际会采取的步骤:
运行`/init`命令(或者你的工具对应的命令)。在Claude Code中,这个命令会扫描整个项目,推断出该项目使用的语言、框架、入口点以及构建指令等基本信息,然后生成一个初始版本的`CLAUDE.md`文件。这个输出文件只是一个起点,并不是最终完成的版本。你需要阅读这个文件,删除其中大部分内容,只保留核心部分即可。
然后添加三条规则,每条规则都用项目符号来表示。
第一条是关于架构设计的规则。选择你们团队最重视、也严格执行的那条规范。对我们来说,那就是四层架构模式。相应的规则内容是:“控制器不得直接调用存储库函数,必须通过应用层进行处理。”
第二条规则是关于代码可被发现性的。确定团队中最重要的共享资源是什么,因为新代码很可能会重复使用这些资源。对我们而言,这个共享资源就是设计系统。所以规则是:“在创建新的UI组件之前,请先查看/src/design-system/目录。”
第三条规则则是“禁止修改某些文件”。找出代码库中风险最高的文件或模块——无论是与认证、计费相关的功能,还是涉及数据迁移的部分。相应的规则是:“未经人工批准,严禁修改/auth/目录下的文件。”
这样就可以开始了。只需制定三条规则,花十分钟时间把它们写下来,你团队中那些经常重复出现的错误就会大大减少。
如果觉得三条规则已经太多了,也可以从一条开始。选择代码库中非常重要但容易被忽视的某一点,然后把它写下来。例如:“在TypeScript中禁止使用any类型。” “始终使用枚举类型,而不要直接将字符串与枚举值进行比较。” “在提交拉取请求之前,先运行代码检查工具。” 这些规则不需要非常复杂,也不必涵盖所有边缘情况,只要能体现你目前心中所持有的某一条判断标准即可。
第二天再添加一条规则。第一周结束时,你可能会发现5%的重复性错误;等到收到了20到30个拉取请求后,这些错误的比例可能会上升到20%到30%。规则文件在最初创建时并不需要非常完善,只要它存在并不断得到补充和完善即可。
这就是所谓的“复利效应”——这也是为什么这种方法在实际项目中能够发挥作用,而不仅仅停留在理论层面。
随着时间的推移,这个规则文件会像任何团队都会经历的那样逐渐发展。每次通过代码审查发现的错误都可能成为新的规则内容。几周后,你就会拥有十条或十五条规则;几个月后,你就真正建立了一个完善的代码审查系统。
犯错的地方在于试图在第一天就编写出完美的规则文件。正确的做法应该是从一条简单的规则开始,然后不断对其进行修改和完善。
哪些内容仍需要人工审核?
这个系统并不能取代人工审核,也不应该被用来替代它。
人工智能审查工具能够捕捉到规则中规定的问题,同时也能发现很多显而易见的问题。但它无法处理那些需要根据具体上下文来判断的问题,也无法做出与产品开发策略相关的决策,更无法判断某项修改是否真的有必要进行。
在审核由人工智能生成的代码时,这个系统还存在一个重要的盲点:审查者所使用的训练数据和推理方式,与编写代码的智能体是完全相同的。如果原来的智能体因为无法查看数据迁移的时间线而忽略了版本之间的差异,那么阅读相同代码差异的人工智能审查工具也会遇到同样的问题。因此,在审核过程中使用两个人工智能工具,并不能等同于拥有两个独立的审查人员——它们仍然存在共同的盲点。
正因为如此,在这种设置中,人工智能审核工具永远不会批准任何拉取请求。它只会生成一份结构化的审核报告,并将其添加到拉取请求的描述中。最终还是由人类来阅读这些修改内容并决定是否批准这些更改。人工智能只是第一步审核工具,而不是最终的审批环节。
责任机制也必须由人类来承担。当人工智能批准的某些更改导致生产出现问题时,必须有人负责事后分析,并决定下次需要做出哪些改进。人工智能无法担任这个角色。不过,它确实可以减少人类审核人员在处理复杂问题之前需要先排查的那些小错误。
为期两周的设置计划
如果你想为自己的团队实施这套方案,以下是一个适合在几周内完成的详细计划。这些步骤并不需要一次性全部完成。
第1天:初始化内存文件
在项目根目录下运行/init命令(或你所使用工具的相应指令)。阅读生成的CLAUDE.md文件(或AGENTS.md文件),删除其中大部分内容,只保留与技术架构和项目结构相关的部分。
将前文提到的三条规则添加到这些文件中:一条关于架构设计的规则、一条关于代码可发现性的规则,以及一条“禁止修改”的规则。你可以选择同时保留这两个文件,或者创建一个符号链接来关联它们。
第2天:为高风险区域添加特定服务相关的配置文件
挑选代码库中变更频率最高或风险最大的两三个领域,为每个领域创建一个AGENTS.md文件,遵循相同的编写格式。文件中应包含该领域的架构设计规范、命名规则、可参考的测试案例链接,以及任何现有的文档资料。对于那些目前还不需要包含在内的内容,可以暂时忽略。
第3天:建立目录结构并设置安全防护机制
在项目根目录下创建一个.claude/文件夹(或你所使用工具对应的文件夹),并在其中设置commands/和pr-rules/两个子文件夹。编写一个settings.json文件,列出所有被禁止的操作内容。测试确保人工智能审核工具无法读取.env文件、无法执行git push命令,也无法提交拉取请求。如果发现有这些功能仍然可以正常使用,请先调整配置设置。
第4天:编写拉取请求审核脚本
根据你的项目结构,修改本文中提供的脚本。脚本中应包含差异对比的范围、规则加载方式、输出格式,以及最后一条“建议添加新规则”的提示信息。在已经合并过的分支上运行该脚本,不断调整输出内容,直到其能够满足实际使用需求。
第5天:在实际的拉取请求上测试该脚本
让一两名工程师在提交他们的拉取请求之前先运行这个脚本。仔细阅读输出结果,注意哪些错误被检测到了,哪些被遗漏了,以及哪些信息属于干扰性内容。将那些被遗漏的错误信息添加到规则文件中。第一周的主要工作就是进行各种调整和优化。
第2周:全面推广并编写文档
一旦该命令能够可靠地生成有用的输出,就请整个团队在提交拉取请求之前都运行它,并将输出结果粘贴到拉取请求的描述中。在你的贡献指南中添加一小节内容,解释这一工作流程。在团队的日常工作中安排一项定期任务,每月审查规则文件,删除那些已经过时的内容。
这样,你就建立了一个可正常运行的系统。此后,系统的维护工作就是逐步进行的:每一条经过审查的评论都可能成为新的规则;每一个架构决策都可能需要更新相关的《AGENTS.md》文件。随着团队日常工作的进行,这个系统会不断得到改进。
哪些方面已经见效,哪些还需要继续改进
经过几个月的实践,我给出了以下诚实的评估:
已经取得成效的地方
我的审查工作负担明显减轻了。工程师们会在我看到拉取请求之前就纠正大多数容易出现的错误。人工智能输出结果中的“已验证”部分会告诉我哪些内容可以跳过不看。新加入的工程师也能更快地适应工作,因为各种规范都存储在他们的工具能够读取的地方。规则文件也已经发展成了我可以用来帮助新员工快速入门的实用资源。
尚未完成的部分
人工智能仍然会忽略那些需要结合具体上下文才能判断的问题,而现有的规则也无法覆盖这些情况。规则文件虽然不断扩充,但也需要定期进行整理和优化,而我们目前在这方面还没有建立起严格的习惯。
我们仍在探索如何处理那些只有在特定条件下才适用的规则。在这种情况下,文档确实能起到帮助作用,但我们必须确保这些文档始终保持最新状态。而且,没有任何系统能够抵挡住那些在赶时间时忽视工作流程或文档的坚决执行者。
这里没有捷径可走。这项工作是真实存在的、需要持续进行的,而关键在于自律——要把你的代码库当作人工智能需要学习的对象,把每一次审查评论都看作是一次应该被记录下来的机会,而不是重复输入三十次同样的内容。如果你愿意这样做,其余的工作就交由工具来完成吧。
如果要从这篇文章中汲取三点启示,那就是:
-
首先,不要雇佣普通的审核人员来处理你的代码库所需要解决的问题。普通审核人员只能发现一些普遍存在的问题,而你真正需要的审查工作往往与你的团队具体情况密切相关。
-
其次,把规则保存在人工智能能够读取的文件中,而不是记在人们的脑子里。《AGENTS.md》、《CLAUDE.md》,或者为不同服务、不同领域制定的专门规则文件——选好一种结构并严格遵守它。
-
第三,要把每一次人工审核中发现的问题都视为更新规则的机会。几个月下来,这种累积效应才是最重要的。一个能够自我完善的审查系统,其价值远超过任何单一的工具。
这就是我们所建立的系统。建立基础花了几周时间,而规则的完善则花费了几个月的时间。运行这个系统的成本非常低廉,但它对我们提高拉取请求的处理效率所起的作用,远远超过了我评估过的任何其他工具。
资料来源
-
CircleCI发布的2026年软件交付状况报告,该报告分析了来自22,000多个组织的2800多万份持续集成工作流程数据:https://circleci.com/resources/2026-state-of-software-delivery/
-
CircleCI在博客中详细介绍了各项指标的年度变化情况,其中包括功能分支数量增长了59%,而主分支的数量则有所下降:https://circleci.com/blog/five-takeaways-2026-software-delivery-report/
-
GitHub宣布,Copilot将于2026年6月1日开始采用按使用量计费的模式:https://github.blog/news-insights/company-news/github-copilot-is-moving-to-usage-based-billing/
-
GitHub的变更日志确认,从2026年6月1日起,Copilot的代码审核功能将开始消耗GitHub Actions的资源:https://github.blog/changelog/2026-04-27-github-copilot-code-review-will-start-consuming-github_actions-minutes-on-june-1-2026/
-
AGENTS.md是这一开放标准的官方网站,其中介绍了该标准在Agentic AI基金会和Linux基金会的管理下是如何得到发展的:https://agents.md/
-
Anthropic的Claude代码相关文档,其中详细讲解了其内存管理系统的相关内容,包括CLAUDUE.md文件、自动内存管理功能以及/init命令的使用方法:https://code.claude.com/docs/en/memory
-
Anthropic关于如何使用GitHub Actions与Claude代码的文档,其中包含了有关基于令牌计费的说明以及一些成本控制建议:https://code.claude.com/docs/en/github_actions
-
CodeRabbit的定价文档,明确说明了其按开发者数量每月收费的模式:https://docs.coderabbit.ai/management/plans
-
Greptile在2026年3月发布的定价公告,介绍了新的计费模式:每名开发者每月需支付30美元的费用,其中包含50次代码审核服务:https://www.greptile.com/blog/greptile-v4
-
HumanLayer撰写的关于如何编写高质量的CLAUDUE.md文件的文章,其中还提供了有关代码执行效率下降问题的数据分析:https://www.humanlayer.dev/blog/writing-a-good-claude-md