因为公司给了 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,也不能替代测试,但很适合做提测前的自动化兜底。