提测前让 AI 检查一下代码,我的 Bug 率降低了 20%

因为公司给了 Cursor 的席位,所以本文主要以前端使用 Cursor CLi 的视角来说,Claude Code 或者其他 AI 工具也可以用这一套工作流,后端也可以用类似的流程。

先说说标题,这里不是说 AI 能直接把项目质量提升 20%,也不是说它能替代测试、Code Review 或自测。我这里说的 Bug 率下降,指的是在提测前多加了一道 AI Review 流程之后,测试阶段暴露出来的低级问题明显少了。

比如这些问题:

text 复制代码
接口字段为空导致页面白屏
按钮重复点击导致重复提交
loading / empty / error 状态漏处理
接口字段改名后没有兼容旧数据
权限按钮展示条件漏了某个状态
异常被吞掉,测试环境只看到"操作失败"

这些 Bug 不一定复杂,但很消耗测试和开发的沟通成本。以前经常是提测之后测试同学点出来,开发再回去修。后来我在提测前加了一步:用脚本自动提取本次 git diff,交给 Cursor CLI 做一次代码审查,然后输出一份 Markdown 报告

最后落到项目里,就一个命令:

bash 复制代码
npm run ai-review

跑完会生成:

text 复制代码
.review/ai-review.md

这份 Markdown 就是提测前的 AI Review 报告。

它不会替你写业务逻辑,也不会保证"零 Bug"。但对于一些低级、重复、容易漏看的问题,它确实能提前拦下一部分。对我来说,这一步最大的价值不是"让 AI 证明代码没问题",而是:在提测前先让 AI 帮我扫一遍本次改动,把明显风险暴露出来


为什么是提测前,而不是上线前?

很多团队会把 AI Review 放到上线前,作为发布前最后一道兜底。这当然也有价值。

但我更建议把它前移到提测前。

原因很简单:越晚发现问题,修复成本越高。

上线前发现问题,往往已经进入发布窗口,大家的关注点是"能不能发"。这时候再改代码,容易引入新的不确定性。提测前发现问题就不一样了,此时需求还在开发流转阶段,修复、补测、重新自测都更从容。

这一步不是替代测试,而是减少一些"不该流到测试阶段的问题"。

尤其是前端项目,很多 Bug 并不是编译错误,而是状态边界没兜住:空数据、慢接口、重复点击、弹窗重置、权限展示、接口字段兼容。这些问题靠 人工检查代码不一定能发现,但 AI 基于 diff 做一次 Review,反而有机会提醒出来。


为什么用 git diff,而不是让 AI 扫整个项目?

很多人第一次用 AI 审代码,会直接问:

text 复制代码
帮我检查当前分支有没有问题

这个问法通常效果不好。

项目太大,上下文太散,AI 很容易给出一些正确但没用的建议,比如:

text 复制代码
建议补充单元测试
建议优化异常处理
建议增强代码可读性
建议完善注释

这些建议当然不能说错,但对"这次能不能提测"帮助有限。

提测前真正要看的不是整个项目,而是:

text 复制代码
这次到底改了什么?
这些改动有没有明显风险?
有没有可能导致测试阶段直接报 Bug?
有没有可能影响老逻辑、老数据、旧接口?

这就是 git diff 的价值。

git diff 天然就是本次改动的边界。把 AI Review 的范围限制在 diff 里,输出会更聚焦,也更接近真实 Code Review 的思路。

所以这套流程的核心不是"让 AI 扫项目",而是:

text 复制代码
自动生成本次 git diff
自动调用 Cursor CLI 审查
自动输出 Markdown 报告
开发者人工确认报告里的风险

最终使用方式

配置完成后,提测前只需要执行:

bash 复制代码
npm run ai-review

默认比较:

text 复制代码
origin/main...HEAD

也就是当前分支相对 origin/main 的所有变更。

如果你本机 Cursor CLI 命令不是 agent,而是 cursor-agent,可以这样执行:

bash 复制代码
CURSOR_CLI=cursor-agent npm run ai-review

执行完成后,直接打开报告:

bash 复制代码
cat .review/ai-review.md

项目里会生成几个辅助文件:

text 复制代码
.review/release.stat       # 改动统计
.review/release.files      # 改动文件列表
.review/release.diff       # 完整 diff
.review/review-prompt.md   # 本次 Review 使用的 Prompt
.review/ai-review.md       # 最终 AI Review 报告

其中最重要的是 .review/ai-review.md。提测前主要看这份文件即可。


准备工作

先确认本机已经安装 Cursor CLI。

官方安装方式一般是:

bash 复制代码
curl https://cursor.com/install -fsSL | bash

安装后可以看一下命令是否可用:

bash 复制代码
agent --version

有些环境或旧教程里命令名可能还是:

bash 复制代码
cursor-agent --version

