☰
AI写代码必须过人工审查关:四条清单与两次打回实战
2026/10/15 12:31:57 网站建设 项目流程

1. 为什么我决定给 AI 写的代码加一道人工审查关

让 AI 写代码这件事,我从最早用它补全一个函数,到后来让它整文件整模块地生成,前后大概折腾了一年多。效率确实上来了,但踩的坑也足够写一本小册子。最典型的一次,AI 给我生成了一段看起来毫无问题的数据库查询逻辑,跑测试全绿,结果上线第二天就发现它在某个边界条件下会把整张表的敏感字段全查出来——因为它在拼接条件时"顺手"加了个恒真判断。从那以后我就定了个规矩:AI 可以写,但代码必须过我这道审查关,而且审查要有清单、有打回机制,不能凭感觉。

这篇东西就是把我这套审查流程完整摊开讲。核心是四条审查清单,配合两次强制打回节点。所谓"两次打回",指的是在流程里我设了两个必须停下来做判断的卡点:第一次打回发生在 AI 提交代码之后、进入测试之前,主要拦逻辑和权限层面的硬伤;第二次打回发生在测试通过之后、合并之前,主要拦那些"测试测不出来但会要命"的问题,比如权限边界、资源释放、隐式依赖。这两次打回不是形式主义,是我用真实事故换来的经验。

这套方法适合谁?如果你已经在用 Claude Code、各类 AI Agent 或者本地模型辅助写代码,并且开始把 AI 产出往真实项目里放,那这套清单你直接抄就行。如果你还停留在"AI 写完我扫一眼就提交"的阶段,那更要看——因为你现在省下的那几分钟审查时间,迟早会以几倍的调试成本还回来。下面我会把每条清单拆到能直接落地的颗粒度,包括具体查什么、怎么查、查到问题怎么处理,以及我在实操中总结的那些文档里不会写的细节。

2. 四条审查清单的整体设计与取舍逻辑

2.1 清单为什么是四条而不是十条

一开始我列了十几条审查项,结果发现根本执行不下去——人脑在审查代码时能同时保持的注意力焦点是有限的,清单太长就会变成走过场。后来我做了减法,把审查项按"出问题的后果严重程度"和"AI 最容易犯的概率"两个维度排序,最后收敛到四条。这四条覆盖了 AI 生成代码里 80% 以上的真实风险,剩下的长尾问题交给测试和运行时监控兜底。

这四条分别是:逻辑正确性、权限与边界、依赖与副作用、可维护性。注意顺序是有讲究的,不是随便排的。逻辑正确性放第一,因为它是根,逻辑错了后面全白搭;权限与边界放第二,因为这是 AI 最容易忽略、而后果又最严重的一类;依赖与副作用放第三,这类问题隐蔽性强,测试经常测不出来;可维护性放最后,因为它不致命但影响长期,放在最后是因为前三条不过关的代码根本不配谈可维护性。

提示:清单顺序本身就是优先级。审查时严格按顺序来,不要跳着看。我试过先看可维护性,结果被一段"写得很漂亮但逻辑是错的"代码骗过去,白白浪费半小时。

2.2 两次打回节点的位置选择

打回节点的位置比清单内容更关键。放早了,AI 还没写完你就打断,效率低;放晚了,问题已经混进测试甚至主干,清理成本高。我最终把第一次打回放在"AI 完成一个可运行单元之后、跑自动化测试之前",第二次放在"测试全绿之后、合并请求之前"。

为什么第一次要在测试之前?因为 AI 生成的代码经常是"测试友好型"的——它会顺着你给的测试用例去写,导致测试通过但真实场景崩。在测试之前拦一道,能逼着你先从逻辑和权限角度审视,而不是被绿灯迷惑。第二次放在合并之前,是因为有些问题只有在你准备把它并入主干、开始考虑它和现有代码如何共存时才会暴露,比如命名冲突、全局状态污染、隐式依赖。

2.3 清单和打回节点的配合关系

四条清单不是平均分配到两次打回里的。第一次打回重点查前两条——逻辑正确性和权限边界,这两条是"硬伤",不过关直接打回重写。第二次打回重点查后两条——依赖副作用和可维护性,这两条是"软伤",可以打回修改也可以带条件通过。这种分配的逻辑是:硬伤必须零容忍,软伤可以权衡。

打回节点触发时机重点清单处理方式
第一次打回AI 完成可运行单元后、测试前逻辑正确性、权限与边界硬伤直接打回重写
第二次打回测试全绿后、合并前依赖与副作用、可维护性软伤可修改或带条件通过

