AI编程时代,代码审查该怎么做?从逐行到分层
发布时间:2026/10/15 12:38:17 锦皓数字建站

1. 当AI开始替你写代码审查这件事到底该怎么摆位置“AI 编程都替你写代码了人还要把时间花在逐行审查上吗”这个问题我第一次认真琢磨是在用 Claude Code 连续写了三天业务代码之后。那几天我几乎没怎么手敲逻辑大部分函数、单测、甚至一些边界处理都是它生成的我做的事情变成了描述需求、看它改文件、跑测试、然后决定要不要接受。到第三天晚上我盯着屏幕突然意识到一件事我并没有比以前轻松多少因为我把省下来的打字时间几乎全部投进了“看它写得对不对”这件事上。这个感受不是个例。身边用 Codex、Claude Code、各种 agent 框架的同行聊到最后都会绕回同一个矛盾点生成速度上去了但审查压力也跟着上来了。标题里这个问题之所以扎心是因为它戳中了一个真实的取舍——如果 AI 已经能写出能跑的代码人到底还要不要逐行去读我的结论可能和很多人的直觉不太一样逐行审查这件事本身没有错错的是“无差别地逐行审查”。真正需要重新设计的不是要不要审而是审什么、审到什么粒度、哪些环节可以交给机器、哪些环节必须人来看。先把话说清楚这篇不是要鼓吹“AI 写的代码不用看”也不是要贩卖“以后程序员只负责点确认”的焦虑。我想做的是把这件事拆开AI 编程工具现在到底能替我们做到哪一步代码审查里哪些部分是真正产生价值的哪些只是习惯性的仪式感以及在实际项目里怎么用一套可操作的流程把审查成本压下来同时不把风险放大。适合正在用 Claude Code、Codex 这类工具写代码的人也适合团队里负责代码质量、正在纠结要不要把 AI 生成代码纳入正式流程的人。我自己的背景是后端和工具链方向日常和 Python、Go、TypeScript 打交道也带过小团队做代码评审。下面这些经验一部分来自我自己踩的坑一部分来自和同行交流时反复出现的共性问题。我会尽量把“为什么这么做”讲透而不是只给一堆结论。2. AI 编程工具到底替我们做了什么又留下了什么2.1 从补全到 agent能力边界已经变了很多人对 AI 编程的印象还停留在“自动补全下一行”。这个认知已经落后了。早期的代码补全本质是概率预测它猜你接下来想写什么给你一个片段你按 Tab 接受。这个阶段 AI 不参与决策它只是个更聪明的输入法。但 Claude Code、Codex 这类工具是另一个物种。它们属于 agent 形态能读整个项目、能自己决定改哪个文件、能跑命令、能看报错、能根据报错再改一轮。你给它的不是“下一行写什么”而是“把这个功能实现一下”。它会自己拆步骤、自己找相关文件、自己写测试、自己验证。这个差别非常关键补全工具留下的是片段agent 留下的是一整套决策链。我举个具体的例子。我让 Claude Code 给一个已有的订单服务加一个“超时未支付自动取消”的逻辑。它做的事情包括找到订单状态机定义、找到定时任务入口、新增一个状态流转、补了一个幂等判断、加了两条单测、还顺手改了配置文件里的超时时间常量。整个过程它改了 6 个文件。这里面每一个改动单独看都合理但合在一起就产生了一个我需要判断的问题它选的这个定时任务入口和我原本设想的那个是不是同一个它加的幂等判断覆盖的场景够不够这就是 agent 和补全的本质区别。补全不会替你做架构决策agent 会。而架构决策恰恰是最需要人来看的部分。所以“AI 都替你写代码了”这句话准确的说法应该是AI 替你写了实现但决策它只是给了一个默认答案这个答案对不对还是你的事。2.2 生成速度提升之后瓶颈转移到了哪里有个很直观的算术。假设以前写一个模块编码 4 小时自测加审查 1 小时总共 5 小时。现在 AI 生成编码压缩到 1 小时但审查因为代码量没变、甚至因为你不熟悉它的写法而变多假设审查变成 1.5 小时总共 2.5 小时。整体是快了但你会发现审查在总时间里的占比从 20% 涨到了 60%。这个占比变化才是问题的核心。以前审查是收尾动作现在审查变成了主要工作。如果你的审查方式还是老一套——从头到尾一行一行读——那你的时间结构就崩了。你会觉得“AI 是快了但我更累了”因为你的审查方法没有跟着工作方式一起升级。我实测过一个对比。同一个需求我用两种方式处理 AI 生成的代码。第一种是逐行读读完再跑测试一个 300 行的改动我花了大概 40 分钟。第二种是先跑测试、再看 diff 的“骨架”、只精读关键路径同样的改动我花了 15 分钟而且事后回顾两种方式漏掉的问题数量差不多。差别在于逐行读的时候我的注意力被大量格式、命名、无关紧要的细节消耗掉了真正该盯的地方反而没盯住。2.3 逐行审查的三种价值只有一种不可替代我把逐行审查能带来的价值拆成三类这样更容易判断哪些可以省。第一类是发现语法和低级错误。比如变量名拼错、少个括号、类型不匹配。这类价值现在基本可以交给机器编译器、linter、类型检查、测试任何一个都比人眼靠谱。你花时间逐行找这类问题是纯浪费。第二类是发现逻辑和边界问题。比如循环少跑一次、空值没处理、并发下有竞态。这类问题机器能发现一部分测试覆盖到的但覆盖不到的部分还得靠人。这是逐行审查真正有价值的地方但注意它不需要你逐行读它需要你针对性地看关键路径。第三类是判断设计和意图是否匹配。比如 AI 选了一个方案能跑但和项目整体架构不一致或者埋了一个未来会爆的坑。这类问题只有人能判断而且它往往不在某一行里而在多个文件的改动之间的关系里。逐行读反而容易漏掉这种“跨行”的问题。所以结论很清楚逐行审查的不可替代价值集中在第二类和第三类而这两类都不需要你真的“逐行”。你需要的是有重点地审。把第一类交给机器把精力集中在后两类这才是 AI 编程时代审查该有的样子。3. 重新设计审查流程从逐行到分层3.1 先跑起来再决定看哪里我现在处理 AI 生成代码的第一步永远是先让它跑起来。不是先读代码是先跑测试、跑构建、跑一遍核心流程。这个顺序的调整看起来很小但效果很大。原因很简单如果代码根本跑不起来你读它就是在读一堆废纸。先跑能过滤掉大量低级问题也能让你对“这段代码大概在干什么”有个整体感觉。跑通了你再去读读的时候脑子里有运行时行为做参照理解成本会低很多。具体操作上我会让 agent 自己先把测试跑一遍。Claude Code 这类工具本身就能执行命令你直接让它“跑一下相关测试把失败的贴出来”。它会自己跑、自己看报错、自己修修到通过为止。这个过程你不需要介入等它说“测试通过了”你再开始看。这一步能省掉你大量“帮它找语法错误”的时间。提示让 agent 自己跑测试的时候一定要确认它跑的是真实的测试而不是它自己临时写的、只验证自己逻辑的假测试。我踩过这个坑它写了个测试断言的是它自己实现的输出等于自己给自己判卷。后来我的做法是明确要求它“跑项目里已有的测试套件”而不是“写个测试验证一下”。3.2 看 diff 的骨架而不是看每一行跑通之后第二步是看 diff。但看 diff 也有讲究。我的习惯是先看改了哪些文件、每个文件改了多少行形成一个“改动地图”。这个地图能告诉我这次改动的形状是集中在一个文件里的小改还是散落在多个文件里的大改。如果是散落在多个文件里的大改我会特别警惕。因为跨文件的改动最容易出现“每个文件单独看都对合起来不对”的问题。这时候我会重点看文件之间的调用关系而不是每个文件内部的实现细节。看 diff 的时候我有个小技巧先看删除的行再看新增的行。删除的行往往揭示了这次改动动了什么原有的逻辑而新增的行只是结果。很多人看 diff 习惯从新增看起容易被新代码带着走忽略了它删掉了什么。删掉的东西有时候比新增的更重要。3.3 关键路径精读其余略读第三步才是真正读代码但只读关键路径。什么是关键路径我一般按这几个标准挑涉及状态变更的代码比如订单状态、用户权限、资金流水涉及并发和异步的代码比如锁、队列、回调涉及外部输入的代码比如接口参数、文件读取、第三方返回涉及错误处理的代码比如异常捕获、重试、降级这四类地方我会逐行读甚至读两遍。其余的部分比如纯数据转换、格式化、日志打印我基本是扫一眼确认没有明显问题就过。这个策略背后的逻辑是风险不是均匀分布的。一段代码里真正可能出大问题的地方就那么几处把精力压在这几处收益远高于平均用力。我做过统计我事后发现的、真正严重的问题90% 以上都落在这四类关键路径里。剩下的 10% 里大部分是测试能覆盖到的。3.4 用测试当审查的放大器测试在这里的角色不只是验证功能它还是审查的放大器。一段代码如果测试覆盖得好你审查的时候就可以少读很多——因为测试已经帮你验证了那些路径。反过来如果一段 AI 生成的代码没有测试或者测试很弱那你就得自己多读。所以我现在会让 agent 在生成代码的同时生成测试但我不会盲信它的测试。我会看测试覆盖了哪些分支特别是那些我关心的边界。如果它只测了正常路径我会要求它补边界测试。补测试的过程其实也是逼它把边界想清楚的过程很多时候补着补着就发现原来的实现有问题。注意AI 写的测试有个通病喜欢测“实现细节”而不是“行为”。比如它测一个函数断言的是内部某个变量被设成了什么值而不是函数的输出对不对。这种测试很脆实现一改就挂而且它验证不了真正的行为。看到这种测试我会让它重写成基于输入输出的行为测试。4. 哪些环节可以放心交给机器哪些必须人来看4.1 可以交给机器的部分先说能放手的。以下几类我现在基本不花人的时间格式和风格。缩进、命名规范、import 顺序这些交给 linter 和 formatter。AI 生成的代码风格通常还行但偶尔会飘配好 pre-commit 钩子自动修人不用管。类型和语法错误。交给编译器和类型检查。TypeScript 的 tsc、Python 的 mypy、Go 的编译器这些工具比人眼快也比人眼准。跑一遍就知道有没有问题。明显的逻辑错误。交给测试。循环边界、空值、类型转换只要测试覆盖到机器就能发现。这也是为什么我一直强调测试要写够。重复代码和坏味道。交给静态分析工具。SonarQube、CodeQL 这类工具能扫出重复、复杂度高、潜在 bug 的地方。AI 生成的代码有时候会有重复工具一扫就出来。这几类加起来大概能覆盖审查工作量的 50% 到 60%。把它们交出去人的时间就腾出来了。4.2 必须人来看的部分剩下的部分机器替代不了必须人来看架构一致性。AI 不知道你项目的整体设计意图它只会按局部最优来写。它可能在一个本该用事件驱动的地方写了同步调用在一个本该分层的模块里直接跨层访问。这类问题只有了解项目全局的人能判断。业务语义正确性。代码能跑不代表业务逻辑对。比如“超时未支付取消订单”AI 可能理解成“创建后 30 分钟取消”而你的业务其实是“最后一次支付尝试后 30 分钟”。这种语义偏差测试测不出来只有懂业务的人能发现。安全和权限。AI 生成的代码在安全上经常有盲区比如没做权限校验、把敏感信息打进日志、SQL 拼接没参数化。这类问题必须人来看而且要看得很仔细。性能和资源。AI 可能写出一个功能正确但性能很差的实现比如在循环里查数据库、一次性加载全表。这类问题在小数据量下测不出来上线才爆。未来可维护性。这段代码三个月后还好改吗AI 不在乎这个它只在乎现在能跑。人得替未来的自己考虑。4.3 一张对照表帮你快速判断审查内容交给机器必须人看判断依据格式、命名、import是否linter/formatter 可自动修类型、语法是否编译器/类型检查覆盖循环边界、空值部分部分测试覆盖到的交给机器架构一致性否是需要项目全局知识业务语义否是需要业务理解安全权限否是机器容易漏风险高性能资源部分是压测能发现一部分可维护性否是需要长期视角这张表不是绝对的但能帮你快速判断一个审查点该不该花人的时间。我的经验是凡是“需要理解意图”的都得人来看凡是“有明确规则”的都能交给机器。5. 实操一套可复制的 AI 代码审查流程5.1 准备阶段把规则前置审查成本高很多时候是因为规则没前置。如果项目里没有统一的 linter 配置、没有测试框架、没有 CI那审查的时候你就得人肉补这些成本自然高。所以第一步是把基础设施搭好。我的做法是在项目里配好这几样格式化工具Prettier、Black、gofmt配 pre-commit 钩子提交前自动跑静态检查ESLint、Ruff、golangci-lint配到 CI 里不通过不让合测试框架pytest、jest、go test要求新代码有对应测试类型检查tsc、mypy配到 CI这些配好之后AI 生成的代码在提交前就会被机器过一遍大量低级问题根本到不了人眼前。这一步是一次性投入长期省时间。5.2 生成阶段给 agent 明确的约束AI 生成代码的质量很大程度上取决于你给它的约束。我现在给 agent 的提示词里会固定带上这几条1. 改动前先读相关文件的现有实现保持风格一致 2. 新增逻辑必须配测试测试要覆盖正常路径和至少两个边界 3. 涉及数据库查询的必须参数化不允许字符串拼接 4. 涉及外部输入的必须做校验 5. 改动完成后跑一遍项目已有的测试套件把结果贴出来这几条约束看起来简单但能挡掉很多常见问题。特别是第 5 条逼它自己验证能省掉你大量“帮它找错”的时间。提示约束不要写太多太细写多了 agent 反而容易顾此失彼。我一般控制在 5 到 7 条都是最关键的。剩下的靠 CI 和审查兜底。5.3 审查阶段按优先级过一遍到了审查环节我按这个顺序过第一步看测试结果。测试全绿才继续有红的先让它修。第二步看改动地图。改了哪些文件、多少行形成整体印象。跨文件改动多的话重点看调用关系。第三步看删除的行。搞清楚这次改动动了什么原有逻辑。第四步精读关键路径。按前面说的四类状态、并发、外部输入、错误处理逐行读。第五步扫其余部分。快速过一遍确认没有明显问题。第六步问三个问题。这段代码的业务语义对吗安全上有漏洞吗三个月后还好改吗这六步走下来一个中等规模的改动大概 15 到 20 分钟。比逐行读快而且覆盖更全。5.4 一个真实案例的完整走查说个具体的。前段时间我用 Claude Code 给一个内部工具加“批量导出”功能。它改了 4 个文件新增了一个导出服务、改了路由、加了一个配置项、补了测试。我先跑测试全绿。看改动地图4 个文件导出服务是主体200 多行。看删除的行路由里删了一个旧的单条导出接口改成批量。这一步让我注意到旧接口可能有调用方得确认一下。果然前端还有地方在调旧接口这是个它没考虑到的问题。然后精读关键路径。导出服务里涉及文件写入和外部输入导出参数我重点看了这两块。发现它写文件的时候没处理磁盘满的情况也没限制导出条数理论上可以一次导出全表。这两个都是隐患我让它补了限制和错误处理。最后扫其余部分配置项和测试没问题。整个过程 20 分钟左右发现了 3 个它没考虑到的问题。如果我逐行读可能也会发现但花的时间会更长而且不一定能发现“旧接口有调用方”这种跨文件的问题——因为那个问题不在它改的代码里而在它没改的地方。这个案例说明一件事审查的重点很多时候不在新增的代码里而在新增代码和现有系统的交界处。AI 只对它改的地方负责交界处是它最容易忽略的也是人最该盯的。6. 常见问题与排查技巧实录6.1 AI 生成的代码“看起来对但实际错”怎么快速识别这是最常见也最头疼的问题。代码读起来通顺逻辑自洽但跑起来结果不对。我的经验是这类问题往往出在假设上。AI 在生成代码时会对一些它不知道的东西做假设比如假设某个字段一定存在、假设某个调用一定成功、假设数据量不大。识别方法找代码里的假设点。具体看这几处有没有直接访问可能为空的字段没做判空有没有假设外部调用一定成功没做错误处理有没有假设数据量小用了全量加载有没有假设并发不高没加锁这些假设点就是最可能出错的地方。我一般会针对每个假设点问一句“如果这个假设不成立会怎样”往往一问就发现问题。6.2 审查时容易漏掉的几类问题我整理了一个速查表是我自己踩过坑之后总结的问题类型典型表现排查方法边界遗漏循环少一次、空数组没处理看循环条件和判空并发竞态共享状态没加锁找共享变量和异步点资源泄漏文件/连接没关看 try/finally 或 with权限缺失接口没校验身份看入口有没有鉴权日志泄露敏感信息进日志搜日志里的参数性能陷阱循环里查库看循环体内的 IO这张表我基本是审查时对着过一遍特别是涉及关键路径的时候。它帮我挡掉过好几次线上事故。6.3 团队协作里怎么定审查标准如果是团队审查标准不统一是个大问题。有人逐行读有人只看测试最后质量参差不齐。我的建议是团队一起定一个审查清单明确哪些必须看、哪些可以交给机器。清单不用长一页纸就够。核心是让所有人对“审到什么程度”有共识。比如约定涉及资金和权限的改动必须两人审纯 UI 改动一人审加测试通过即可。有了这个共识AI 生成的代码该走什么流程就清楚了不会因为“这是 AI 写的”就特殊对待也不会因为“AI 写的应该没问题”就放松。注意团队里最容易出的问题是有人觉得“AI 写的肯定有问题得逐行看”有人觉得“AI 写的能跑就行”。这两种极端都会出问题。前者浪费时间后者埋雷。定清单就是为了把这两种极端拉回中间。6.4 我踩过的三个坑第一个坑盲信测试通过。有次 AI 生成的代码测试全绿我直接合了结果上线发现一个边界没覆盖。后来我才知道它写的测试只覆盖了它自己想到的路径没想到的路径它也没测。教训是测试通过只是及格线不是满分。第二个坑忽略它改的配置文件。AI 有时候会顺手改配置比如超时时间、重试次数。这些改动藏在 diff 里容易漏看。我有次就没注意它把重试次数从 3 改成了 10结果压测的时候把下游打挂了。教训是配置文件一定要单独看一遍。第三个坑在它不熟悉的领域放权太多。AI 对主流框架很熟但对一些冷门库或者内部框架它容易瞎猜。我有次让它改一个内部 DSL 的代码它按自己的理解写了一通看着像那么回事其实语法都不对。教训是越是它不熟的领域越要盯紧。7. 回到那个问题人还要不要逐行审查绕了一圈回到标题那个问题。我的答案是逐行审查这个动作本身要保留但“逐行”的范围要大幅缩小。不是每一行都值得你花同样的注意力把精力集中在关键路径和交界处其余交给机器这才是 AI 编程时代该有的审查方式。我现在的实际做法是AI 生成的代码我大概只精读 20% 到 30% 的行其余靠测试、静态检查和快速扫读兜底。这个比例不是拍脑袋定的是踩坑踩出来的——我发现我事后真正后悔没看的地方基本都落在那 20% 到 30% 里。剩下的 70% 到 80%看了也就是图个心安实际价值有限。当然这个比例因人因项目而异。涉及资金、安全、核心链路的项目精读比例要高内部工具、实验性代码可以低一些。关键是你要有意识地去分配注意力而不是习惯性地从头读到尾。最后分享一个我最近在用的技巧让 AI 自己先审一遍自己的代码。我会在它生成完之后让它“以审查者的角度找出这段代码可能的问题特别是边界、并发、安全方面”。它经常能自己发现一些问题改完之后我再审成本就低多了。这个技巧不能替代人的审查但能帮你过滤掉一批它自己就能发现的问题把人的时间留给更难的判断。这个方向后续还能怎么扩展我还在试。比如把审查清单做成 agent 能读的规则文件让它生成代码的时候就对照着自检或者把常见的坑做成测试模板让它生成测试的时候自动带上。这些还在摸索有进展再聊。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。