下面默认用 agent 演示。如果你的本机命令是 cursor-agent,可以通过环境变量切换:

bash 复制代码
CURSOR_CLI=cursor-agent npm run ai-review

Cursor CLI 支持在终端或 headless 环境中使用 Agent,也支持脚本化、自动化场景;-p / --print--output-format--mode ask 等参数可以用于非交互式执行。([Cursor][1])


第一步:添加 npm script

package.json 里增加一个脚本:

json 复制代码
{
  "scripts": {
    "ai-review": "node scripts/ai-review.mjs"
  }
}

这样团队成员不需要记住具体脚本路径,也不需要关心底层到底执行了哪些命令。只要会跑项目里的 npm script,就能使用这套提测前检查流程。

后续统一约定为:

bash 复制代码
npm run ai-review

这个命令会自动完成三件事:

text 复制代码
1. 自动对比 origin/main...HEAD
2. 自动生成本次 diff 文件
3. 自动调用 Cursor CLI 输出 Markdown 审查报告

第二步:新增自动审查脚本

新建文件:

text 复制代码
scripts/ai-review.mjs

脚本内容如下:

js 复制代码
import { execFileSync } from 'node:child_process';
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const rootDir = resolve(__dirname, '..');

const baseBranch = process.argv[2] || 'origin/main';
const target = process.argv[3] || 'HEAD';
const cursorCli = process.env.CURSOR_CLI || 'agent';

const reviewDir = resolve(rootDir, '.review');
const statFile = resolve(reviewDir, 'release.stat');
const filesFile = resolve(reviewDir, 'release.files');
const diffFile = resolve(reviewDir, 'release.diff');
const promptFile = resolve(reviewDir, 'review-prompt.md');
const outputFile = resolve(reviewDir, 'ai-review.md');

const ignorePaths = [
  ':!dist',
  ':!build',
  ':!coverage',
  ':!node_modules',
];

function run(command, args, options = {}) {
  return execFileSync(command, args, {
    cwd: rootDir,
    encoding: 'utf8',
    stdio: options.stdio || ['ignore', 'pipe', 'pipe'],
  });
}

function write(file, content) {
  writeFileSync(file, content, 'utf8');
}

function hasOriginRemote() {
  try {
    run('git', ['remote', 'get-url', 'origin'], { stdio: 'ignore' });
    return true;
  } catch {
    return false;
  }
}

function ensureReviewDir() {
  if (!existsSync(reviewDir)) {
    mkdirSync(reviewDir, { recursive: true });
  }
}

function generateDiffFiles() {
  const range = `${baseBranch}...${target}`;
  const pathspec = ['--', '.', ...ignorePaths];

  write(statFile, run('git', ['diff', '--stat', range, ...pathspec]));
  write(filesFile, run('git', ['diff', '--name-only', range, ...pathspec]));
  write(diffFile, run('git', ['diff', '--unified=80', range, ...pathspec]));
}

function generatePrompt() {
  const prompt = `你现在是一名资深前端代码审查员,请基于本次 git diff 做提测前 Review。

请读取以下文件:
- .review/release.stat:改动统计
- .review/release.files:改动文件列表
- .review/release.diff:完整代码 diff

Review 目标:
找出本次变更中可能在测试阶段暴露为 Bug 的风险点,重点关注业务正确性、运行时稳定性、接口兼容性和用户操作边界。

请重点检查:
1. 是否有 undefined、null、空数组、空对象导致的运行时错误
2. 是否有接口入参、出参、字段名、字段类型的兼容性问题
3. 是否有权限、鉴权、越权访问或权限展示问题
4. 是否有重复请求、请求竞态、按钮重复提交问题
5. 是否有 loading、error、empty 状态缺失问题
6. 是否有弹窗、表单、分页、筛选条件状态没有重置的问题
7. 是否有缓存更新、缓存失效、缓存脏数据问题
8. 是否有异常处理不完整,或者错误被吞掉的问题
9. 是否有配置、环境变量、灰度开关缺失默认值的问题
10. 是否有埋点、日志缺失,导致问题难以定位
11. 是否有回滚风险,或者新旧逻辑不能兼容的问题

输出格式:

## Review 结论

用一句话说明是否建议提测。如果存在 P0,请明确写"不建议提测"。

## P0 阻塞提测问题

没有则写"无"。

## P1 高风险问题

没有则写"无"。

## P2 建议优化

只写和本次 diff 强相关的建议,不要输出套话。

## 人工确认项

列出 AI 无法完全判断、但提测前应该人工确认的事项。

要求:
- 只基于本次 diff 分析,不要泛泛而谈。
- 每个问题都要写清楚:文件、问题描述、风险、建议修改、是否阻塞提测。
- 不要评价代码风格,除非它会导致真实 Bug。
- 不要输出"建议补充单元测试"这种空泛建议,除非能指出具体应该测试哪个分支。
- 如果 diff 信息不足,可以明确说明需要补充哪个文件或哪段上下文。
- 如果没有明显问题,直接说明"未发现阻塞提测问题",不要硬凑建议。
`;

  write(promptFile, prompt);
  return prompt;
}