这个表格我贴在工位上,每次审查前扫一眼,避免自己偷懒跳过某个节点。实测下来,坚持这两个节点之后,我这边 AI 代码引发的线上问题下降了大概七成,剩下的三成基本是需求理解偏差,那属于另一个范畴的问题了。

3. 四条清单逐条拆解与实操要点

3.1 逻辑正确性:别被"看起来对"骗了

逻辑正确性是第一条,也是最难查的一条,因为 AI 生成的代码往往在语法和表面逻辑上都挑不出毛病。我的做法是分三层查:输入输出契约、边界条件、异常路径。

输入输出契约这一层,我会先不看实现,只看函数签名和注释,问自己"如果我是调用方,我期望它返回什么"。然后带着这个期望去读实现,看它是否真的满足。AI 特别容易在这里做"合理但错误"的假设,比如你让它写一个分页查询,它可能默认页码从 1 开始,但你的系统里页码从 0 开始,这种偏差测试用例如果也是 AI 写的,就会一起错,测不出来。

边界条件这一层,我有个笨办法但很有效:拿一张纸,把输入参数的所有边界值列出来——空值、零、负数、最大值、超长字符串、特殊字符,然后逐个在脑子里跑一遍。AI 生成的代码在正常输入下几乎不会错,错的全在边界。我踩过最坑的一次是 AI 写的一个金额计算函数,正常金额都对,但输入为 0 时它会返回一个极小负数,因为浮点精度处理没考虑零值,结果对账时差了 0.0001,查了一整天才定位到。

异常路径这一层,重点看 AI 有没有"吞异常"。AI 很喜欢写try...catch然后 catch 里什么都不做或者只打日志,这在它看来是"健壮",实际上是掩盖问题。我的标准是:catch 块里要么做有意义的恢复,要么往上抛,绝不允许静默吞掉。

注意:审查逻辑正确性时,一定要脱离 AI 给你的测试用例。我习惯自己手写三到五个"刁钻"的输入,专门挑 AI 测试没覆盖的角落。这一步花的时间,比后面 debug 省的时间多得多。

3.2 权限与边界:AI 最没概念、后果最严重的一类

权限问题是我把 AI 代码往生产环境放之后,遇到的最频繁也最危险的一类。原因很简单:AI 在生成代码时,它的"世界观"里没有你的权限体系。它不知道哪个数据库账号只能读、哪个目录只能写、哪个接口需要鉴权。它只会按功能逻辑写,权限全靠你补。

我审查权限时看三个点:数据访问范围、操作权限、资源边界。数据访问范围指的是这段代码能碰到哪些数据,有没有可能越权访问。比如 AI 写的一个查询,本意是查当前用户的数据,但它可能忘了加用户过滤条件,导致能查到所有人的数据。操作权限指的是这段代码执行的操作,当前运行身份有没有权限做,以及该不该做。资源边界指的是文件、内存、网络这些资源的使用有没有上限,AI 写的循环和递归经常没有终止保护。

这里有个我总结的快速判断法:问 AI 这段代码"最坏情况下能做什么"。不是问它设计意图,而是问它如果被恶意输入驱动,能造成什么后果。这个方法能快速暴露权限设计缺陷。比如一个文件处理函数,最坏情况下能不能删掉整个目录?一个查询接口,最坏情况下能不能拖垮数据库?如果答案是"能",那这段代码就必须加约束。

权限审查点常见 AI 失误我的检查动作
数据访问范围忘记加用户/租户过滤手动构造越权查询验证
操作权限用高权限身份执行低权限操作核对运行身份与最小权限原则
资源边界循环无上限、递归无终止检查所有循环和递归的退出条件

3.3 依赖与副作用:测试测不出来的隐形炸弹

依赖与副作用是第二次打回的重点,因为这类问题在单元测试里几乎测不出来。AI 生成的代码经常引入一些"顺手"的依赖,或者产生一些"看不见"的副作用,单个函数测试全绿,一集成到系统里就出问题。

我查依赖时看两点:显式依赖是否必要、隐式依赖是否存在。显式依赖就是 import 进来的那些库和模块,我会问"这个依赖真的需要吗,能不能用已有的替代"。AI 有时候会为了一个小功能引入一个巨大的库,增加打包体积和攻击面。隐式依赖更麻烦,比如代码依赖了某个全局变量的当前值、依赖了某个单例的初始化顺序、依赖了系统时间或环境变量,这些在测试环境里可能恰好是对的,到生产就崩。

