代码审查是在合入代码之前最值得投入的环节,但在实际团队里,它往往变成最容易被压缩、被拖延、被形式化的过程。很多开发者对 Code Review 的真实感受并不是“有人帮我发现了 bug”,而是“提交之后又要等、又要解释、又要反复修改”。当团队规模变大、提交频率变高、PR 数量变多时,人工审查的时间成本会指数级上升。此时,AI Engineer 这个角色最该回答的问题不是“AI 能不能替代人审”,而是“怎样用 AI 把传统代码审查里机械的、可枚举的、低判断成本的部分全部吃掉,让人只处理真正需要经验判断的内容”。
这篇文章会围绕“终结传统代码审查”这条主线展开,而不是简单讨论代码审查要不要做。这里要讨论的是:传统代码审查的瓶颈到底在哪,AI 审查能力的边界在哪,怎么在 VS Code 里先搭一个本地审查助手,怎么把审查接到 CI 流水线,以及当工具出现误报、漏报、不生效时,应该按什么链路去排查。文章最后会给出一个可复用的落地清单。整个实现方案不做平台绑定,代码和配置用通用示例说明,落到自己项目时需要按实际技术栈调整。
1. 传统代码审查的问题不在“审”,而在“查”
1.1 人工审查的三重成本
代码审查最容易被误解的地方,是把它当成“打开 PR 看一眼”。实际上,一次有效审查需要先理解改动上下文,再逐行检查逻辑,然后验证边界条件,最后还要把意见表达清楚。这一串动作里,只有“表达意见”是机器难替代的,前面的“理解上下文”和“逐行检查”恰恰是成本最高、也最机械化的部分。
传统代码审查的成本主要集中在这三处:
| 成本类型 | 具体表现 | 产生原因 |
|---|---|---|
| 时间成本 | 一个 PR 从提交到合入可能要等几小时甚至隔天 | 审查者需要在多个任务之间来回切换,很难连续集中注意力 |
| 上下文切换成本 | 审查者刚写完自己的代码,又要看别人的分支 | 每次切换都要重新加载模块结构、业务背景、历史约定 |
| 表达成本 | 审查者发现了问题,但要写成对方能理解的意见 | 没有统一的审查表达模板,意见经常出现歧义 |
这些成本叠加之后,团队会本能地压缩审查投入。常见的做法是“只 review 大改、小改直接合”,或者“只看 diff、不跑代码、不验证测试”。这种方式省下了时间,却把缺陷留到了测试甚至线上。
1.2 需要终结的是机械性审查,不是质量门禁
代码审查本来承担着两个职责:一个是质量门禁,防止明显问题进入主干;另一个是知识传递,让团队成员理解彼此的设计思路。质量门禁可以自动化,知识传递不可以。如果团队因为流程太重而放弃了代码审查,等于把两个职责一起丢掉。
反过来看,AI 介入能解决的是前半段:格式、命名、重复代码、明显的空指针风险、接口参数校验、常见性能反模式、日志规范、安全漏洞模式。这些内容完全可以通过规则引擎、静态分析、AI 模型在几秒内完成,不需要人类逐行确认。人工审查真正需要保留的部分,是架构合理性、业务逻辑正确性、扩展性、团队特定约定,以及那些“代码能跑但设计有问题”的判断。
所以要“终结”的,不是代码审查这件事,而是“所有问题都要由人在 PR 页面里逐字写出来”的传统模式。
1.3 AI Engineer 在审查流程里的定位
AI Engineer 在这个场景里不是“写提示词的人”,而是“流水线设计者”。他要回答几个问题:哪些审查任务交给规则,哪些交给模型,哪些必须保留给人;AI 审查结果出问题时怎么降级;模型误报太多时怎么调;审查结果如何进入 PR 评论而不只是躺在终端里。
实际上,代码审查非常适合作为 AI 工程化的第一个落地场景。因为它的输入输出结构非常稳定:输入是 diff 文件和变更上下文,输出是问题列表。你可以把它做成命令行工具,也可以接入 CI,也可以做成 IDE 插件。比起“用 AI 写业务代码”,审查场景的输出结果更容易验证,也更方便迭代。
一个可用的基本分工是这样的:
- 静态检查规则负责确定性问题:未使用变量、资源未关闭、明显的空指针。
- AI 模型负责模式识别和语义检查:接口参数缺失校验、缓存使用不当、事务边界异常、命名与职责不符。
- 人工负责最终决策:这些问题是否真的需要改、怎么改、是否影响兼容性。
这个分工也是后面搭建整套流程的基本框架。
2. 先划定 AI 审查能力边界,再选落地方式
2.1 AI 擅长什么,不擅长什么
任何团队在上 AI 审查工具之前,都应该先做一次能力边界确认。否则预期放得太高,工具一上线就被误报淹没,最后整个方案被否决。
AI 目前比较擅长的审查点是:
- 代码规范类:命名、格式、注释、魔法数字、过长函数。
- 常见缺陷模式:空指针、资源泄漏、异常被吞、硬编码配置。
- 安全类模式:SQL 注入、命令注入、敏感信息明文输出、不安全的反序列化。
- 重复代码检测:同结构代码块、重复条件判断。
- 接口约束:参数未校验、返回值类型不匹配、异步调用缺少异常处理。
AI 目前不太可靠的点是:
- 复杂业务逻辑是否正确:模型能看出逻辑结构,但不能真正运行业务场景。
- 跨模块影响面:一次改动会影响哪些调用方,模型难以从单文件 diff 中判断。
- 团队特定约定:某些团队要求所有 Service 层返回统一结果对象,这种约定模型不知道,只能靠提示词注入。
- 测试覆盖是否足够:模型无法判断测试用例和业务场景之间的映射是否完整。
用一个表格来归纳:
| 审查类型 | 适合 AI | 适合人工 | 说明 |
|---|---|---|---|
| 格式与命名 | 是 | 否 | 交给规则引擎即可,不需要模型 |
| 常见缺陷模式 | 是 | 辅助确认 | 模型给出怀疑点,人确认上下文 |
| 安全漏洞模式 | 是 | 重点复核 | 高危项必须人工确认后再处理 |
| 重复代码 | 是 | 否 | 结果可直接作为重构建议 |
| 业务逻辑正确性 | 否 | 是 | 模型只能提示异常,不能替代理解 |
| 架构与扩展性 | 否 | 是 | 需要结合项目演进方向判断 |
| 团队约定 | 弱 | 是 | 通过提示词和规则补充,但无法全覆盖 |
这个表格应该在下手搭工具之前,先和团队对齐一遍。否则,AI 审查工具很容易变成“又一种 CI 噪音”。
2.2 按代码量选择落地方式
不同规模的仓库,落地方案差异很大。如果团队只有一个十几万行代码的中型服务,直接在 VS Code 里跑本地审查脚本已经完全够用;如果团队有几十个仓库、几百个服务,本地脚本就管不过来了,必须接入 CI,并集中管理审查结果。
三种落地方式对比:
| 落地方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| IDE 本地审查 | 个人开发、小团队 | 反馈最快、改一行审一行 | 缺少团队统一入口,无法形成门禁 |
| CI 流水线审查 | 中大型团队、多仓库 | 强制生效、结果集中、可关联 PR | 反馈较慢,需要设计降级策略 |
| 专用审查平台 | 安全要求高、审计要求严 | 权限、审计、报告完整 | 成本高、维护重、不一定适合小团队 |
对于大多数中小团队,推荐先做 IDE 本地审查,跑通之后再迁移到 CI。因为本地审查的反馈链路短,开发者能实时看到问题;CI 审查可以后续再加入,作为合入前的最后一道关卡。
2.3 一个保守但可落地的组合
不追求一步到位,推荐这样组合:
- 用 ESLint、Pylint、Checkstyle 等已有工具做规则检查。
- 把 diff 文件和项目规范文档发给模型,让模型输出审查意见。
- 审查意见统一转成结构化 JSON,再渲染成 PR 评论。
- 高危问题阻止合入,普通建议只提醒不阻塞。
这套组合的好处是每一层都可以单独调试。规则检查有问题,不会影响模型审查;模型输出有问题,可以用 JSON 校验挡住。它不依赖某一个具体平台,也不要求团队一次性接受全部自动化结论。
3. 在 VS Code 里先把“本地审查助手”跑起来
3.1 安装开源审查类扩展时的注意事项
VS Code 扩展市场里有不少以 code review、open code review 命名的扩展。安装时不要只看名字,要看扩展的支持范围。有些扩展只是把 PR 列表搬进 IDE,本质上还是人工审查;有些扩展会调用模型接口做审查,这才是本文要用的那类。
以“open code review”这类扩展为例,安装命令通常是:
code --install-extension <扩展标识符>不同扩展的标识符不一样。实际安装前,可以在 VS Code 扩展面板里搜索 open code review,进入扩展详情页确认三点:
- 是否支持当前语言。
- 是否支持自定义审查提示词。
- 审查结果是否可以导出为文本或 JSON。
注意:扩展市场里的同类工具差异很大。有的工具会直接把 diff 发给远程 API,敏感代码仓库要先确认数据出网策略。建议在隔离环境或小仓库先试用几天,再决定是否进入生产仓库。
3.2 配置审查提示词,让输出结构化
AI 审查工具能否好用,很大程度上取决于审查提示词。提示词不是越复杂越好,而是要约定输出格式、问题等级、定位方式和处理建议。
下面是一个通用的审查提示词模板,适用于大多数模型接口:
你是一名代码审查工程师。请基于 git diff 内容进行审查,只报告真实存在的问题。 审查要求: 1. 区分问题等级:error 表示会导致功能错误或安全风险;warning 表示存在隐患;suggestion 表示优化建议。 2. 每条问题必须包含文件路径、行号、问题描述、修复建议。 3. 不要报告格式问题,格式问题交给 linter 处理。 4. 不要输出无具体位置的泛泛意见。 5. 如果 diff 内容不完整,只审查能看到的部分。 输出格式: 直接输出 JSON 数组,不要输出额外说明。 每个元素的结构为: {"level":"error|warning|suggestion","file":"文件路径","line":行号,"message":"问题描述","suggestion":"修复建议"}这段提示词有三个关键设计:
- 问题分三级,方便后续接 CI 时决定是否阻塞合并。
- 强制输出 JSON,便于程序解析和回写 PR 评论。
- 明确排除格式问题,避免和已有 linter 重复。
3.3 写一个最小命令行审查工具
在 VS Code 插件之外,更可控的方式是自己写一个命令行审查工具。这样不依赖特定扩展,团队可以统一维护。下面用 Python 写一个最小实现,核心流程是三步:
- 获取当前分支相对主干分支的 diff。
- 构造审查请求。
- 解析模型返回的 JSON,按等级打印。
先创建一个项目目录:
mkdir ai-review && cd ai-review python3 -m venv venv source venv/bin/activate pip install requests然后创建review.py:
import json import os import subprocess import sys import requests def get_diff(base_branch="main"): result = subprocess.run( ["git", "diff", base_branch, "--", "*.py"], capture_output=True, text=True ) return result.stdout def build_prompt(diff_text): with open("review_prompt.txt", "r", encoding="utf-8") as f: base_prompt = f.read() return base_prompt + "\n\n```diff\n" + diff_text[:12000] + "\n```" def call_review(prompt): api_key = os.getenv("AI_API_KEY") endpoint = os.getenv("AI_ENDPOINT") model = os.getenv("AI_MODEL", "gpt-4o-mini") headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } payload = { "model": model, "messages": [ {"role": "system", "content": "你是代码审查助手。"}, {"role": "user", "content": prompt} ], "temperature": 0.2 } response = requests.post(endpoint, headers=headers, json=payload, timeout=60) response.raise_for_status() content = response.json()["choices"][0]["message"]["content"] return content.strip() def parse_review(content): start = content.find("[") end = content.rfind("]") if start == -1 or end == -1: raise ValueError("模型输出不是合法 JSON 数组") return json.loads(content[start:end+1]) def main(): if len(sys.argv) > 1: base_branch = sys.argv[1] else: base_branch = "main" diff_text = get_diff(base_branch) if not diff_text.strip(): print("没有发现变更") return prompt = build_prompt(diff_text) content = call_review(prompt) issues = parse_review(content) for item in issues: mark = {"error": "[E]", "warning": "[W]", "suggestion": "[S]"}.get(item["level"], "[?]") print(f"{mark} {item['file']}:{item['line']} {item['message']}") print(f" 建议: {item['suggestion']}") print(f"\n共发现 {len(issues)} 条问题")脚本里要解释几个设计决定:
base_branch默认是main,可以用命令行参数覆盖。build_prompt里拼接了review_prompt.txt,提示词独立存放,方便调整。call_review从环境变量读取密钥,避免密钥写进代码。parse_review只取第一个 JSON 数组,规避模型输出前后附带说明的情况。
3.4 接入 VS Code 快捷键和保存时触发
在 VS Code 里,可以通过 Tasks 把这个脚本绑成快捷键。先创建.vscode/tasks.json:
{ "version": "2.0.0", "tasks": [ { "label": "ai-review", "type": "shell", "command": "source venv/bin/activate && python review.py", "group": { "kind": "build", "isDefault": true }, "presentation": { "reveal": "always", "panel": "shared" } } ] }然后在keybindings.json里绑定快捷键:
{ "key": "ctrl+alt+r", "command": "workbench.action.tasks.runTask", "args": "ai-review" }这里有一个取舍:不建议把完整审查绑到“保存时触发”,因为每次保存都会调用模型接口,既消耗额度,又会在频繁保存时刷屏。更合理的做法是绑定快捷键,或者在 git commit 前用 pre-commit 触发。保存时只跑本地 linter 就够。
3.5 本地验证检查点
本地工具完成后,按这个顺序验证:
- 在任意项目里修改一个 Python 文件,故意加入一个空指针风险和一行未使用变量。
- 运行
python review.py main,确认能输出 diff。 - 确认模型返回的内容能解析成 JSON 数组。
- 确认问题等级和行号定位准确,不是模糊建议。
这个检查点很关键。如果按行号点过去找不到对应代码,说明提示词里的行号约定没生效,或者 diff 截断导致行号错位。不要在行号不准的情况下接入 CI,否则团队马上会失去信任。
4. 把审查流程接到团队流水线:从本地到 CI
4.1 在 GitHub Actions 中接入 AI 审查任务
本地脚本跑通后,下一步是把同一套逻辑放进 CI。这样可以保证每个 PR 都经过相同标准的审查,而不是依赖某个开发者自己是否记得运行。
下面是一个 GitHub Actions 工作流示例:
name: ai-code-review on: pull_request: types: [opened, synchronize] jobs: review: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies run: | pip install requests - name: Run AI review env: AI_API_KEY: ${{ secrets.AI_API_KEY }} AI_ENDPOINT: ${{ secrets.AI_ENDPOINT }} AI_MODEL: ${{ vars.AI_MODEL }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python ci_review.py注意fetch-depth: 0很重要。没有它会只拉取单次提交,无法拿到完整 diff。
4.2 审查结果如何回写 PR 评论
CI 里只打印审查结果意义不大,最好能把结果发回 PR 评论。GitHub 的 REST API 可以创建 issue 评论,实际场景里也应该尽量合并同一次提交的评论,避免反复刷屏。
import os import requests def post_pr_comment(repo, pr_number, body): api_url = f"https://api.github.com/repos/{repo}/issues/{pr_number}/comments" headers = { "Authorization": f"Bearer {os.getenv('GITHUB_TOKEN')}", "Accept": "application/vnd.github+json" } response = requests.post(api_url, headers=headers, json={"body": body}) response.raise_for_status()在 CI 里使用时,仓库名和 PR 号从github.event中读取。GitHub Actions 默认提供GITHUB_REPOSITORY和GITHUB_REF环境变量,但更稳妥的方式是显式传入:
env: PR_NUMBER: ${{ github.event.pull_request.number }} REPO_NAME: ${{ github.repository }}代码里再改成:
repo_name = os.getenv("REPO_NAME") pr_number = os.getenv("PR_NUMBER")4.3 分级处理:error 阻塞合并,warning 提醒,suggestion 不阻塞
AI 审查结果必须在 CI 里分级,否则要么太吵,要么形同虚设。推荐的规则是:
| 输出等级 | 含义 | CI 处理策略 |
|---|---|---|
| error | 有明确的逻辑错误或安全风险 | 阻止合并,必须人工确认 |
| warning | 存在明显隐患或代码异味 | 不阻断,但必须在 PR 评论中列出 |
| suggestion | 优化建议 | 只记录,不产生噪音 |
在ci_review.py中,可以统计 error 数量,使用非零退出码:
error_count = sum(1 for item in issues if item["level"] == "error") if error_count > 0: print(f"发现 {error_count} 个 error 级别问题,阻止合并") sys.exit(1)这里要注意,AI 模型不可能 100% 准确,error 判定一旦落到 CI 阻断,必须有降级入口。建议的方法是:error 级问题本身不直接阻止合并,而是生成一个固定格式的评论,由维护者确认后关闭。否则模型误报一次,就会导致整条流水线被绕过。
4.4 学习环境与生产环境的配置差异
| 配置项 | 学习环境 | 测试环境 | 生产环境 |
|---|---|---|---|
| 模型 | 小参数模型或低成本模型 | 与生产同型号,但只做观察 | 稳定版本模型,锁定提示词和温度 |
| 密钥 | 本地.env文件 | CI Secret | 集中密钥管理,不能进仓库 |
| 审查范围 | 当前分支 diff | 全量 PR diff | 全量 PR diff + 变更关联扫描 |
| 阻断策略 | 只输出建议 | 可开启 warning 阻断,临时放量 | 只阻断 error,且必须有降级入口 |
| 数据出网 | 本地可控 | 尽量使用同区域 API | 按公司安全规范选择专用网关 |
| 输出落点 | 终端 | PR 评论 + 文件日志 | PR 评论 + 集中报告 + 指标上报 |
| 日志 | 无要求 | 保留原始请求响应 | 脱敏后保留,用于模型质量问题复盘 |
学习环境追求的是快速跑通,不要一开始就在安全、权限、审计上投入过度。生产环境则要反过来,宁可审查速度慢一点,也要保证结果的可追溯性和人工复核入口。
5. 用一段有问题的代码验证审查效果
5.1 准备一段包含常见缺陷的示例代码
为了验证审查流程是否真正有效,准备一段有明显缺陷的 Python 代码。这里不使用极端复杂的代码,而是选择项目里最容易出现的几种问题:空指针类风险、资源未关闭、异常被吞、硬编码密钥。
import os import sqlite3 def load_user(db_path, user_id): connection = sqlite3.connect(db_path) cursor = connection.cursor() try: cursor.execute("SELECT name, email FROM user WHERE id = ?", (user_id,)) row = cursor.fetchone() return {"name": row[0], "email": row[1]} except Exception: pass finally: if connection: connection.close() def send_notice(user): api_key = "sk-test-1234567890" client = create_client(api_key) result = client.send(user["name"]) return result.status_code == 200 def create_client(key): from fake_sdk import Client return Client(key)这段代码里有四个典型问题:
row可能为 None,下面会抛出TypeError。- 裸
except: pass吞掉了所有异常,排查时没有任何日志。 api_key硬编码在代码里,属于敏感信息泄露。- 连接关闭操作放到
finally里是对的,但“是否关闭”的条件判断没有必要,可以直接 close。
5.2 运行审查并查看输出
假设已经写好了review.py,在项目根目录执行:
python review.py main一份可能的审查输出如下:
[E] app/example.py:8 在 fetchone() 返回 None 时,row[0] 会抛出 TypeError 建议: 先判断 row 是否为 None,再取字段;或者使用 get 方法并返回默认值。 [W] app/example.py:9 异常被裸 except 捕获,缺少日志和上下文 建议: 记录异常类型和相关参数,至少使用 logging.exception()。 [E] app/example.py:14 API Key 硬编码在代码中 建议: 从环境变量或密钥管理服务读取,不要提交到仓库。 [S] app/example.py:21 函数 create_client 只做了一层转发 建议: 若没有额外逻辑,可以直接去掉,减少调用链。这里不需要把输出当作绝对正确。重点看两个东西:
- 行号是否能对应到问题代码。
- 问题描述是否给了足够上下文,让开发者不需要再打开原始文件确认。
如果模型把问题定位到完全无关的行,说明提示词里的 diff 格式和行号约定需要调整。
5.3 如何判断审查输出是有效还是噪声
AI 审查最容易出现的问题是输出很多,但开发者的真实感受是“每条都对,但每条都不用改”。要避免这个问题,可以建立一个简单的评价维度:
| 维度 | 有效输出 | 噪声输出 |
|---|---|---|
| 定位准确 | 行号准确,能对应到具体代码 | 只说了类名或函数名,无法定位 |
| 问题可复现 | 描述的是明确缺陷或隐患 | 描述的是风格偏好,不涉及正确性 |
| 建议可执行 | 可以照着修改,或明确需要人工确认 | 建议模糊,如“可以考虑优化” |
| 有等级区分 | 明确标出 error、warning、suggestion | 所有问题都是同一等级 |
| 有优先级 | 高危问题优先展示 | 格式、命名、性能建议混在一起 |
建议团队在落地初期,每周对审查输出的有效性做一次抽查。取 10 条输出,让核心开发者逐条投票“保留”“修改”“删除”,持续调整提示词。这个环节是 AI 审查质量提升的关键,不能省略。
6. 常见问题排查:工具不出结果、误报、漏报
6.1 按现象倒推根因的排查顺序
AI 审查工具接入后,大概率会遇到下面这些问题。排查时应按“输入是否正确、路径是否正确、依赖是否匹配、配置是否生效、权限和网络是否正常、日志是否有异常”的顺序倒推,不要直接怀疑模型能力。
整套链路按顺序检查:
- 当前分支和基准分支是否正确。
- git diff 是否真的取到了变更内容。
- 环境变量是否已经加载。
- 模型接口是否能通。
- 模型返回内容是否能解析为 JSON。
- 审查结果的等级映射是否生效。
- CI 里评论写入权限是否齐全。
6.2 常见问题速查表
| 问题现象 | 常见原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 脚本输出“没有发现变更” | 当前分支与 base 分支无差异,或未取完整历史 | 运行git diff main --stat | 确认分支提交状态,CI 里配置 fetch-depth: 0 |
| 模型返回内容无法解析为 JSON | 提示词没有严格约束输出,或 diff 太长超过模型窗口 | 查看原始响应内容 | 增加 JSON 格式约束,截断 diff,或增加重试 |
| 审查结果全是 suggestion | 提示词没有强调只报告真实问题,或模型被设置成低风险模式 | 查看 prompt 和 temperature 参数 | 在提示词里注明“只报告真实存在的问题”,并降低 temperature |
| 同一问题被反复报 | 提示词里没有要求合并同类问题 | 查看历史评论 | 提示词增加“相同类型问题合并展示” |
| 行号定位不准 | diff 被截断,或模型输出的行号是 diff 内行号而不是文件行号 | 对比 diff 行号 | 提示词明确“行号是文件中真实行号”,并在脚本中做行号转换 |
| API 请求超时 | diff 过长、模型处理速度慢、网络不稳定 | 查看超时设置和请求耗时 | 增加 diff 截断,引入缓存,适当提高超时时间 |
| CI 里 job 失败但本地通过 | 环境变量缺失或 python 版本不一致 | 检查 CI 日志 | 本地尽量使用与 CI 相同的 Python 版本 |
| 评论没有发到 PR | GITHUB_TOKEN 只有读取权限,或仓库名/PR 号读错 | 打印 repo_name 和 pr_number | 确认 actions 配置的 permissions 写入权限 |
| 误报太多导致信任下降 | 提示词过于宽泛,没有领域约束 | 查看模型输出类型分布 | 增加场景白名单,只审查指定文件类型或指定目录 |
6.3 误报和漏报的调优方向
误报多,通常是提示词约束不够。例如没有告诉模型“不要报告 linter 能处理的问题”,模型就会把格式问题混进来。漏报多,通常是审查范围太窄,或者 diff 被截断。调优方向可以参考:
- 增加项目规范到提示词中,例如“本项目禁止在 Service 层直接操作数据库连接”。
- 排除明显不该审查的文件类型。比如 lock 文件、生成的模型文件、打包产物。
- 按目录配置审查深度。核心业务代码目录使用严格策略,测试目录和脚手架代码放低优先级。
- 对模型输出做二次过滤。例如用正则检查是否包含明显非问题内容,或过滤行号不存在的问题。
注意:不要因为误报一开始很多,就直接关闭整个工具。更合理的做法是先运行在“仅提醒”模式,每次发布前把新模型产生的误报和真实问题拉到一起复盘,用两周时间把提示词调整到可接受范围。
7. 最佳实践和扩展方向
7.1 人工审查必须保留的场景
无论 AI 审查工具多成熟,下面这几个场景都必须保留人工审查,否则质量风险会迅速累积。
- 涉及数据库表结构变更或数据迁移的 PR。
- 涉及支付、权限、认证、对外接口协议变更的 PR。
- 跨多个服务或模块协作的大 PR,需要架构层面判断。
- 新人首次提交的代码,人工 review 是知识传递的关键。
- 任何被 AI 标记为 error 的问题,需要人来确认,而不是直接关闭流程。
这五个场景的共性在于,它们都需要项目上下文和业务判断,不能靠单文件 diff 完成。AI 可以提供辅助信息,但不能作为最终决策者。
7.2 落地 AI 审查的三个阶段
第一阶段,观察期。只把结果输出到终端和 PR 评论,不阻断合并流程。团队先确认误报率和可读性是否达到可接受范围。
第二阶段,规则期。接入静态检查工具和模型审查,error 级输出统一转为 PR 评论,并自动邀请维护者确认。此时可以开始统计问题分布、修改耗时、重复问题率。
第三阶段,门禁期。当误报率降到可接受水平后,再把 error 级问题接入 CI 阻断。同时配置降级按钮:当模型服务不可用或连续失败时,自动跳过审查,不让工具成为发布阻塞点。
7.3 上线前技术检查清单
这个清单可以直接复制到团队文档里,每次调整审查规则后逐项检查。
- 审查脚本在本地和 CI 使用相同 Python 版本和依赖版本。
- 模型接口密钥不写入代码仓库,统一放到环境变量或密钥服务。
- diff 截断长度与模型上下文窗口匹配,并确认截断后行号仍然准确。
- 提示词里明确输出 JSON 格式,并约定 level、file、line、message、suggestion 五个字段。
- 对模型输出做 JSON 解析失败兜底,失败时打印原始响应,方便定位。
- PR 评论采用先去重再写入的策略,避免同一 commit 被多次评论。
- error 级问题有明确处理入口,不直接无人跟进。
- 指定文件类型和目录白名单,不对生成文件和锁文件做审查。
- 保留最近一周的请求日志和错误日志,用于复盘误报和漏报。
- 每周固定抽查一次审查输出质量,持续调整提示词。
传统代码审查不会因为引入了 AI 就彻底消失,但它会被重新分工。机械化的检查和固定模式的缺陷识别,交给工具更合适;架构判断、业务理解和知识传递,仍然需要人来做。AI Engineer 的核心工作,是设计好这条分工边界,建立起从本地到 CI 的自动化审查链路,并且持续用真实 case 调优审查质量。这才是“终结代码审查”的正解:不是取消代码审查,而是让代码审查从团队的负担,重新变成一个稳定、可控、不依赖个人体力的质量保障环节。
如果你正准备在团队里落地 AI 审查,建议从一个小仓库开始。先在 VS Code 里跑通本地脚本,再把一个相对简单的服务接入 CI,运行两周,统计误报率和有效问题数。确认稳定后,再逐步扩展到核心业务仓库。没有一种审查方案能第一天就完美,能持续迭代的流程,才是能长期存在的流程。