如果把过去一年开发团队的技术讨论拉一个清单,“AI 写代码”一定排在最前面。真正让团队紧张的往往不是代码量变大,而是另一个更实际的工程问题:AI 生成代码的速度已经超过人工审查的速度,人类正在失去对代码的全量审查能力。代码评审原本默认一个前提——每个提交都由熟悉上下文的人逐行读完。可当一次需求可以由 AI 在几十分钟内产出几百行、甚至上千行代码时,这个前提已经站不住。要解决的问题不是“要不要用 AI 写代码”,而是当“审不完”成为现实后,用什么流程、关卡和工具把风险控制在合理范围内。核心思路是停止和“逐行审完所有 diff”较劲,把审查体系改造成三层:机器拦截、AI 预审、人工重点核实。
1. 为什么“代码审不完”是必然出现的工程问题
1.1 代码生成速度与人工审查带宽存在剪刀差
传统开发模式下,一个开发者每天能产出的有效代码量有限,评审者可以用相近的时间把 diff 看完。AI 编程工具接入后,这个平衡被打破了。一个清晰的 prompt 可以生成一个完整的工具函数、一套单元测试、一次跨模块重构的初稿,早晨还没结束,分支上已经堆了好几个模块的代码。
对比几个现实数字就能明白问题所在:
- 人工编写:一个中型功能模块可能需要几天,期间代码分多次提交,每次 diff 可读。
- AI 编写:同一个功能可以在几十分钟内形成初稿,一次 commit 就包含过去几次提交的改动量。
- 人工评审:一个人全神贯注一小时能认真读掉的代码量有限,而且连续阅读时间越长,发现问题的密度越低。
于是团队会出现三类典型信号:MR 的 diff 行数明显变大,一个合并请求包含过去两到三个请求的改动;审查者只能看结构、看命名、看明显错误,细节逻辑依赖提交者自测;合入后缺陷变多,修复成本高于在审查阶段拦截的成本。
这里的关键不是“AI 生成的代码质量一定差”,而是审查体系仍然按人工代码时代设计。人工互审假设每个提交都有另一个完整理解上下文的人逐行审阅。当这个假设不再成立,真正的问题就从“审得细不细”变成了“审哪里、怎么审、用什么工具兜底”。
1.2 审查策略要从“全覆盖”转向“风险分级”
代码审查的真正目的不是完成“看完所有行”这个动作,而是降低缺陷进入主干的概率,以及降低后续修复成本。只要能在低成本环节拦截大部分机械问题,让高层级审查集中处理机器和 AI 都判断不了的问题,整体风险就会明显下降。
新的审查流水线可以分成四步:
- 提交前自动检查:格式、基础语法、明显错误。
- CI 阶段的静态分析和安全扫描:类型错误、常见漏洞模式、敏感信息泄漏。
- AI 预审:基于 diff 生成结构化审查意见,作为第二道机器防线。
- 人工按风险等级抽查和放行:把时间集中在高风险区域,而不是平均分配给所有行。
这个模型不是放弃人工审查,而是把人从“所有 diff 的全文阅读者”重新定位成“高风险变更的最终裁决者”。
2. 先把机器能判断的关卡全部自动化
2.1 机器先做三类检查:格式、静态规则、安全敏感项
第一类是格式与基础语法检查。代码格式化、未使用变量、缺少结束符这类问题没有任何讨论价值,应当由工具直接拦截。常见的实现是 pre-commit 钩子,进入版本控制前就完成。
第二类是静态分析与类型检查。这类检查可以捕获空值访问、类型不匹配、未处理错误分支、明显的并发问题等。工具清单按语言和团队习惯组合:
| 检查类别 | 常见工具 | 拦截目标 |
|---|---|---|
| 格式规范化 | Prettier、Black、gofmt | 缩进、引号、换行、排序 |
| 语言级静态检查 | ESLint、Ruff、golangci-lint | 未用变量、复杂度过高、可疑分支 |
| 类型检查 | TypeScript、mypy、pyright | 类型不匹配、空值传播 |
| 安全静态扫描 | Semgrep、CodeQL、SonarQube | SQL 注入、路径穿越、不安全反序列化 |
| 敏感信息扫描 | gitleaks、TruffleHog | 密钥、Token、连接串误提交 |
第三类是安全敏感信息扫描。AI 在生成代码时经常把配置示例也写进代码里,如果生成结果包含假密钥或真实可用的凭据,人工很难逐行发现,而 gitleaks 这类工具可以在一秒钟内扫出可疑模式。
2.2 用一个最小配置把检查关卡落地
先在仓库根目录创建一个 pre-commit 配置。以下示例用于说明思路,实际项目要结合自己的语言和包管理工具调整版本:
# .pre-commit-config.yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: - id: check-json - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.9 hooks: - id: ruff args: [--fix] - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.11.2 hooks: - id: mypy additional_dependencies: [types-requests]安装并执行一次,确认钩子生效:
pip install pre-commit pre-commit install pre-commit run --all-filespre-commit 的版本会持续更新,落地前先查看当前可用版本,不要把示例版本当成默认事实。
CI 阶段需要做的是限制检查范围。AI 生成的代码往往改动量很大,如果每次都在全仓库上跑 lint 和类型检查,CI 会变得越来越慢,最后团队会因为等待时间过长而绕过检查。推荐做法是只检查当前分支相对主干的变更文件:
#!/usr/bin/env bash set -euo pipefail BASE_REF="${BASE_REF:-origin/main}" CHANGED_FILES=$(git diff --name-only "${BASE_REF}"...HEAD || true) echo "== 变更文件清单 ==" echo "$CHANGED_FILES" # 1. 只对变更的 JS/TS 文件运行 ESLint JS_FILES=$(echo "$CHANGED_FILES" | grep -E '\.(js|jsx|ts|tsx)$' || true) if [ -n "$JS_FILES" ]; then npx eslint $JS_FILES fi # 2. 对本分支的提交历史做敏感信息扫描 gitleaks detect --source=. --log-opts="${BASE_REF}...HEAD" || true脚本里最关键的是git diff --name-only这一句,它保证了检查范围是被这次分支真正影响到的代码,而不是整个仓库。CI 配置里把这个脚本作为独立 job 执行即可。
2.3 自动检查的边界必须明确
机器检查能拦截语法、类型、明显漏洞和敏感信息,但它判断不了三件事:需求是否被正确实现、业务规则是否被遗漏、两个模块之间的交互是否符合预期。一个函数可以通过所有 lint 和类型检查,却仍然把订单状态计算错。
所以自动关卡是效率工具,不是质量保证的全部。它要做的是把人从“这行少了个分号”“这里可能为空”这类低水平劳动里解放出来,让人的精力能集中到机器无法判断的问题上。这个定位决定了自动关卡的设计原则:宁可多花一点配置时间,也要尽量多拦截、少误报。误报过多会导致团队不再相信工具输出,最终把整个关卡关掉。
注意:不要把自动检查的结果当作“已经审过”。机器检查通过只能说明代码满足规则,不能说明它满足需求。
3. 用 AI 审查 AI:把“审不完”变成“预审”
3.1 AI 预审解决什么问题
自动检查只能判断规则,AI 审查可以做一些接近逻辑判断的工作:发现空指针路径、状态未更新、资源未关闭、复制粘贴导致的重复逻辑、错误处理被吞掉等问题。也就是说,静态检查回答“这行合不合法”,AI 预审回答“这段逻辑可疑不可疑”。
AI 预审不是替代人,而是给每条变更生成一个带严重级别和行号的“风险地图”。人工拿到这份地图后,可以直接跳到高风险位置精读,而不是从头扫到尾。这个变化非常重要:当 diff 从 200 行变成 2000 行时,“先过滤再阅读”是唯一可行的方式。
同时要明确 AI 审查的局限性:
- 它可能引用不存在的代码行,这是大模型幻觉的直接表现。
- 它可能把“风格不同”误报成“逻辑错误”,需要人工忽略。
- 它无法访问运行时数据,不能替代测试。
3.2 给 AI 审查一个结构化提示词模板
AI 审查的提示词不能写成“帮我看看这段代码有什么问题”,那样会得到一堆空泛建议。要限制输入范围、输出格式和关注类型,方便人工快速消费结果。
你是一名资深代码审查者。请审查下面 git diff 中的内容。 只关注四类问题: 1. 逻辑错误:边界条件、空值、并发、资源未释放。 2. 安全风险:注入、敏感信息、权限校验缺失、异常被无信息吞掉。 3. 数据一致性:字段丢失、状态未更新、事务边界错误。 4. 明显可维护性缺陷:复制粘贴代码、注释与实现矛盾。 要求: - 先输出问题清单,使用表格:严重级别、文件、行号、问题描述、为什么是问题、修复建议。 - 再输出“需要人工确认”列表,列出你风险高但不完全确定的内容。 - 不要编造 diff 中不存在的代码。 - 如果没有发现问题,明确输出“未发现明确问题”。 diff 内容如下: {DIFF}实际使用时,把{DIFF}替换成git diff origin/main...HEAD的输出。不要让大模型直接读整个代码库,范围越大,模型越容易关注无关内容,也越容易产生幻觉。
关键点在要求里写得非常具体:先出表格,再出人工确认列表,禁止编造代码。这些约束不是可有可无的装饰,它们直接决定了 AI 审查结果是否值得人工去读。
3.3 在 VS Code、CLI 和自托管工具中落地
AI 审查工具目前有几类落地方式:
- 在 VS Code 中使用支持 diff 上下文的扩展,选中变更后发起审查。
- 在 CLI 环境中用脚本把 diff 喂给模型接口,把输出保存为审查报告。
- 使用社区开源方案,例如 Open Code Review 这类以 diff 为输入、生成审查意见的工具。这类工具通常会要求在 VS Code 里安装扩展,然后配置模型接口。具体安装命令和配置项以官方文档为准,因为开源项目迭代非常快。
- 团队可以选择在 CI 中运行审查机器人,每个 MR 自动发布一条审查意见,类似一个“AI 评审人”。
无论用哪种方式,都要先处理连接配置。配置模型接口时,团队可能会遇到两类典型报错。一类是 HTTP 401,响应体里出现api_key_required之类的字段,说明模型接口的密钥缺失或无效,需要检查环境变量和配置文件。另一类是模型接口返回地区或区域不支持的信息,这通常与账号所在地、组织配置有关,需要确认组织的可用范围。这类错误不是代码问题,排查顺序是先看密钥、再看网络、再看账号权限。
注意:不要把来源不明的 AI 提示词或脚本直接粘贴到终端、DevTools 控制台或带权限的目录中执行。任何会执行任意命令的提示词,都要先读一遍再确认。
4. 人工只盯高价值区域:分层审查策略
4.1 把变更分成四档
人工审查不可能覆盖所有 diff,但不代表每个 diff 风险相同。团队可以根据变更影响到的模块、代码位置和改动类型把变更分级,然后给每级分配不同的审查深度。
| 风险级别 | 典型变更 | 审查方式 | 人工投入 |
|---|---|---|---|
| A 级 | 支付、鉴权、核心状态机、数据迁移 | 人工逐行审阅,AI 预审先行 | 高 |
| B 级 | 批量任务、对外接口、数据库访问 | AI 预审 + 人工重点抽查 + 测试 | 中 |
| C 级 | 日志、页面展示、埋点、样式 | AI 预审 + 随机抽查 | 低 |
| D 级 | 实验原型、一次性脚本、文档示例 | 自动检查即可 | 最低 |
分级不是让团队少做事,而是把有限的注意力配置到风险密度最高的地方。一个支付模块的 50 行变更,比一个宣传页面的 500 行变更更值得人逐行阅读。
4.2 抽样式深度审查怎么抽
对于 B 级和 C 级变更,人工可以选择抽样。抽样不能随机抽,否则可能抽到一段从未被调用过的辅助函数,而真正危险的依赖更新没人看。
推荐的抽样顺序:
- 先看变更文件列表,找出过去六个月出现缺陷最多的文件。
- 优先查看对外接口、数据库读写、异常处理相关的变更片段。
- 用
git log查看这个文件最近由谁修改、修改频率如何。高频修改文件往往承担高复杂度逻辑,值得细看。 - 对 AI 预审给出的“需要人工确认”列表逐条确认,这比漫无目的地扫读效率高很多。
一个可操作的做法是:对 B 级变更至少精读 30% 的变更行,且必须覆盖所有异常分支;对 C 级变更至少精读变更后的入口和出口。这个比例不来自标准规范,而是来自团队自己的缺陷数据,统计几次合入后的线上问题后,再调整比例。
4.3 高风险变更必须强制人工放行
如果团队把“人工放行”也交给自动流程,那前面所有分级都是空话。A 级模块应当通过仓库保护规则强制要求指定负责人批准,可以用 CODEOWNERS 声明所有者:
# .github/CODEOWNERS /payment/ @pay-owner /src/security/ @security-owner /db/migrations/ @db-owner配置仓库保护规则时,可以要求:
- A 级模块的改动必须有一个明确 Owner 批准。
- 所有 MR 必须通过 CI。
- AI 审查机器人可以发表意见,但不能作为唯一批准人。
- 高风险的库版本升级不允许由 AI 生成的代码分支直接合入,必须有负责人核对变更说明。
这里的核心逻辑是:机器负责“过程正确”,人负责“决策正确”。AI 生成的代码可以自动通过格式和静态检查,但它是否进入主干,必须以人工确认为前提。
5. 常见问题与排查链路
5.1 典型问题现象与处理方案
| 问题现象 | 可能原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| CI 检查越来越慢 | 每次都在全仓库跑检查,而不是只跑变更文件 | 查看 CI 日志中各步骤耗时 | 改为只检查BASE_REF...HEAD的变更文件 |
| AI 审查意见指向不存在的代码 | 提示词没有限定 diff 范围,模型看到的上下文过多 | 检查输入给的是 diff 还是整库代码 | 只传变更文件或变更行 |
| AI 审查频繁误报 | 提示词关注面太宽,把风格问题当逻辑问题 | 抽查误报内容的分布 | 收窄关注类型,禁止泛泛建议 |
| 本地 pre-commit 没生效 | 安装钩子后未执行pre-commit install,或有人跳过钩子 | 执行git commit观察是否触发钩子 | 重新安装钩子,并把关键检查放到 CI |
| 合并后才发现密钥泄露 | 敏感信息扫描只配在本地,没进 CI | 检查扫描工具是否在 CI job 中执行 | 将 gitleaks 加入 CI,并定期全库扫描 |
| 审查疲劳,意见变少 | 所有 MR 都堆给一个负责人 | 统计各 MR 的首次响应时间 | 轮值制度结合模块 Owner |
5.2 按固定顺序排查问题
当审查流水线出现异常时,不建议直接改工具或加规则。先按下面这个顺序排查,多数问题能在前两步定位:
- 确认输入是否正确:diff 范围对不对,是不是拿到了完整变更,分支有没有推送到远端。
- 确认路径和命名:配置文件名、钩子目录、脚本路径是否与项目约定一致。
- 确认版本匹配:pre-commit 的镜像版本、ESLint 插件版本、模型接口版本是否和配置匹配。
- 确认配置是否生效:检查钩子是否安装、CI job 是否真的执行、环境变量是否注入。
- 确认权限和网络:密钥是否有效、CI runner 能否访问内网依赖、代码仓库的权限是否允许机器人读取。
- 查看日志关键字:CI 日志里出现
timeout、401、403、unsupported_country_region_territory时,按提示逐项处理。 - 人工兜底:工具全部正常但结果不合理时,先人工确认问题是否真实,再决定是否调整规则。
6. 落地清单与下一步扩展
6.1 团队接受 AI 代码前的检查清单
下列清单可以直接复制到项目文档中,作为发布前检查依据:
发布前检查清单 - [ ] 变更文件列表与需求范围一致,没有夹带无关修改 - [ ] 自动检查关卡已运行:格式、lint、类型检查、安全扫描 - [ ] 敏感信息扫描通过,未出现密钥、Token、连接串 - [ ] AI 审查报告已生成,人工确认了其中“高风险”和“需人工确认”项 - [ ] A 级模块已有指定 Owner 批准 - [ ] 高风险依赖升级有负责人核对变更说明 - [ ] 新增代码有对应测试,测试在 CI 中通过 - [ ] 异常分支被覆盖:空值、超时、失败回滚、部分成功 - [ ] 未将来源不明的提示词或脚本直接执行 - [ ] 回滚方案明确,知道如何快速回退本次变更6.2 生产环境还要补的保障
以上流程解决的是“代码合入前”的问题。合入后,生产环境还需要额外的保障:
- 配置外置:密钥、连接串、开关不写进代码库,交给环境变量或配置服务。
- 日志与监控:高危模块要有足够日志,关键业务操作需要有 traceId 串联。
- 可观测告警:审查阶段漏掉的问题,靠监控和告警兜底,越早发现修复成本越低。
- 回滚机制:每个版本明确回滚方式,禁止只有一个负责人知道怎么回滚。
- 依赖锁定:AI 生成代码经常引入新依赖,锁定版本并审查依赖来源。
- 数据备份:涉及数据迁移的变更,必须先验证可回滚性。
6.3 可以继续扩展的方向
这套审查体系落地后,团队可以继续往三个方向扩展。
第一个方向是变更影响分析。根据调用关系自动判断一个函数被谁引用,把“这个文件改了会影响哪些下游”变成机器可直接查询的事实。AI 生成的跨模块改动先做影响分析,再决定是否需要更多人工关注。
第二个方向是测试补充自动化。AI 生成代码的同时生成对应单元测试,并把测试覆盖情况纳入合并门槛。这里的重点是审查测试质量,而不是只看覆盖率数字。
第三个方向是对 AI 审查结果做反馈闭环。记录每次 AI 审查意见最终是否被确认,用这部分数据微调提示词和工具参数。AI 审查不是一次配置就结束的功能,它和静态规则一样需要持续校准,否则会因为误报增加而逐渐被团队忽略。
回到最初的问题:AI 写代码但人审不完,怎么办。答案不是制造一个无所不能的审查机器人,而是重新分配责任——机器负责能机械化判断的全部环节,AI 预审负责生成风险地图,人只对真正高风险、需要业务判断和长期上下文的部分做深度决策。这套体系不需要一次搭完,可以先从“CI 只检查变更文件”和“一个结构化 AI 审查提示词”开始,跑通两周后根据团队自己的缺陷数据加关卡。先让流程在最小范围内稳定,再逐步扩大,比一开始就设计一个全自动审查平台更可靠。