副作用这块,我重点看全局状态修改、外部 IO、以及执行顺序敏感的操作。AI 写的代码经常在不该改全局状态的地方改全局状态,比如一个查询函数顺手更新了缓存,一个格式化函数顺手改了传入的对象。这类副作用在单测里如果没断言,就完全测不出来。我的做法是审查时专门找"这个函数除了返回值,还改变了什么",把所有副作用列出来,逐个判断是否合理。

提示:判断副作用是否合理,有个简单标准——函数名和注释有没有暗示这个副作用。如果函数叫getUserInfo却修改了数据库,那这个副作用就是隐藏的、危险的,必须打回。

3.4 可维护性:不致命但决定这段代码能活多久

可维护性放最后,不是因为它不重要,而是因为前面三条不过关的代码根本不值得谈可维护性。但一旦前面三条过了,可维护性就决定了这段 AI 代码是能长期用下去,还是三个月后你自己都不想碰。

我查可维护性看三点:命名是否表意、结构是否清晰、注释是否解释"为什么"。命名这块,AI 特别喜欢用data、result、temp、handle这种万能词,短期看没问题,长期看就是灾难。我的标准是:变量名要能回答"这是什么",函数名要能回答"它做什么",如果一个名字需要看实现才能理解,就得改。

结构清晰这块,AI 生成的代码经常是"一坨到底",一个函数几百行,中间嵌套好几层。我会看函数的圈复杂度和嵌套深度,超过一定阈值就要求拆分。注释这块,AI 写的注释经常是"复述代码",比如// 将 a 加 b 赋值给 c,这种注释毫无价值。我要的是解释"为什么这么做"的注释,比如"这里用位运算是因为性能敏感,实测比取模快三倍"。

4. 两次打回的完整实操流程

4.1 第一次打回:从 AI 提交到测试前的拦截

第一次打回的触发时机是 AI 完成一个可运行单元之后。什么叫"可运行单元"?我的定义是:能独立跑起来、能产生可观察输出的一段代码,可以是一个函数、一个类、一个接口。AI 说"写完了"之后,我不会立刻跑测试,而是先做第一次审查。

具体流程是这样的:先让 AI 自己复述一遍它写了什么、为什么这么写,这一步能暴露它自己的理解偏差。然后我按逻辑正确性和权限边界两条清单逐项过,每过一项在清单上打勾。发现硬伤就直接打回,打回时我会明确告诉 AI 问题在哪、期望是什么,而不是笼统地说"重写"。实测下来,给 AI 具体的错误描述和期望,它第二次改对的概率远高于笼统反馈。

第一次打回有个关键原则:只拦硬伤,不纠结风格。逻辑错了、权限越界了,打回;命名不好、注释不够,先记下来留到第二次。这样做的原因是第一次打回要快,要保证 AI 的迭代节奏,如果第一次就把所有问题都提出来,AI 容易改乱,你也容易失去重点。

4.2 第二次打回:测试通过后的最后一道关

第二次打回发生在测试全绿之后。这里有个反直觉的点:测试全绿恰恰是最危险的时候,因为你会放松警惕。我见过太多"测试全绿就合并"然后出事的案例,所以我把第二次打回设在这个位置,专门对抗这种松懈。

第二次审查重点查依赖副作用和可维护性。我会做几件事:把这段代码和现有代码放一起看,检查命名冲突和风格一致性;追踪它引入的所有依赖,评估必要性和风险;列出它所有的副作用,逐个判断合理性;最后通读一遍,问自己"三个月后的我能不能看懂这段代码"。

第二次打回的处理比第一次灵活。硬伤依然打回,但软伤可以带条件通过——比如命名问题可以合并后统一重构,注释缺失可以补一个 issue 跟踪。这种灵活性是为了不让完美主义拖慢交付,但前提是硬伤必须清零。

打回节点审查耗时(参考)打回率(我的实测)主要拦截问题
第一次打回10-20 分钟/单元约 40%逻辑错误、权限越界
第二次打回15-30 分钟/单元约 25%隐式依赖、副作用、命名混乱

4.3 打回之后怎么让 AI 改对

打回不是终点,让 AI 改对才是。我总结了一套"打回话术",核心是三段式:指出问题、说明后果、给出期望。比如不说"这个查询有问题",而说"这个查询没有加用户过滤条件(问题),会导致用户 A 查到用户 B 的数据(后果),请加上基于当前用户 ID 的过滤(期望)"。

这套话术的关键是"说明后果",因为 AI 对后果的理解比对人话的理解更敏感。你告诉它"这会导致越权",它下次生成类似代码时就会更注意权限。我试过只指出问题不说后果,AI 改是改了,但换个地方又犯同样的错;说了后果之后,它在同类场景下的表现明显改善。

