AI 代码审查的五个判断维度
代码审查正在变成一个流程问题
半年前,我的代码审查方式还算稳定:打开 PR,看 diff,按经验判断。审查同事写的代码,问题通常出在逻辑遗漏或架构取舍上——这些可以靠经验补位。
但审查 AI 生成的 PR 之后,老办法不太好使了。AI 写出来的代码往往语法正确、结构清晰、注释工整,单看每一行都觉得「没毛病」。但合在一起跑,问题就冒出来了——漏改的文件、没处理的空值、绕过了项目封装层直接调 API。
我后来意识到,这不是审查能力的问题,是审查方式的问题。靠脑子里的经验清单去逐行看 AI 代码,效率低、容易漏,而且每次审查的关注点不一样。更靠谱的做法是:把审查规则写成可重复执行的规范,让每次审查走同一条路径。
换句话说,审查 AI 代码,需要的是一套可重复执行的 SOP,而非一组零散的注意点。
为什么凭经验看 PR 不够了
先说数据。GitClear 在 2025 年底发布了一项覆盖两亿多行代码变更的研究,发现 AI 辅助代码的代码克隆(duplicate code)增长了 4 倍,重构代码占比从 2021 年的 25% 降到不足 10%。[1] 代码复制量首次超过了代码迁移量。
Stack Overflow 2025 年开发者调查的数据更值得注意:84% 的开发者在使用 AI 工具,但只有 29% 信任它们——信任度比上年下降了 11 个百分点。[2] 用的人越来越多,信的人越来越少。
arXiv 在 2025 年底的一篇论文调查了 72 篇相关研究,给出了具体的缺陷分布:功能缺陷被讨论最多(56 篇提及),其次是语法错误(32 篇)和可靠性问题(21 篇),其中一项针对 GitHub Copilot 的实证研究发现约 40% 的 AI 生成代码包含安全漏洞。[3]
这些数据指向同一个问题:AI 生成的代码在表面上做得不错(语法、命名、格式),但在行为正确性、边界处理、安全意识和项目一致性上,需要更系统的审查方法。
靠经验逐行看 PR 的第一个问题是不可重复。同一个审查者,今天关注安全,明天关注性能,审查结果随状态波动。第二个问题是不可传递。一个人的经验清单无法直接交给团队里的其他人。第三个问题是不可扩展。当 AI 工具让 PR 数量翻倍时,人脑逐行审查会成为瓶颈。
InfoQ 在 2026 年 6 月的一篇报道中提到了 DoorDash 的经验:他们的 AI 审查系统必须「只给出可执行的建议,才能赢得信任,而不是制造噪音」。[4] 人对人也是一样——审查规范如果不聚焦、不可执行,审查者很快就会跳过它。
三层审查 SOP
经过多个项目的实践,我把 AI 代码审查拆成了三层。每层解决不同的问题,层与层之间有明确的输入输出关系。
规范层:把项目约束写成 AI 和人都能读的规则
这是最容易被忽视、也最有杠杆效应的一层。
Google 的工程实践文档把代码审查分成七个维度:Design、Functionality、Complexity、Tests、Naming、Comments、Style。[5] 这是一套通用标准,但它缺少项目特有的约束。比如,你的项目要求 API 业务逻辑放在 modules/ 而不是 routes/,要求单文件不超过 500 行,要求 Server Components 优先——这些规则如果只存在于团队负责人的脑子里,AI 不知道,新成员也不知道。
AGENTS.md 和 CLAUDE.md 是近两年兴起的开放标准,用来把项目约束写成 AI 编码代理可以读取的格式。截至 2026 年,超过 6 万个开源项目使用了 AGENTS.md。[6] 它的作用不只是指导 AI 写代码——更重要的是,它把审查标准从「人脑里的经验」变成了「可追溯、可执行的文档」。
在一个实际项目中,规范层通常包含这些内容:
| 规范类别 | 典型规则示例 | 审查时的作用 |
|---|---|---|
| 代码边界 | API 业务逻辑放 modules/ 不放 routes/ | 审查时按目录结构判断归属是否正确 |
| 文件约束 | 单文件不超过 500 行 | 审查时自动标记超标文件 |
| 框架约束 | React Server Components 优先 | 审查时检查 Client/Server 边界 |
| 测试策略 | 测试放 apps/tests/,营销页不写单测 | 审查时判断测试位置和覆盖范围 |
| 安全规则 | 用户输入必须净化,禁止 dangerouslySetInnerHTML 直渲 | 审查时重点检查数据流安全 |
Addy Osmani 在讨论如何为 AI 代理写好规格说明时提出了一个三层约束模型:[7]
- 常规安全操作(
Always):例如「提交前必须跑测试」。 - 需要人工确认的操作(
Ask):例如「修改数据库 schema 前必须询问」。 - 绝对禁止的操作(
Never):例如「永远不要提交密钥」。
这个分层思路同样适用于审查规范——不是所有规则都需要同等的审查力度。把约束分成「自动检查」「人工必查」「按需抽查」三级,审查效率会高很多。
流程层:让每个 PR 走同一条审查路径
有了规范,下一步是定义审查流程。
我在项目里用到的审查流程来自 review-code-review 这个 Skill(可以理解为一份可执行的审查 SOP)。它定义了审查的输入、顺序、严重级别和合并决策,让每次审查走同一条路径。
审查顺序按风险从高到低排列:
- 需求符合度:是否实现了该实现的内容,有无遗漏、越界和破坏性变更。
- 正确性:边界条件、错误路径、并发、异步、状态一致性。
- 安全性:认证授权、输入校验、注入、XSS、CSRF、敏感信息。
- 架构边界:目录归属、依赖方向、抽象必要性、API 契约。
- 测试与验证:测试是否覆盖高风险逻辑,验证命令是否匹配改动。
- 性能与可靠性:N+1、重复请求、内存泄漏、缓存、降级路径。
- 可维护性:复杂度、命名、可读性。
- 风格:只看工具无法自动处理且影响理解的问题。
这个顺序的关键设计是:从需求开始,从风格结束。大多数审查者习惯从命名和格式看起(因为容易看出问题),但 AI 代码在风格和命名上通常做得不错,花时间在上面的回报率很低。把注意力先放在高风险维度上,效率更高。
严重级别也需要明确定义,否则审查者和作者会在「这个问题到底要不要改」上反复拉锯:
| 级别 | 含义 | 对合并的影响 |
|---|---|---|
| Blocker | 安全漏洞、数据丢失、核心功能错误、构建失败 | 不能合并 |
| Major | 重要边界遗漏、错误处理不足、架构边界破坏 | 应在本次修复 |
| Minor | 可读性、局部可维护性、非阻塞性能优化 | 建议修复 |
| Nit | 命名、表达、风格偏好 | 可选微调 |
| Question | 需要作者解释意图 | 暂不当作结论 |
合并决策只有四种明确状态:Approved、Approved with follow-ups(可合并但需记录后续)、Changes requested、Needs context。不允许出现「没看完就写 LGTM」的情况。
danicat.dev 的一篇实践文章提出了一个值得采纳的原则:在 AI 时代,「代码是一次性的」,审查者应该只看提交本身的质量,而不是看它是谁写的。[8] 这意味着审查标准必须写在 PR 之外的文档里(AGENTS.md、审查 Skill),而不是依赖审查者当时的状态。
执行层:五维度审查 + AI 预筛
流程层定义了「按什么顺序看」,执行层解决「具体看什么」。
在规范层和流程层的基础上,我把执行层的注意力集中在五个维度。这五个维度来自对 AI 生成代码的风险特征的观察——它们是 AI 最容易出错、也最容易被「看起来可以」掩盖的领域。
| 维度 | 审查重点 | AI 常见表现 | 严重等级 |
|---|---|---|---|
| 行为正确性 | 用户可见行为是否符合需求 | 只改了列表页,没检查详情页和分类页 | 🔴 阻塞合并 |
| 边界条件 | 空数据、失败、非法输入是否处理 | 主路径顺畅,但空列表显示空白 | 🔴 阻塞合并 |
| 数据流 | 数据来源、转换、组件传递是否清晰 | Client 组件意外导入 server-only 模块 | 🔴 安全漏洞 |
| 验证证据 | 是否有可复现的命令、截图或测试结果 | PR 只写「已测试」,没有具体证据 | 🟡 要求补充 |
| 维护成本 | 是否贴近项目现有模式,是否过度抽象 | 为单一场景新增通用 helper | 🟢 建议优化 |
下面展开每个维度的具体审查方法。
行为正确性
AI 擅长实现单点功能,但容易遗漏需求涉及的其他入口和相邻功能。
比如让 AI「给图片列表加上无限滚动」。Agent 大概率会写出一个不错的 IntersectionObserver 实现,加上骨架屏加载和错误重试。但审查时需要多看几步:
- 用户切换筛选条件后,滚动位置是否重置?
- 用户从详情页返回列表页,滚动位置是否需要恢复?
- 无限滚动的加载状态是否和已有的骨架屏组件风格一致?
这些是上下文问题,AI 不知道图片列表组件同时被收藏页和搜索结果页引用,也不知道旧版列表接口有一个特殊的缓存策略需要保持一致。
我在实践中形成的一个习惯是:审查 AI 代码时,先不看它改了什么,而是先看它没改什么。需求涉及的其他模块是否需要同步改动?已有的数据模型是否支撑新功能?这些「沉默的遗漏」往往比代码里的 bug 更难发现。
边界条件
主路径通常没问题,但空值、错误、异常输入经常没有处理。
假设让 AI 实现一个「根据标签名搜索文章」的 API。AI 大概率会写出这样的代码:
// ❌ 主路径能跑通,边界全部缺失
async function searchByTag(tag: string) {
const articles = await db.article.findMany({
where: { tags: { some: { name: tag } } }
})
return articles
}这段代码能正常工作——如果传入的 tag 合法、标签存在、数据库正常、结果不为空。但实际运行中会遇到:
// ✅ 把实际会碰到的情况逐一处理
async function searchByTag(tag: string) {
// 空标签、超长输入
if (!tag || tag.length > 50) {
return { articles: [], total: 0 }
}
try {
const articles = await db.article.findMany({
where: { tags: { some: { name: tag } } }
})
// 空结果——是否需要推荐相似标签?
if (articles.length === 0) {
const similar = await suggestSimilarTags(tag)
return { articles: [], total: 0, similarTags: similar }
}
return { articles, total: articles.length }
} catch (error) {
logger.error('Tag search failed', { tag, error })
// 数据库异常时降级到缓存
return getCachedArticlesByTag(tag)
}
}左边的代码能跑通 demo,右边的代码才能撑住日常使用。差异在于是否预想了主路径之外的情况。AI 的训练数据里,大多数示例代码展示的是正常路径,异常处理往往被简化或省略。这种现象在当前各类语言模型中普遍存在。
数据流
AI 对框架约束的理解来自训练数据中的通用模式,而非项目的具体规则。它知道 React 组件可以用 useState,但不知道你项目的 Server Components 里不能用。它知道 fetch 可以发请求,但不知道项目的 API 调用必须走统一的 client 封装。
更值得留意的是安全相关的数据流问题。AI 生成的代码在数据净化方面经常偷懒。原因多半是训练数据里大量示例代码没有做净化,而安全规则又往往是项目特有的。比如,某个项目可能允许管理员富文本中包含 <iframe>,但用户投稿内容必须过滤掉。这类判断需要人来完成。
| 数据流问题 | AI 常见表现 | 审查者需要追问 |
|---|---|---|
| Server / Client 边界 | Client 组件里用了 Node.js API | 这个代码运行在浏览器还是服务端? |
| XSS 风险 | dangerouslySetInnerHTML 直接渲染 | 内容来源是否可信?是否经过净化? |
| 路径遍历 | 用原始文件名存储文件 | 文件名是否经过安全处理? |
| SQL 注入 | 拼接查询字符串 | 是否使用了参数化查询? |
| 跨层数据传递 | 数据转换发生在错误的层 | 转换逻辑应该在 server、API 层还是组件? |
审查数据流时,可以沿着一条数据从来源走到终点:它在哪里产生、经过了哪些函数、最终渲染在哪里。这条路径上每个节点都值得看一眼。
验证证据
如果 PR 作者声称「已测试」,但没有给出测试证据,这个声称只是意见,不是事实。
Stack Overflow 的调查里有一个值得注意的发现:审查者面对 AI 代码时会产生「判断负担」——他们发现手动验证 AI 输出花费的时间和自己写代码差不多。[2] 审查者要面对的是「看起来能跑但实际不工作的代码」「自信但错误的解释」和「引用不存在的 API」。
## ❌ 不合格的验证描述
- 已测试
- 功能正常
- LGTM
## ✅ 有具体证据的验证描述
### 验证步骤
1. `pnpm typecheck` — 通过,无类型错误
2. `pnpm test -- --filter=search` — 18 tests passed
3. 浏览器验收:
- 搜索有结果:标签筛选正常,URL 参数同步 ✅
- 搜索无结果:显示「暂无相关文章」和推荐标签 ✅
- 空输入:提交按钮禁用,不发送请求 ✅
4. 截图见附件验证证据的门槛可以概括为:如果另一个人拿到同样的代码和同样的步骤,能否复现出同样的结果?能复现的是证据,不能复现的是声明。
维护成本
GitClear 的数据在这一点上最有说服力:代码克隆增长 4 倍,重构比例从 25% 降到不足 10%。[1] AI 工具正在改变开发者的代码编写方式——更倾向于复制和微调,倾向于为单一场景创建过度抽象。
// ❌ AI 常见的过度抽象:为单一场景创建通用 helper
// utils/dateFormatterFactory.ts
export function createDateFormatter(
locale: string,
timezone: string,
options: Intl.DateTimeFormatOptions
) {
return new Intl.DateTimeFormat(locale, { ...options, timeZone: timezone })
}
// 只在 ArticleDate 组件中用了一次
// ✅ 更贴近项目实际的做法
// ArticleDate.tsx 内联实现
const formatDate = (date: string) =>
new Intl.DateTimeFormat('zh-CN', {
year: 'numeric', month: 'long', day: 'numeric'
}).format(new Date(date))判断维护成本的经验法则:如果一段抽象只有一处消费,它更接近内联代码而不是基础设施。
一个完整案例:从 PR 到合并决策
把三层 SOP 串起来看一个实际场景。
需求:给内容平台加上文章收藏功能。
Agent 的 PR:改了文章详情页,加了一个收藏按钮,用 localStorage 存储收藏状态。
规范层检查:对照 AGENTS.md 里的约束——
- 「测试放
apps/tests/」→ PR 没有新增测试 🟡 - 「Server Components 优先」→ 收藏按钮用了
'use client',需要确认是否必要 🟡 - 「API 调用走统一 client 封装」→ 收藏接口直接用了
fetch,应该走项目 API client 🔴
流程层检查:按风险顺序审查——
- 需求符合度:收藏列表页未实现 🔴
- 正确性:未登录用户可以点击,点击后才提示登录;快速连续点击无防抖 🔴
- 安全性:无明显安全问题 🟢
- 架构边界:
localStorage在 SSR 中访问需要做环境判断 🟡 - 测试与验证:PR 只写了「本地测试通过」🔴
执行层输出:
| 严重级别 | 发现 |
|---|---|
| Blocker | 收藏接口未走项目 API client,绕过了统一的鉴权和重试逻辑 |
| Major | 收藏列表页未实现,需求覆盖不完整 |
| Major | 未登录用户可以点击收藏按钮,交互逻辑不完整 |
| Major | 验证证据不足,缺少具体命令输出和截图 |
| Minor | localStorage 在 SSR 中需要做环境判断 |
合并决策:Changes requested。需要修复 Blocker 和 Major 后重新提交。
这个案例展示了三层 SOP 的协作方式:规范层提供了项目特有的判断标准(API client 封装、Server Components 策略),流程层确保了审查不跳步(从需求开始,不是从命名开始),执行层聚焦在 AI 最容易遗漏的五个维度上。
如何构建你自己的审查 Skill
上面的三层结构听起来完整,但实际落地需要一个起点。
我的建议是从 Google 的七维度标准出发,叠加项目特有的约束。具体步骤:
- 盘点项目约束。把散落在 README、wiki、聊天记录里的项目规则整理出来。优先整理最容易出错的边界(目录归属、文件约束、安全规则)。
- 写成 AGENTS.md 或 CLAUDE.md。用 Addy Osmani 的三层模型(Always / Ask / Never)组织规则。[7]
- 定义审查顺序和严重级别。按风险从高到低排列审查维度。定义 3-5 个严重级别,每个级别对应明确的合并影响。
- 写成 Skill 或模板。把审查流程写成可重复执行的文档。每次审查时按这个文档走,不需要靠记忆。
- 迭代。每季度回顾一次审查中发现的遗漏,把新模式补进规范层。
Re-entry 在一篇关于 AI 代码审查策略的文章中提出了六个组织要素,[9] 其中有几个和建设审查 Skill 直接相关:
| 要素 | 对审查 Skill 的启示 |
|---|---|
| 工具注册和范围 | Skill 里应该列出项目允许的工具和 API 调用方式 |
| 作者问责 | 审查模板里应该要求作者签名验证证据 |
| 风险分级验证 | 不同风险等级的改动需要不同强度的审查 |
| 自动化门禁 | 风格、类型检查等低维问题交给 CI,人工聚焦高维判断 |
| 数据与 Prompt 卫生 | Skill 里应该标注哪些数据不能出现在 AI 输出中 |
| 审计痕迹 | PR 模板里应该有 AI 辅助标记字段 |
最后一个建议:不要把审查 Skill 写成一本大书。InfoQ 报道中 Cloudflare 的经验是「专用代理比单一通用审查者效果更好」。[4] 审查 Skill 也一样——按维度拆分成可独立执行的小检查,比写一份面面俱到的长文档更容易坚持。
检查清单
把三层 SOP 压缩成一份每次审查可以用的快速清单:
## AI 代码审查 SOP 快速清单
### 规范层(审查前 30 秒)
- [ ] 对照 AGENTS.md 检查目录归属和文件约束
- [ ] 确认框架约束(Server/Client、API 封装层)
- [ ] 检查是否有 Never 级规则被违反
### 流程层(按顺序审查)
- [ ] 需求符合度:是否完整,有无遗漏和越界
- [ ] 正确性:边界条件、错误路径、并发状态
- [ ] 安全性:认证授权、输入校验、注入、XSS
- [ ] 架构边界:目录归属、依赖方向、API 契约
- [ ] 测试与验证:高风险逻辑有测试,验证命令匹配改动
- [ ] 性能:N+1、重复请求、内存泄漏
- [ ] 可维护性:复杂度、命名、文件是否过大
### 执行层(五维度聚焦)
- [ ] 行为正确性:AI 没改的文件是否需要同步改动
- [ ] 边界条件:空值、错误、非法输入是否处理
- [ ] 数据流:来源→转换→终点路径是否清晰安全
- [ ] 验证证据:有无可复现的命令和截图
- [ ] 维护成本:是否贴近项目模式,有无过度抽象
### 合并决策
- [ ] 给出明确结论:Approved / Approved with follow-ups / Changes requested / Needs context
- [ ] Blocker 和 Major 数量统计
- [ ] 未覆盖的风险面说明收束
审查 AI 代码的核心变化是:从「凭经验逐行看 PR」转向「按规范走流程」。
规范层把项目约束从人脑搬到文档,流程层让每次审查走同一条路径,执行层把注意力聚焦在 AI 最容易遗漏的维度上。三层叠在一起,审查就不再依赖审查者的状态,而是依赖可重复执行的规范。
84% 的开发者在用 AI 工具,但只有 29% 信任它们。这个信任差距,靠的是一次更仔细的审查,更靠一套能持续运转的 SOP。
Sources:
- [1] AI Copilot Code Quality: 2025 Data — GitClear:覆盖两亿多行代码变更的研究,发现代码克隆增长 4 倍、重构占比从 25% 降至不足 10%。
- [2] Mind the Gap: Closing the AI Trust Gap — Stack Overflow:2025 年开发者调查,84% 使用 AI 工具,信任度降至 29%。
- [3] A Survey of Bugs in AI-Generated Code — arXiv:调查 72 篇论文,系统分类 AI 生成代码中的八类缺陷。
- [4] AI Is Moving up the Software Lifecycle — InfoQ:DoorDash、Cloudflare 等公司的 AI 审查治理实践。
- [5] The Standard of Code Review — Google Engineering Practices:Google 代码审查七维度标准。
- [6] AGENTS.md Open Standard:面向 AI 编码代理的项目约束开放格式,超过 6 万个开源项目使用。
- [7] How to Write a Good Spec for AI Agents — Addy Osmani:为 AI 代理编写规格说明的最佳实践,包含三层约束模型。
- [8] How to Do Code Reviews in the Agentic Era — danicat.dev:AI 时代代码审查的实践指南。
- [9] AI Code Review Policy: The Six Components — Re-entry:AI 代码审查策略的六个组织要素。
- [10] Building Shared Coding Guidelines for AI — Stack Overflow:为 AI 和人类建立共享编码指南的讨论。