11|CI、Hooks、测试:别相信 AI 说「应该没问题」
本篇是《从头重新学 AI 编程》系列第 11 篇。
对于很多非编程专业的朋友来说,这篇在 AI 编程中不是必须的,有了前面的知识,你基本上已经可以在一些简易的项目中得心应手了。而这篇属于在生产环境上的加强防护,算是能让你对 AI 编程的理解更加深入。
上一篇聊了 Skill,怎么把反复说的话固化成自己的模板。
这一篇聊一个你迟早会踩的坑,AI 写完代码跟你说「应该没问题」,你到底该不该信。
先讲一件事。
我让 AI 给一个待办应用加「批量删除」功能。AI 很快写完了,回了一句让我特别有安全感的话,已完成,添加了批量删除的 API 和前端按钮,测试已通过,代码没有问题。
我看了一眼,逻辑好像对,代码也挺整洁。点了合并。
然后线上炸了。
原因是它写的批量删除,没有检查这些待办项是不是属于当前用户。任何人只要猜到 ID,就能删别人的数据。
你说 AI 是故意骗我吗?不是。它跑的测试是它自己写的,那个测试只测了「能不能删成功」,根本没测「能不能删别人的」。在它的世界里,测试确实过了,代码确实没问题。
这就是 Vibe Coding 里我觉得最危险的一个瞬间,你信了 AI 那句「没问题」。
为什么会这样?因为你让 AI 自己写代码、自己写测试、自己跑测试、自己说没问题。这就像让考生自己出卷子、自己批卷子,那分数当然好看。

所以你需要的不是更聪明的 AI,是几道不归 AI 管的防线。我自己梳理下来是三道,每一道拦的东西都不一样。
第一道,叫 Hooks,作用是事前拦截。
你在 AGENTS.md 里写的那些规则,其实是软约束。你写了「不要改 migration 文件」,AI 可能记住,也可能聊到第二十轮就忘了。Hooks 不一样,它是硬约束,在 AI 执行操作的那一瞬间,用脚本去检查,不合规直接给你拦下来。
打个比方,AGENTS.md 是贴在门口那张「请勿吸烟」的告示,Hooks 是烟雾报警器加自动喷淋。一个靠自觉,一个直接动手。
它能拦的事情挺多的。AI 要执行 rm -rf 或者 git push --force,直接阻断。AI 改完文件忘了格式化,自动补一道 prettier。AI 想去读 .env 文件,拦住,提醒它走环境变量。会话一开始,自动提醒它先读 AGENTS.md。
以我们这个待办应用为例,你可以配一个 hook,让 AI 每次改完 .ts 文件就自动跑一遍 lint。
{
"hooks": {
"afterFileEdit": [
{
"matcher": "*.ts",
"command": "npx prettier --write $FILE && npx eslint --fix $FILE"
}
]
}
}
配好之后,AI 写的每一行 TypeScript,出来就是格式化好的,你完全不用操心。
Hooks 跟 AGENTS.md 的分工其实很清楚。AGENTS.md 告诉 AI 应该怎么做,Hooks 直接拦住它不该做的。一个动嘴,一个动手。

但 Hooks 有个管不到的地方,它拦得住危险命令和格式问题,拦不住逻辑错误。前面那个「批量删除没检查权限」的坑,Hooks 一点办法都没有,因为那段代码格式完美、命令也不危险,它就是逻辑上少了一刀。
这种问题,只有测试能抓出来。这就是第二道防线。
但这里有个关键的顺序问题。在 Vibe Coding 里,测试不是写完代码再补的东西,而是先定「什么算对」,再让 AI 去写。
你跟 AI 说「帮我加个批量删除」,它上来就开写了。但如果你换个说法,
先不要写实现。帮我列一下批量删除这个功能,需要测哪些场景。
它会给你一份测试计划,大概像这样。
1. 正常删除,选中 3 个待办,删除成功,列表更新
2. 空选,没选任何项就点删除,提示请先选择
3. 权限校验,尝试删除不属于自己的待办,返回 403
4. 部分失败,选中 5 个,其中 1 个不存在,其余 4 个正常删除
5. 并发,两个人同时删同一个待办,不报错
你扫一眼就会发现,第 3 条「权限校验」,AI 自己写实现的时候大概率是想不到要测的。那你现在就把它摁在这儿,确认它会覆盖到,然后再让它写代码。
这里有个原则我想说重一点,永远不要让 AI 实现完再补测试。因为它补的测试会刚好贴着它写的实现来,实现里有什么 bug,测试就跟着绕过什么 bug,俩一起糊弄过去。先定标准再写代码,测试才是在考它,而不是在配合它。
测试定好了,还有个现实问题,你不可能每次 AI 一改代码你就手动跑一遍。这事得自动化,那就是 CI。
一份最小的 CI 配置,拿 GitHub Actions 举例,长这样。
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
就四步,装依赖、跑 lint、跑测试、跑构建。任何一步挂了,整个 CI 红灯,代码合不进去。
你还可以在 AGENTS.md 里加一条,让 AI 主动配合 CI。
## CI 规则
1. 提交前必须本地跑过 npm run check,确保通过
2. 如果 CI 挂了,先看失败日志,不要猜测式修复
然后在 package.json 里加一个命令,让本地检查跟 CI 跑的完全一样。
{
"scripts": {
"check": "npm run lint && npm test && npm run build"
}
}
这样 AI 改完能自己先跑一遍 check,不用傻等 CI 跑五分钟才发现挂了。