function runCursorReview(prompt) {
  const result = run(cursorCli, [
    '-p',
    '--mode',
    'ask',
    '--output-format',
    'text',
    prompt,
  ]);

  write(outputFile, result);
}

function main() {
  ensureReviewDir();

  console.log(`Base branch: ${baseBranch}`);
  console.log(`Target: ${target}`);
  console.log(`Cursor CLI: ${cursorCli}`);

  if (hasOriginRemote()) {
    console.log('Fetching origin...');
    run('git', ['fetch', 'origin', '--prune'], { stdio: 'inherit' });
  }

  console.log('Generating git diff files...');
  generateDiffFiles();

  console.log('Generating review prompt...');
  const prompt = generatePrompt();

  console.log('Running Cursor CLI review...');
  runCursorReview(prompt);

  console.log(`AI review report generated: ${outputFile}`);
}

main();

这个脚本做了几件事:

text 复制代码
1. 默认比较 origin/main...HEAD
2. 生成改动统计、改动文件列表、完整 diff
3. 自动写入提测前 Review Prompt
4. 调用 Cursor CLI 做只读审查
5. 把结果写入 .review/ai-review.md

第三步:运行 npm run ai-review

配置好以后,直接执行:

bash 复制代码
npm run ai-review

控制台大概会输出:

text 复制代码
Base branch: origin/main
Target: HEAD
Cursor CLI: agent
Fetching origin...
Generating git diff files...
Generating review prompt...
Running Cursor CLI review...
AI review report generated: /your-project/.review/ai-review.md

然后查看报告:

bash 复制代码
cat .review/ai-review.md

如果想在编辑器里看,也可以直接:

bash 复制代码
code .review/ai-review.md

这时候 .review/ai-review.md 里会有类似这样的结构:

markdown 复制代码
## Review 结论

未发现阻塞提测问题,但有 2 个 P1 风险建议提测前确认。

## P0 阻塞提测问题

无。

## P1 高风险问题

...

## P2 建议优化

...

## 人工确认项

...

相比直接把 Cursor CLI 的输出打印在终端里,生成 Markdown 文件有几个好处:

text 复制代码
1. 方便贴到需求卡片、MR / PR 评论或提测说明里
2. 方便作为提测前检查记录保存
3. 方便团队复盘哪些问题是在提测前被拦下的
4. 修完问题后可以重新跑一遍,对比前后报告

我一般重点看报告里的哪些内容?

Cursor CLI 生成报告后,不要只看最后一句"建议提测"或者"不建议提测"。

我一般重点看三块。

1. P0 阻塞提测问题

P0 一般是提测前必须处理的问题,比如:

text 复制代码
新增页面直接读取 data.list[0].name,但接口返回空数组时会报错。

或者:

text 复制代码
提交按钮没有禁用,连续点击可能发起多次创建请求。

这种问题只要命中,就不要纠结是不是 AI 误判,直接回到代码里人工确认。

如果确实成立,就先修掉再提测。

2. P1 高风险问题

P1 不一定马上阻塞,但很可能在测试阶段被打回来。

比如:

text 复制代码
接口字段从 userName 改成 username,但页面里仍然读取旧字段,历史缓存数据可能展示为空。

或者:

text 复制代码
弹窗关闭后没有重置表单状态,再次打开时可能带出上一次填写的数据。

这类问题要结合业务场景判断。有些必须马上修,有些可以和产品、测试确认后再决定。

3. 人工确认项

这个部分很有价值。

因为 AI 不一定知道测试环境配置、后端接口状态、灰度策略和历史数据情况。它如果能提示:

text 复制代码
需要确认 VITE_xxx 开关是否已经在测试环境配置默认值。

或者:

text 复制代码
需要确认后端是否已经兼容新增字段为空的情况。

这类信息比单纯指出代码问题更贴近提测流程。


前端项目里最容易被提前扫出来的问题

我主要是前端视角,所以这里重点说前端项目。

1. 空数据导致页面崩溃

前端很多线上或测试环境问题不是语法错误,而是接口数据不符合预期。

比如:

js 复制代码
const name = user.profile.name;

如果 profile 为空,页面就直接崩了。

AI Review 很适合帮忙扫这类问题,尤其是 diff 里出现了新的字段访问、新的数组取值、新的对象解构时。

2. loading / error / empty 状态缺失

常见问题包括:

text 复制代码
请求中按钮没有禁用
接口失败没有错误提示
空数组没有空状态
接口慢时页面展示旧数据
弹窗关闭后状态没有重置

