
1. 当AI把代码写完审查这件事到底变了什么先说一个我自己的真实场景。上个月我让 Claude Code 帮我重构一个老项目的日志模块需求描述写了大概三行它一口气吐了四百多行代码结构清晰、命名规范、异常处理也补上了。我当时的第一反应是爽第二反应是我该从哪里看起。四百行代码如果按以前那种逐行审查的习惯一行一行读下来至少四十分钟而且读到后面注意力早就散了真正有问题的分支逻辑大概率会被我漏掉。这个场景其实代表了很多人在用 AI 编程工具之后的共同困惑代码的生产速度被拉高了一个数量级但审查的速度没有同步提升。以前一天写两百行审查两百行节奏是匹配的。现在 AI 十分钟给你四百行你如果还用老办法逐行看审查就成了整个流程里最慢的一环甚至比手写还累。所以问题不是要不要审查而是审查的粒度、顺序和重点应该怎么重新设计。逐行审查在 AI 编程时代不是被淘汰了而是被重新定位了——它从默认动作变成了针对性动作。你需要先判断哪些代码值得逐行看哪些只需要看接口和边界哪些可以直接靠测试兜底。这篇文章我想聊的就是这件事在 AI 大量产出代码的前提下一个从业者应该怎么重新组织自己的审查流程。我会结合 Claude Code、agent 类工具的实际使用经验讲清楚审查策略怎么分层、哪些地方最容易出问题、以及我自己踩过的几个坑。不管你是刚接触 AI 编程的新手还是已经在用 agent 做开发的熟手应该都能从中找到可以直接用的方法。2. AI 生成代码的信任分层不是所有代码都值得逐行读2.1 为什么逐行审查在 AI 场景下会失效传统手写代码时逐行审查之所以有效是因为代码是你自己思维的延伸。你读自己的代码其实是在回忆当时的决策过程大脑会自动补全上下文读起来很快。但 AI 生成的代码不一样它的决策过程你完全没参与每一行对你来说都是陌生代码。陌生代码的阅读速度天然就慢因为你需要重建它的逻辑链路。更麻烦的是AI 生成的代码往往表面质量很高。命名规范、注释齐全、格式整齐这会给你一种看起来很靠谱的错觉让你的注意力不自觉地放松。但实际上真正容易出问题的地方——边界条件、并发时序、错误恢复路径——恰恰藏在那些看起来最正常的代码里。我做过一个粗略的统计在我用 Claude Code 生成的代码里语法错误几乎为零格式问题几乎为零但边界条件处理不当的比例大概在 15% 左右。也就是说你逐行读一遍可能 85% 的时间花在了没问题的代码上真正有问题的 15% 反而因为注意力疲劳被漏掉。2.2 按风险等级给代码分层我的做法是拿到 AI 生成的代码后先不读先分类。分类的依据是这段代码出错的后果有多严重而不是它有多复杂。风险等级代码类型审查策略典型例子高涉及资金、权限、数据删除逐行审查 单元测试 人工复核支付扣款、用户鉴权、批量删除中核心业务逻辑、状态机重点审查分支和边界订单状态流转、任务调度低工具函数、格式化、日志看接口 跑测试日期格式化、字符串处理极低配置、常量、类型定义扫一眼即可枚举定义、配置文件这个分层的关键在于你的注意力是有限资源要花在后果最严重的地方。一段格式化日期的函数写错了最多是显示难看一段扣款逻辑写错了那是真金白银的损失。把这两者用同样的审查强度对待本身就是一种资源浪费。2.3 一个具体的分层实例举个我实际遇到的例子。我让 Claude Code 写一个用户积分过期清理的任务它生成的代码大概包含这几块查询过期积分、批量更新状态、写操作日志、发送通知。我当时的处理是查询过期积分这段涉及数据库查询条件如果条件写错可能误删有效积分属于高风险我逐行看了 WHERE 条件确认时间边界用的是还是确认时区处理是否正确。批量更新状态涉及数据写入中高风险我重点看了它有没有做分批处理防止一次更新太多行锁表以及失败回滚逻辑。写操作日志低风险我只看了它记录的字段够不够排查问题没逐行读。发送通知低风险而且通知发多发少不影响数据我直接跳过逐行审查靠后面的集成测试验证。这样一套下来真正逐行读的代码大概只占 30%但覆盖了 90% 的风险。剩下的 70% 用测试和抽查兜底整体审查时间从预估的四十分钟压缩到了十五分钟左右。提示分层不是偷懒而是把审查从均匀用力变成重点用力。前提是你对业务的风险点有清晰判断这个判断力恰恰是 AI 替代不了的。3. 审查顺序的重排先看契约再看实现3.1 为什么顺序比方法更重要很多人审查 AI 代码时习惯从第一行开始往下读这是手写代码时代留下的惯性。但 AI 代码的结构往往是自顶向下生成的函数签名、参数、返回值这些契约层面的东西反而比实现细节更值得先看。原因很简单契约错了实现再对也是白搭。如果 AI 把一个函数的返回值类型理解错了或者参数顺序搞反了你逐行读实现根本发现不了因为实现本身是自洽的。但如果你先看契约一眼就能看出这个函数不该返回 null或者这个参数应该是可选的。我现在审查 AI 代码的固定顺序是接口契约 → 调用关系 → 核心分支 → 实现细节。这个顺序的本质是从粗到细先确认大框架没问题再往里钻。3.2 契约层要看什么契约层包括函数签名、类型定义、接口协议、数据结构。看这一层时我关注三个问题输入输出的类型和边界是否明确AI 经常写出参数是 any 类型或者返回值可能是 undefined这种模糊契约这在后续调用时就是隐患。命名是否准确反映意图AI 有时候会用processData这种万能命名掩盖了函数真正的职责这种命名会让你在后续维护时误用。错误处理的方式是否统一是抛异常还是返回错误码是返回 null 还是空对象AI 在不同函数里可能用不同风格这种不一致会在调用链上累积成 bug。我遇到过一个典型问题Claude Code 生成的一个数据转换函数签名是transform(input: RawData): ProcessedData看起来没问题。但我仔细看发现当input为空数组时它返回的是null而不是空数组。这个契约的不一致导致下游调用方在遍历返回值时直接报错。如果我当时从实现开始读很可能读到最后才发现这个边界问题但如果先看契约这个隐患在签名层面就能嗅到。3.3 调用关系怎么快速梳理AI 生成的代码往往是一个函数调用另一个函数形成一条链。审查时我建议先画出这条链确认每一环的输入输出能对上。具体做法是找到入口函数看它调用了谁被调用者的返回值怎么用的再往下追一层。通常追两到三层就能覆盖主要逻辑。这个过程中重点看数据在传递过程中有没有被意外修改以及异常有没有被吞掉。我见过 AI 生成的一段代码在中间层用try-catch包住了调用但 catch 块里只写了个console.log异常被静默吞掉了。这种问题在逐行读实现时很容易被忽略但在梳理调用关系时一眼就能看出这里异常没往外抛上层根本不知道出错了。3.4 核心分支的识别技巧核心分支指的是代码里那些决定走向的 if-else、switch、循环条件。AI 生成的分支逻辑最容易出问题的地方是边界值和默认分支。我的习惯是看到分支就先问三个问题边界值取不取得到默认分支else处理了吗多个条件之间有没有重叠或遗漏这三个问题能覆盖大部分分支 bug。举个实际例子AI 写的一段权限判断def check_permission(user, resource): if user.role admin: return True elif user.role editor and resource.owner user.id: return True return False这段代码看起来没问题但如果你问如果 user 是 None 会怎样就会发现它在第一行就抛异常了。AI 生成代码时经常默认输入是正常的对异常输入的处理要么缺失要么放在很后面。审查分支时把异常输入作为必查项能提前拦下很多问题。4. 测试兜底让机器替你审查那些不值得逐行看的代码4.1 测试是审查的延伸不是替代有一种观点认为有了 AI 生成代码再让 AI 生成测试就能形成闭环人就不用审查了。这个想法很美好但实际用下来会发现一个问题AI 生成的测试和 AI 生成的代码往往共享同一套错误假设。什么意思如果 AI 对某个需求的理解有偏差它生成的代码会带着这个偏差它生成的测试也会带着同样的偏差测试跑通了但需求其实是错的。所以测试能兜住实现层面的 bug但兜不住理解层面的偏差。理解层面的偏差还是得靠人来看。不过测试确实能帮你省掉大量不值得逐行看的代码的审查时间。对于那些低风险的、逻辑直白的代码与其逐行读不如写几个测试用例跑一遍跑通了就放过。4.2 测试用例应该覆盖哪些AI 容易错的点基于我的经验AI 生成代码时最容易出错的几类场景测试用例应该重点覆盖空输入和边界值空数组、空字符串、0、负数、极大值。AI 经常忘记处理这些。并发和时序如果代码涉及异步操作测试要覆盖操作还没完成就来了下一个请求的情况。错误路径不只是测正常流程能跑通更要测依赖服务挂了会怎样。数据一致性涉及多步写入的操作测试要验证中间步骤失败时前面的写入有没有回滚。我一般会让 AI 先生成测试然后我自己补充边界用例。补充的时候不看它的实现代码只看需求描述这样能避免被它的实现思路带偏。4.3 一个测试兜底的实操流程我现在的流程大概是这样AI 生成代码后先做风险分层第 2 节讲的方法。对低风险代码直接让 AI 生成测试我补充边界用例跑通就过。对中高风险代码先做契约和分支审查审查通过后再补测试。所有测试跑通后做一次集成验证确认各模块拼起来能正常工作。这个流程里测试不是最后一步而是和审查交织进行的。低风险代码靠测试省时间高风险代码靠审查保质量两者配合整体效率比纯逐行审查高很多。注意测试跑通不等于代码没问题。测试只能证明你测到的路径是对的证明不了你没测到的路径也是对的。所以高风险代码测试和审查都不能省。5. 那些 AI 特别容易写错、但逐行读也容易漏的地方5.1 异步代码的时序问题AI 生成异步代码时最常见的错误是忘记 await或者在循环里串行 await 导致性能问题。这类问题逐行读的时候很容易漏因为代码看起来逻辑是对的只是执行顺序不对。我遇到过一个例子AI 写了一段批量处理数据的代码在 for 循环里逐个 await 数据库写入。逻辑上没问题但一千条数据就是一千次串行往返性能极差。逐行读的时候你看到的是循环 await感觉很正常只有当你意识到这里可以并行时才会发现这是个问题。审查异步代码时我的建议是先看有没有 await 遗漏再看有没有可以并行的地方最后看错误处理。错误处理在异步场景下特别容易出问题因为 Promise 的 reject 如果没被 catch会变成 unhandled rejection而这种错误在测试里不一定能复现。5.2 状态共享和并发安全如果 AI 生成的代码涉及共享状态比如全局变量、单例、缓存并发安全就是必查项。AI 对并发的理解往往停留在加锁就行但实际场景里锁的粒度、锁的顺序、死锁风险都是它容易忽略的。我见过 AI 生成的一段缓存代码用了一个普通的 dict 做缓存没有考虑多线程读写。在单线程测试里跑得好好的一上生产环境就出现数据错乱。这类问题的特点是测试环境很难复现生产环境一出现就是大问题。所以涉及共享状态的代码不管风险等级如何我都会人工过一遍。5.3 错误处理的假完整AI 生成的错误处理经常是看起来完整实际没用。比如try: result do_something() except Exception as e: logger.error(f操作失败: {e}) return None这段代码捕获了异常记录了日志返回了 None。看起来处理得很完整但实际上调用方拿到 None 之后怎么办如果调用方没检查 None直接用了就会在更远的地方报一个莫名其妙的错排查起来非常困难。这种假完整的错误处理逐行读的时候很容易被放过因为它形式上是对的。审查时我建议重点看异常被捕获之后程序的控制流去了哪里以及调用方有没有能力处理这个失败。5.4 依赖版本的隐性假设AI 生成代码时会基于它训练数据里的库版本来写。但你的项目用的可能是另一个版本API 签名、行为、默认值都可能不一样。这类问题逐行读代码是发现不了的因为代码本身没错错的是代码和你的环境不匹配。我的做法是AI 生成涉及第三方库的代码后先确认库版本再查对应版本的文档确认 API 用法一致。这一步花不了几分钟但能避免很多代码看着对、跑起来报错的情况。6. 把审查变成提问和 AI 协作审查的实操方法6.1 让 AI 自己解释代码你来判断一个很实用的技巧是生成代码后不要自己闷头读而是让 AI 解释这段代码的关键决策。比如问它这段代码在输入为空时会怎么处理这个循环的退出条件是什么如果数据库连接失败控制流会走到哪里AI 解释的时候你其实是在做交叉验证它的解释和代码是否一致解释里有没有回避某些边界如果它的解释含糊其辞那大概率那段代码本身就有问题。这个方法的好处是把读代码变成了审逻辑。读代码是线性的、容易疲劳的审逻辑是跳跃的、更容易抓住重点。6.2 用反向提问暴露假设AI 生成代码时隐含了很多假设。这些假设它不会主动告诉你但你可以通过反向提问逼出来。比如如果这个函数的输入是负数会发生什么如果两个请求同时到达这段代码会怎样如果这个外部服务返回了预期之外的数据格式会怎样这些问题问出来AI 要么给你一个合理的答案说明它考虑到了要么开始打补丁说明它原本没考虑到。后者就是你需要重点审查的地方。6.3 让 AI 生成审查清单还有一个我常用的方法让 AI 针对它刚生成的代码生成一份审查清单列出这段代码里最值得人工确认的几个点。AI 对自己生成的代码往往能指出一些它不太确定的地方这些地方就是审查的重点。当然AI 的清单不一定完整你需要在此基础上补充自己的判断。但作为一个起点它能帮你快速定位到高风险区域比你自己从头扫一遍效率高。6.4 多 AI 协作审查的尝试我最近在试的一个方法是用 A 工具生成代码用 B 工具审查。不同工具的思维模式不一样A 可能忽略的问题B 可能一眼看出来。这种交叉审查能发现一些单一工具发现不了的问题。不过这个方法有个前提你得对两个工具的能力边界有了解知道哪个更擅长逻辑审查哪个更擅长安全审查。盲目交叉反而会增加噪音。7. 审查的止损点什么时候可以停止审查7.1 审查不是越久越好审查有一个边际收益递减的规律前 20% 的时间能发现 80% 的问题后面的时间发现的问题越来越少但你的注意力越来越差反而可能引入误判——把没问题的代码当成有问题改来改去反而改出 bug。所以审查需要一个止损点达到某个标准后就停止审查交给测试和线上监控。这个标准因人而异我的标准是高风险代码逐行看完 中风险代码分支看完 低风险代码测试跑通达到这个程度就停。7.2 什么情况下必须过度审查但有些情况下止损点要往后推甚至要过度审查代码涉及不可逆操作比如删除数据、发送真实通知、扣款。这些操作一旦出错后果无法挽回必须反复确认。代码要上线到关键路径比如支付流程、登录流程。这些路径出问题影响面大。你对这段代码的领域不熟不熟就意味着你判断不了风险这时候宁可多花时间。7.3 把审查结果沉淀成检查项每次审查发现的问题我都会记下来慢慢形成一份自己的AI 代码检查项。比如检查异步代码有没有漏 await检查异常捕获后控制流去了哪检查共享状态有没有并发保护。下次审查时拿着这份清单过一遍比凭感觉审查更可靠。这份清单不需要很正式记在笔记里就行。关键是持续积累用得越久清单越贴合你的项目特点审查效率越高。8. 我踩过的几个坑和对应的经验8.1 坑一被代码很漂亮骗了刚开始用 Claude Code 的时候我经常被它生成的代码颜值迷惑。命名规范、注释齐全、缩进整齐看起来就很专业于是审查的时候不自觉地放松了警惕。结果有一次一个看起来完美的函数在处理空输入时直接抛了异常上线后才发现。经验代码的颜值和质量没有必然关系。AI 生成的代码格式永远是漂亮的但逻辑不一定对。审查时要刻意忽略格式专注逻辑。8.2 坑二以为测试跑通就万事大吉有一次我让 AI 生成代码和测试测试全绿我就直接上线了。结果生产环境出现了一个测试没覆盖到的边界问题。回头一看AI 生成的测试只覆盖了正常路径边界路径一个都没测。经验AI 生成的测试默认只测happy path。边界用例必须自己补而且补的时候不要看实现代码只看需求避免被实现思路带偏。8.3 坑三审查时改着改着改出新 bug有一次审查 AI 代码我觉得某个地方写得不好就顺手改了。改完之后没重新跑测试直接提交了。结果那个不好的地方其实是 AI 有意为之我改完之后破坏了原有的逻辑。经验审查时如果决定修改改完必须重新跑测试而且要想清楚AI 为什么这么写。如果理解不了它的意图宁可先不改标记出来后续确认。8.4 坑四忽略了环境差异AI 生成的代码在它的认知里是正确的但你的项目环境可能不一样。我遇到过一次AI 用了一个库的新 API但我的项目锁的是旧版本跑起来直接报错。经验涉及第三方库的代码生成后先确认版本兼容性。这一步很快但能省掉很多排查时间。9. 一个可以直接抄的审查流程把上面这些经验整理一下我现在的审查流程大概是这样分层拿到 AI 代码先按风险等级分类高风险的逐行看低风险的靠测试。看契约先看函数签名、类型、接口确认输入输出明确。理调用梳理调用链确认数据传递和异常处理没问题。查分支重点看边界值、默认分支、异常输入。补测试让 AI 生成测试自己补边界用例跑通。反向提问让 AI 解释关键决策用反向问题暴露隐含假设。止损达到标准就停不追求看完每一行。沉淀把发现的问题记入检查清单下次复用。这个流程不是死的你可以根据自己的项目特点调整。核心思想就一条审查的目标不是读完所有代码而是覆盖所有风险。AI 把代码生产速度提上去了审查也要相应地提效而不是简单地加速逐行读。最后分享一个我自己的体会用 AI 编程久了你会发现审查能力比编码能力更重要。因为编码这件事AI 已经能帮你做掉大半但判断这段代码能不能信还是得靠人。这个判断力来自你对业务的理解、对风险的敏感、对边界情况的经验。这些恰恰是 AI 暂时替代不了的也是你作为从业者真正值钱的地方。