先说结论省得你往下翻AI 写的代码把关的方式不是「看得更细」是「换个东西看」。代码对不对——交给机器但必须逼它真正跑起来不是嘴上说通过了。改动能炸多大——这才是留给人的活也是现在机器还替不了你的那一块。下面说我具体怎么干。一次 3 行的改动炸了三个项目我现在每天有十几个 Agent 同时给我干活。它们不吃饭、不睡觉、不摸鱼代码是成批往我这儿涌的。而我一个人两只眼睛。那天我 review 其中一个 Agent 提交的改动换个图标改了 3 行。我扫了一眼干净通过。第二天早上隔壁三个项目的构建全红了。那 3 行本身一点毛病没有。问题是那个静态资源目录是几十个子项目共用的仓库里塞着七十多个小应用都从那儿取图。AI 不知道我也没想起来。那天我想明白一件事我逐行看过、还点了头的代码炸点根本不在我看的那些行里。这不是我不够仔细。这是逐行 review 这件事到了 AI 时代已经行不通了。一、为什么逐行看是条死路第一快慢完全对不上。它 20 分钟写 800 行我一小时看 200 行。你哪是在看代码你是在被灌。看到第三个文件的时候你的眼睛已经在滑了——这时候你不是在把关你是在给自己制造「我看过了」的心理安慰。第二AI 的 bug 长得不像 bug。人写的 bug 有手感变量名打错、大小括号少一个、复制粘贴忘了改。你扫过去会「咯噔」一下。AI 不会犯这种错它的每一行都语法正确、命名规范、还配着注释。它错在它没写的那部分和它当成理所当然的那些事上。一句话人写的 bug 长得像 bugAI 写的 bug 长得像正确答案。第三炸点常常不在 diff 里。上面那 3 行就是。改动本身完美炸的是没出现在 diff 里的那七十多个项目。你把 diff 看穿了也看不见它——diff 只显示改了什么不显示碰了什么。二、第一关交给机器让它自己测但得是「真启动」「让 AI 自己写测试」这句话坑就坑在中间那两个字自己。你不给标准它一定给自己出最容易的那张卷子。骗局一编译过 ≠ 能跑现在的前端构建工具为了快默认不做类型检查——它把 TypeScript 的类型当注释直接剥掉只做语法转换。所以你少 import 了一个函数构建照样绿包也照样打出来用户点到那个按钮才崩控制台一行xxx is not defined。这就像过安检只称包的重量不看包里装了什么。轻就放行。我们线上真吃过这个亏而且吃过不止一次改动本身逻辑完全正确就是漏了一行 import全流程绿灯直达生产。骗局二单元测试全绿 ≠ 能跑AI 写单元测试有个极其稳定的坏习惯把所有依赖都换成假的。数据库返回什么它编接口返回什么它也编。然后被测的那段代码在这个由它亲手搭建的理想世界里跑得非常漂亮。这叫自己出题、自己判卷、自己打满分。真实的翻车长这样假数据里数据库返回一个规规矩矩的对象真库里那一列三年前存的是空值代码一拿来用空指针。测试 100% 覆盖率生产 100% 崩。一句话AI 写的测试默认在证明「我是对的」你得逼它去证明「我可能是错的」。所以必须真正启动跑集成测试有三类问题只有真的把服务起起来、连上真库、走一遍真接口才抓得到启动才炸两个 bean 重名、注入了实现类而不是接口、配置项拼错——编译的时候全对一启动就炸。数据和想象不一样库里的老数据长得跟你想的不一样。测试库是干净的生产库是有历史的。前后端对不上字段名对不上、类型对不上、时区差八小时、枚举多一个值。两边各自的单测都绿一联调就散。这三类恰恰是 AI 最容易翻车的三类——因为它写代码时看得见你的代码看不见程序真正跑起来是什么样。逼 AI 真测的四个动作可以直接抄验收标准你给别让它自选。「跑通」太模糊。要写成起服务调这个接口把接口返回的原文贴给我。要证据不要结论。它说「已验证通过」的时候八成没跑或者跑的是它自己拿假数据搭出来的世界。让它贴日志、贴返回内容、贴报错行。我被这句话骗过Agent 信誓旦旦说修复已生效我自己复现了一遍发现代码根本没走到那个分支。让它先写一个会失败的测试。测试得先挂一次再改到通过。AI 默认就写「一上来就过」的测试那种等于没写——它只是把现在的表现原样抄了一遍。把容易出事的情况点名。正常情况它一定会测出问题的情况它一定不测。你得点名依赖超时怎么办、返回空怎么办、用户手快点两下怎么办、这条数据已经被别人删了怎么办。做到这四条「对不对」这件事基本就不用你再盯着了。剩下的才是你的活。三、第二关留给人只看能炸多远人看代码本来就不该盯着「这行写错了没」——那件事机器比你细。人要回答的是另一个问题这个改动最多能牵连到谁我把它拆成三个圈一圈一圈往外看。越往外炸得越大。第一圈代码——这段东西有多少人在用新增一个文件、500 行影响范围是零炸也只炸自己。改一个公共方法、3 行影响整个仓库炸了全家一起。一句话diff 的行数和风险没关系引用数才有关系。所以看 diff 的第一件事不是读逻辑是看文件路径。路径里带 common、base、utils、assets、interceptor、公共组件目录的风险自动升一级——不管它只改了几个字符。好消息是数引用这件事正是 AI 最擅长的体力活。搜集让它干你只负责拍板。让它先交一份清单这次改动涉及的每个函数/文件/字段 列出仓库里所有引用它的位置 按「本模块内 / 跨模块 / 跨项目」分组给我。跨项目那一栏只要有东西这个改动就不能顺手放行。第二圈数据——新代码碰上老数据还能跑吗AI 看得见你的代码看不见你数据库里躺了三年的东西。典型翻车加一个非空字段存量几万行全是空的把整数换成枚举老行的值根本不在枚举里加了个布尔字段历史数据存的是空字符串读出来一转换直接崩。这类 bug 有个共同特征测试环境永远不炸生产必炸——因为测试库的数据是你上周才造的干净得像样板间生产库的数据是三年里各种历史版本、各种手工订正、各种导入失败留下的沉积岩。所以但凡改动碰到了字段、类型、状态值人必须问一句碰上库里最老、最脏的那一行还能跑吗第三圈时间——发版那一刻正在跑的怎么办这条最容易被漏掉因为它在代码里完全看不见。你发版的那一秒系统不是静止的有几十张单子正走在审批流程中间有用户正填着表单没提交有浏览器里跑着上个版本的前端包还有定时任务正跑到一半。改了流程定义没走完的老单子还钉死在旧版本上撤都撤不回来改了接口字段名用户手里的旧页面还在按老格式发请求。这就像火车还在跑你去换铁轨——光看图纸新轨道没有任何问题。三个圈之外再问三句最多能炸到谁说不清楚就别放行。说不清楚本身就是最大的危险信号。炸了多久能发现有没有告警、有没有日志。半小时发现和一周后被客户发现完全不是一个级别的事故。炸了能不能一键回滚能回滚的可以放宽不能回滚的必须最严——改过的老数据、发出去的消息、扣掉的钱都是回不来的。这三句话我在评审会上问了很多年。AI 来了之后我发现它们不但没过时反而是唯一还得人来干、AI 替不了的那部分。四、一张放行清单改动类型范围把关方式纯文案、纯样式、独立新页面小AI 自测跑通即可人扫一眼路径改业务逻辑本模块内中必须真启动跑一遍主流程 一条异常情况改公共组件 / 工具类 / 拦截器 / 共享资源大人必须看谁在用它有跨项目引用就单独过一遍动表结构、动字段类型、改库里的老数据最大先看老数据长什么样在有脏数据的库上验回滚脚本先写好动流程、状态机、定时任务最大必须回答正在跑的数据怎么办一句话概括这张表风险不看它改了多少看它碰了多少。最后以前我最得意的技能是扫一眼就看出这行有问题。这技能现在贬值得厉害——机器比我细比我快还不困。但有一样东西它没有它知道全世界怎么写才算好却不知道我们那个目录被七十多个项目共用不知道那张表三年前导进过一批脏数据不知道生产上还挂着一百多张走到一半的单子。AI 有全世界的知识但没有你们公司的记忆。所以把关不是看得更细是换个东西看对不对让它自己跑给你看能炸多大你自己判。我之前写过一篇《AI 帮我省下的时间最后全用来给它擦屁股了》说验 AI 的活比自己写还累。这篇算是那篇的下半场——累是因为你还在验它写得对不对。那件事该交给机器。你的活是判断它能炸多大。这活它干不了。因为它没在这家公司待过三年。说到「三年」这篇讲的是 AI 没有你们公司的记忆。反过来也一样你从一篇文章里能拿走的只有知识从一个人身上才能拿走标准——而后者同样要靠时间熬。我写过一篇《关注一个人是一种习惯熏陶》标题起得挺一般但里面那个故事我自己一直记得早年有个女生主动提出来跟我合租说想看看我是怎么学日语的。她很快过了二级速度惊人。然后她搬走了。不是吵架——跟高标准的人住在一起前三个月是激励第四个月开始是折磨。环境会传染但传染需要时间而大部分人会在传染完成之前跑掉。要是你打算在我这儿待够三年那篇值得看看。有想进「编程一生」用户交流群的朋友吗