还有一个技巧是让 AI 自己解释修改方案再动手。打回后我不直接让它改,而是先问"你打算怎么改",它说清楚了再让它写。这一步能拦住很多"改了但没改对"的情况,因为 AI 在解释时经常会自己发现方案有问题。

5. 常见问题与排查技巧实录

5.1 AI 代码审查的高频问题速查

审查 AI 代码这一年多,我整理了一份高频问题清单,基本覆盖了 90% 以上的打回原因。这份清单我放在手边,每次审查前扫一遍,能显著提高发现问题的速度。

问题类型典型表现排查动作处理方式
边界未处理空值、零值、极值下行为异常手动构造边界输入打回补边界处理
权限缺失查询/操作未加身份过滤构造越权场景验证打回加权限约束
异常被吞catch 块静默或只打日志搜索所有 catch 块打回补异常处理
隐式依赖依赖全局状态、初始化顺序追踪所有外部引用打回显式化依赖
副作用隐藏函数名与行为不符列出所有状态修改打回重构或改名
命名模糊data、result、temp 满天飞通读变量和函数名第二次打回统一改
循环无界循环/递归无终止保护检查所有退出条件打回加保护

5.2 那些文档里不会写的避坑经验

有些坑是我踩过之后才明白的,这里挑几个最有价值的说。第一个是不要相信 AI 的"我理解了"。你给它讲需求,它说理解了,然后写出来的东西经常和你的期望差十万八千里。我的对策是让它先复述需求再动手,复述不对就不让它写。这一步看似浪费时间,实际省了大量返工。

第二个是审查时关掉 AI 的自动补全。我试过一边审查一边开着补全,结果注意力被不断打断,漏掉了好几个问题。后来我审查时会把 AI 辅助功能全关掉,专心读代码。这个习惯养成后,审查效率反而提高了。

第三个是给 AI 的代码打标签。我会在 AI 生成的代码块上加注释标记,比如// AI-GEN: 待审查,审查通过后改成// AI-GEN: 已审查。这样过一段时间回头看,能清楚知道哪些代码是 AI 写的、审查到什么程度,方便后续维护和追责。

注意:AI 生成的代码不要和手写代码混在一起不加区分。我见过一个项目,半年后没人分得清哪些是 AI 写的,结果重构时不敢动,因为不知道改了会有什么连锁反应。

5.3 审查效率的优化技巧

审查 AI 代码是个体力活,效率优化很重要。我的几个技巧:批量审查同类代码,把相似功能的 AI 代码攒一起审,能形成模式识别,越审越快;建立个人问题库,把每次打回的原因记下来,定期回顾,慢慢就能预判 AI 会在哪里犯错;用清单对抗疲劳,人累了就容易漏查,清单能强制你走完流程。

还有一个反直觉的技巧:不要追求一次审完。我试过一口气审几百行 AI 代码,结果后面越审越马虎。后来改成每审 30 分钟休息一下,或者分两次审,准确率明显提高。审查质量比审查速度重要得多,因为漏掉一个权限问题,后面可能要花几天来补。

6. 我在这套流程里踩过的坑和最后的体会

这套四条清单两次打回的流程,不是一开始就设计好的,是我被坑出来的。最早我根本不审查,AI 写完直接提交,结果连续出了几次线上问题,才逼着我开始建流程。中间也走过弯路,比如清单列太长执行不下去,打回节点设错位置导致效率低下,这些都是试错试出来的。

现在回头看,这套流程最大的价值不是拦住了多少 bug,而是让我对 AI 生成的代码建立了"信任但要验证"的心态。AI 确实能大幅提升编码效率,但它的产出必须经过人的判断才能进生产环境。这个判断不能凭感觉,得有清单、有节点、有记录。

如果你打算用这套流程,我的建议是先从两条清单一个打回节点开始,跑顺了再加。一上来就全套,很容易因为太重而放弃。流程是为了服务交付的,不是为了流程本身。等你用顺了,会发现审查 AI 代码这件事,其实比审查人写的代码更有规律可循——因为 AI 的犯错模式是高度重复的,你摸清了它的套路,审查就会越来越快。

最后分享一个我最近在用的做法:把每次打回的原因喂回给 AI,让它自己总结"我容易犯哪些错",然后在下一次生成前先自查。这个做法让我的打回率又降了一截,因为 AI 开始学会在生成阶段就规避那些它常犯的问题。这个思路我觉得还能继续挖,等有更多数据了再单独写一篇。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询