聊到这,你可能觉得,CI 绿了,测试过了,这下总该万事大吉了吧。
还真不是。
CI 能证明的,是代码能构建、测试能跑过。但它证明不了一件更重要的事,功能方向对不对、设计合不合理、有没有顺手改了不该改的东西。这些是机器看不出来的,得靠 review。这就是第三道防线。
还记得第 7 篇讲的 Subagent 吗?我当时说,实现和审查不能共用一个上下文。这里就是最典型的应用场景。写代码的那个 AI,已经为自己的方案辩护了好几轮了,你再让它回头审自己的 diff,结果几乎一定是全绿,它怎么可能说自己写得不好。
正确的做法是另开一个干净的会话,让一个没参与过实现的 AI 来审。
你是 code reviewer,只读,不准改代码。
输入,
- AGENTS.md,项目约定
- git diff,这次的改动
输出要求,
1. diff 有没有超出这次任务的范围
2. 有没有顺手改了无关文件
3. 测试覆盖了哪些场景,哪些没覆盖
4. 有没有新增依赖,有没有碰 auth、权限、密钥
5. 按严重程度列出问题,blocking、question、nit
这个 review agent 只看 diff,没参与过实现,上下文是干净的。它不会因为「这段代码是我写的」而手下留情。一个旁观者,永远比当事人更容易看出问题。
把这三道防线串起来,AI 写完代码、你合并之前,其实就是过一份提交前的清单。
提交前 checklist
格式和规范
- [ ] lint 通过
- [ ] 类型检查通过
- [ ] 格式化一致
逻辑和测试
- [ ] 测试覆盖了正常流程
- [ ] 测试覆盖了边界情况,空值、权限、并发
- [ ] 自己跑了测试、看了输出,不是只信 AI 说的过了
范围和设计
- [ ] diff 没有超出这次任务
- [ ] 没有顺手改无关文件
- [ ] 没有无理由新增依赖
- [ ] 没有碰 auth、权限、密钥
文档
- [ ] 公开行为变了,文档同步了
你可以把这段贴进 AGENTS.md,让 AI 每次提交前自己先过一遍。但有句话我得说清楚,AI 自己过 checklist 只是第一轮,你自己过那一遍,才是最终确认。
说到这个,我还想给你一个我每次都会用的指令。AI 实现完功能之后,别让它甩给你一句「已完成」,你这么跟它说。
实现完成后,不要直接总结「已完成」。先输出,
1. 修改了哪些文件,每个文件为什么改
2. 跑了哪些测试,输出是什么
3. 哪些测试没跑,为什么
4. 还有什么风险是我需要自己检查的
这段话的目的,就是逼它把证据摆出来,而不是给你一句感觉。
「应该没问题」不是验证结果。「测试跑了,输出贴在这」才是。这两句话的差别,就是工程和碰运气的差别。

顺着这个再多说一句,关于「测试要自己跑」这件事,我想专门拎出来强调,因为它实在太常见了。
AI 跟你说「测试通过了」,你信了。但你可能不知道,它说这句话的时候,背后可能是这么几种情况。它跑的是旧测试,新代码的测试压根没加进去。或者它改的是测试本身,让测试去迁就实现,而不是改实现。再或者,它根本没跑,只是「预计会通过」。
所以,永远不要信 AI 那句「我跑过了」。让它把命令和输出贴出来,或者你自己跑一遍。
这不是不信任 AI,这是工程纪律。你让一个同事改完代码,也得自己跑一遍测试才敢合,对 AI 凭什么放宽。
回过头看这三道防线,加上 AGENTS.md,其实是四层东西在配合。
AGENTS.md 管软约束,约定、风格、红线,AI 偶尔忘了也不至于出大事。
Hooks 管硬拦截,危险命令、格式、敏感文件,因为操作一旦执行就撤不回来了。
测试和 CI 管事后验证,逻辑错误、回归 bug,漏了就会混进主分支。
Review 管合并前的最后把关,方向偏差、设计问题、AI 自己审不出来的盲区。

四层叠在一起,才是一道完整的护栏。少了任何一层,都会在某个时刻给你来一下。
我有时候会把它类比成开车。安全带、气囊、刹车、后视镜,平时你一个都用不上,但少哪个你心里都不踏实。写代码也一样,尤其是 AI 写的代码,它量大、速度快、看着特别专业,但「看着对」和「真的对」之间,差的就是这几道你愿不愿意搭起来的防线。
给你一个小练习。
下次你让 AI 写完一个功能,别急着合。先按上面那份 checklist 过一遍,自己跑一次测试,再开一个新会话让另一个 AI 审一下 diff。你体会一下「证据都在手里」的那种踏实,跟以前「AI 说没问题我就信了」的那种忐忑,完全是两种感觉。
下一篇是第 12 篇,也是正文的最后一篇。我们聊 AI Coding 的反模式清单,那些真能把项目搞失控的错误,以及怎么躲开它们。
作者声明本文无利益相关,欢迎值友理性交流,和谐讨论~