这些问题本地自测不一定稳定复现,但测试同学很容易点出来。

3. 接口字段兼容性

比如后端把字段从:

js 复制代码
userName

改成:

js 复制代码
username

如果前端没有做兼容,老接口、缓存数据、灰度环境都可能出问题。

所以我会让 Prompt 明确检查:

text 复制代码
接口入参、出参、字段名、字段类型是否兼容

4. 重复请求和请求竞态

比如搜索框、筛选项、分页切换、弹窗提交,这些地方很容易出现请求时序问题。

典型场景是:

text 复制代码
用户先搜 A,再搜 B
B 请求先返回,A 请求后返回
页面最后展示成 A 的结果

这种问题人工 Review 有时会漏,AI 对 diff 做状态流分析时反而能提醒一下。

5. 权限展示和按钮禁用逻辑

前端权限问题不一定是安全边界,但会影响用户操作体验。

比如:

text 复制代码
无权限用户看到了操作按钮
按钮置灰条件漏了某个状态
审批完成后还能继续点击提交

这类问题如果出现在提测 diff 里,也值得在报告里单独列出来。


AI 发现问题后,要不要让它顺手修?

可以,但我不建议把"自动修复"做进 npm run ai-review 这条命令里。

npm run ai-review 的职责应该很单一:

text 复制代码
自动比对本次代码变更
自动生成 Review 报告
把风险点暴露出来

至于后面的修复动作,应该由开发者看完报告后主动发起

比如报告里提示某个组件可能存在 undefined 访问风险,开发者确认后,可以再单独让 AI 辅助修改:

text 复制代码
请根据 .review/ai-review.md 中提到的 P1 问题,帮我修复 UserTable.vue 里的空值兜底问题。
要求:只修改这个问题相关代码,不要顺手重构其它逻辑。

或者更收敛一点:

text 复制代码
请只修复 UserTable.vue 中接口字段为空时页面崩溃的问题。
不要修改样式,不要调整其它业务逻辑。

这样做有两个好处。

第一,Review 和 Fix 是两个不同阶段。Review 阶段只负责发现问题,不应该直接改变工作区代码。这样即使 AI 有误判,也不会把误判变成代码改动。

第二,用户主动发起修复,可以保留人的判断权。哪些问题是真问题,哪些是误报,哪些需要现在修,哪些可以放到后续优化,应该由开发者结合业务上下文决定。

所以更稳妥的链路应该是:

text 复制代码
npm run ai-review
查看 .review/ai-review.md
人工确认问题是否成立
确认后再让 AI 针对单个问题修复
人工 Review AI 的修改
重新执行测试和 npm run ai-review

不建议做成:

text 复制代码
npm run ai-review
AI 自动发现问题
AI 自动修改代码
AI 自动提交

这类全自动链路看起来很省事,但风险很明显:AI 可能误解业务规则,可能顺手改掉无关逻辑,也可能把一个局部问题修成更隐蔽的问题。

我的建议是:AI 可以参与修复,但修复必须是用户主动触发的动作,不要作为 npm run ai-review 的默认自动化能力。

总结

用 Cursor CLI 配合 git diff 做提测前代码审查,本质上不是"让 AI 帮我 Review 整个项目",而是把问题收敛到一个具体范围:

text 复制代码
本次改动有没有可能在测试阶段暴露为 Bug?

比较推荐的落地方式是:

text 复制代码
package.json 增加 npm run ai-review
Node 脚本自动生成 git diff
Cursor CLI 只读审查本次 diff
自动输出 .review/ai-review.md
人工确认 P0 / P1 / 人工确认项
确认问题成立后,再由开发者主动让 AI 辅助修复
修复后重新跑一遍
再提测

它不能替代 Code Review,也不能替代测试,但很适合做提测前的自动化兜底。

相关推荐
光影少年1 小时前
react的 useState 原理、批量更新机制
前端·react.js·掘金·金石计划
叫我少年1 小时前
Markdown 备忘清单
前端
酒吧舞高材生1 小时前
vue3 PC端-索引列表组件
前端·vue.js
2301_780789661 小时前
多层级 CC 防护体系:前端验证与后端限流的协同配置实践
运维·服务器·前端·网络安全·智能路由器·状态模式
ZC跨境爬虫1 小时前
跟着MDN学HTML_day_47:(Document接口)
前端·javascript·ui·html·ecmascript·音视频
学习论之费曼学习法1 小时前
ReAct框架深度解析:让Agent会思考再行动
前端·react.js·前端框架
前端 贾公子1 小时前
从零开始:使用Node.js和Cheerio进行轻量级网页数据提取
前端·vue.js
阿星做前端1 小时前
不想再给ai回复下一步了,于是我给agent装上了一个自动挡
前端·后端·程序员