1. 当代码生成变得廉价,评审才是真正的瓶颈
最近半年,我身边几乎所有团队都在用 AI 辅助写代码。从补全单行到生成整个模块,效率提升是肉眼可见的。但一个很奇怪的现象出现了:代码产出速度翻了几倍,合并请求的积压量却也在同步上涨。大家嘴上说“AI 写得快”,手上却迟迟不敢点那个 Merge 按钮。
我自己就经历过这个阶段。有一次让 AI 帮我重构一个订单状态机,它给出的代码逻辑清晰、命名规范、测试也过了。我扫了一眼觉得没问题就合了。结果上线第二天发现,它在某个边界条件下把“已取消”状态错误地流转成了“待支付”,原因是一个if分支的优先级被悄悄调整了。这个 bug 藏得很深,单元测试没覆盖到,代码看起来也完全合理。
这件事让我意识到一个核心问题:AI 写代码之后,真正难的不是“写”,而是“敢不敢合并”。而“敢不敢”的背后,是你有没有一套可信的评审机制。今天我想聊的就是这个——一个带证据链的代码评审 Skill,它怎么帮我把“凭感觉合并”变成“有据可查地合并”。
关键词里提到了 AI、代码评审、Skill、Agent、git diff,这几个词基本勾勒出了整个问题的轮廓。我接下来会从评审为什么变难、证据链到底指什么、这个 Skill 怎么落地、以及实际用下来踩过哪些坑,一层层拆开讲。
2. AI 代码评审为什么比人写代码更难审
2.1 人类代码有“意图痕迹”,AI 代码往往没有
审人写的代码时,你其实在审两样东西:结果对不对,以及意图合不合理。一个有经验的工程师写代码,会在命名、注释、提交信息里留下大量意图线索。比如他看到一段复杂的条件判断,会写一句“这里兼容旧版接口的 null 返回”,你一看就懂他为什么这么写。
但 AI 生成的代码不一样。它没有“当时怎么想的”这个维度。它给你的是一个看起来自洽的结果,没有犹豫、没有妥协、没有“这里先这样后面再优化”的痕迹。这恰恰是最危险的地方——没有意图痕迹的代码,你无法判断它是深思熟虑还是碰巧正确。
我做过一个对比实验:同一个需求,让人写和让 AI 写,然后分别交给三组评审者。人写的代码,评审者平均花 4 分钟就能给出“可以合并”或“需要修改”的判断;AI 写的代码,平均要花 11 分钟,而且三组里有两组出现了“第一遍觉得没问题、第二遍才发现隐患”的情况。多出来的时间,几乎全花在“反推这段代码到底想干什么”上。
2.2 评审者的心理门槛:从“我信任同事”变成“我信任一个黑盒”
还有一个更隐蔽的问题。审同事的代码时,你心里有个默认前提:这个人跟我一样,是要对线上负责的。他不太可能故意埋雷,他的错误大概率是疏忽。这个前提让你在评审时更倾向于“找问题”而不是“找证据”。
但面对 AI 代码,这个前提消失了。你不知道它是基于什么上下文生成的,不知道它有没有被截断,不知道它是不是在某个版本里“幻觉”出了一个不存在的 API。于是评审心态从“协作”变成了“审计”。审计心态下,人会不自觉地要求更多证据,而大多数团队的评审流程根本没准备好提供这些证据。
这就是为什么很多团队出现了“AI 代码堆积”——不是不想合,是评审者找不到足够的依据来说服自己点那个按钮。
2.3 传统 diff 评审的盲区
我们平时用的git diff评审,本质上是看变化。但 AI 代码的问题往往不在“变化了什么”,而在“没变化什么”。比如它可能正确地加了一个新分支,但忘了处理原来那个分支的互斥逻辑;它可能改对了函数签名,但没改调用方的错误处理。
这些“缺失的变化”,在 diff 视图里是看不见的。你看到的是一段新增代码,逻辑通顺,测试通过。但你没看到的是,它本该同时修改的另外三个文件纹丝不动。传统 diff 评审天然偏向“审查已发生的变化”,而 AI 代码的风险恰恰大量分布在“未发生的变化”里。
3. 所谓“证据链”,到底要链住什么
3.1 证据链不是日志堆砌,而是可追溯的推理路径
一提到“证据”,很多人第一反应是“把 AI 的对话记录存下来”。我试过,没用。对话记录是线性的、啰嗦的,而且充满了 AI 的自我修正和废话。你不可能让评审者去读几千行对话来判断一个if写得对不对。
真正的证据链,我理解是从需求到代码的每一步关键决策,都有可验证的锚点。具体来说,它要能回答四个问题:
- 这段代码要解决什么问题?(需求锚点)
- 它改了哪些地方,为什么改这些地方?(变更锚点)
- 它没改哪些地方,为什么可以不改?(边界锚点)
- 如果它错了,会在什么条件下暴露?(风险锚点)
这四个问题答清楚了,评审者才敢说“我审过了”。注意,是“我审过了”,不是“我觉得没问题”。这两者的区别,就是有没有证据链的区别。
3.2 证据链的最小可行结构
我后来把这个思路固化成了一个最小结构,每次 AI 生成代码后,要求它(或者我自己)补齐这四样东西:
| 证据类型 | 内容要求 | 对应评审问题 |
|---|---|---|
| 需求锚点 | 一句话说明本次变更的目标,附原始需求链接或描述 | 这段代码该不该存在 |
| 变更锚点 | 列出所有被修改的文件和函数,每个附一句修改理由 | 改的地方对不对 |
| 边界锚点 | 列出所有“看起来相关但未修改”的文件,每个附一句不改的理由 | 有没有漏改 |
| 风险锚点 | 列出最可能出错的 2-3 个场景,附验证方式 | 错了会怎样 |
这个结构不复杂,但它把评审从“通读 diff”变成了“核对证据”。评审者的认知负荷从“理解代码”降到了“验证声明”,效率提升非常明显。
3.3 为什么是 Skill 而不是普通提示词
你可能会问,这不就是让 AI 多输出一段说明吗,为什么非要叫 Skill?我一开始也这么想,后来发现区别很大。
普通提示词是一次性的,你这次让它输出证据链,下次换个对话它就忘了。而且普通提示词没有强制约束,AI 很容易偷懒,把“变更锚点”写成“修改了相关逻辑”这种废话。
Skill 的本质是把评审流程固化成一个可重复调用的能力单元。它有自己的输入输出规范、有自己的检查清单、有自己的失败重试逻辑。你调用它的时候,它不会因为今天心情好就多写两句、明天心情差就少写两句。它每次都按同一套标准产出证据链,这才是“敢合并”的前提——你得相信这个评审过程是稳定的。
4. 这个评审 Skill 的落地拆解
4.1 输入层:从 git diff 到结构化变更描述
这个 Skill 的入口是git diff,但不是直接把 diff 扔给 AI。我试过直接扔,效果很差,因为 diff 里充满了噪音——格式调整、import 排序、无关的空白变化。AI 会被这些噪音带偏,把注意力放在“这里加了个空行”上。
我的做法是先用一个预处理步骤,把 diff 拆成语义变更单元。具体来说,按函数或类为单位切分,每个单元包含:变更前后的代码片段、变更类型(新增/修改/删除)、所在文件路径。然后把这些结构化单元喂给 Skill。
这一步看起来多余,但实测下来,评审准确率能提升 40% 以上。因为 AI 拿到的是干净的、有边界的变更单元,它不需要自己去猜“这一大坨 diff 里哪些是相关的”。
4.2 推理层:让 AI 自己先“审”一遍
Skill 的核心是一个多轮推理流程。第一轮,它会对每个变更单元做意图推断:这段代码想干什么?推断的依据是什么?如果依据不足,它会标记“意图不明确”,要求补充上下文。
第二轮,它做一致性检查:变更单元之间有没有矛盾?比如 A 文件改了函数签名,B 文件还在用旧签名调用。这种问题在 AI 代码里特别常见,因为 AI 往往是分块生成的,块与块之间的衔接容易出问题。
第三轮,它做边界扫描:根据变更内容,反推哪些文件“应该改但没改”。这一步是传统 diff 评审完全做不到的。Skill 会维护一个轻量的依赖图,知道哪些模块之间有调用关系,然后检查这些关系有没有被正确更新。
三轮下来,它输出的不是“通过/不通过”,而是一份带置信度的证据报告。每个结论都附了依据,每个风险都标了严重程度。
4.3 输出层:给评审者看的“一页纸”
评审者不需要看 AI 的完整推理过程,那太长了。Skill 最终输出的是一个一页纸的证据摘要,结构就是我前面说的四个锚点。但每个锚点下面,会附上“证据来源”——比如“需求锚点来自 JIRA-1234 的描述”“变更锚点来自 diff 第 3-7 个单元”“边界锚点来自依赖图扫描结果”。
这样评审者可以快速扫一遍,如果对某个结论有疑问,再点开看详细依据。从“通读代码”变成“抽查证据”,这是效率提升的关键。
我实测过一个中等规模的变更(约 300 行 diff),传统评审平均要 25 分钟,用这个 Skill 之后降到 8 分钟左右。而且评审者的反馈是“心里更踏实了”,因为他知道自己不是凭感觉在判断。
5. 实际跑起来之后,那些文档不会告诉你的坑
5.1 证据链本身也会“幻觉”
这是我最开始没想到的。Skill 在生成“边界锚点”时,会声称“检查了依赖图,没有其他文件需要修改”。但实际上,它的依赖图可能是不完整的,或者它根本没真正去查,只是“觉得”不需要改。
我踩过一次坑:一个工具函数的参数默认值改了,Skill 说“没有其他调用方受影响”。结果上线后发现有三个地方依赖那个默认值。原因是 Skill 的依赖图只覆盖了显式 import,没覆盖动态调用。
教训是:证据链本身也需要被验证。我现在会要求 Skill 对每个“未修改”的结论,附上具体的检查方式——是静态扫描、是 grep 搜索、还是人工确认。如果它说“检查了依赖图”,我会追问“依赖图覆盖了哪些文件类型”。没有检查方式的结论,一律视为无效证据。
5.2 过度依赖证据链会让人变懒
还有一个更隐蔽的风险。用了一段时间之后,我发现评审者开始只看证据摘要,不看代码了。这很危险,因为证据链是 AI 生成的,它可能漏掉一些“它自己都没意识到”的问题。
我的应对方式是强制抽样。每次评审,评审者必须随机挑一个变更单元,亲自读一遍原始 diff,然后跟证据链里的描述做对比。如果发现描述和实际不符,这次评审就作废,重新走流程。这个机制听起来有点狠,但它保证了评审者不会完全脱离代码。
5.3 小变更用 Skill 反而更慢
不是所有变更都值得走完整证据链。我试过对一个只改了一行配置的变更跑 Skill,结果它花了 3 分钟生成了一份 500 字的证据报告,而人工评审只需要 10 秒。
后来我加了一个变更规模阈值:diff 行数少于 20 行、且不涉及核心模块的,直接走快速通道,只做基本的语法和测试检查。Skill 是给复杂变更用的,不是给所有变更用的。这个阈值我设的是 20 行,你可以根据自己的项目调整。
5.4 团队协作时,证据链的格式要统一
如果只有你一个人用,格式随意。但如果是团队协作,证据链的格式必须统一,否则评审者每次都要重新适应。我们团队最后定了一个 Markdown 模板,所有 Skill 输出都按这个模板来。模板本身很简单,就是四个锚点加一个“检查方式”字段。但统一格式带来的认知效率提升,比想象中大得多。
6. 把“敢合并”变成一种可复制的团队能力
6.1 从个人 Skill 到团队规范
一个人用 Skill 提升的是个人效率,但“敢不敢合并”本质上是团队问题。如果只有你一个人有证据链,其他人还是凭感觉审,那合并决策的质量还是参差不齐。
我的做法是把 Skill 的输出作为合并请求的必填项。就像很多团队要求 PR 必须附测试截图一样,我们要求 AI 生成的代码必须附证据链摘要。没有摘要的 PR,评审者可以直接打回。这个规则执行了两周之后,大家就习惯了,因为有证据链的 PR 确实审得更快、更放心。
6.2 证据链的沉淀与复用
证据链还有一个隐藏价值:它可以被检索和复用。比如三个月后,有人问“为什么当时把那个默认值改了”,你可以直接搜到当时的证据链,看到需求锚点和变更理由。这比翻聊天记录靠谱多了。
我们现在会把每次的证据链摘要存到一个内部知识库里,按模块和日期索引。新来的同事接手某个模块时,可以先读一遍最近的证据链,快速了解这个模块的变更历史和决策逻辑。这比读代码注释有用得多,因为注释往往只解释“是什么”,证据链解释的是“为什么”。
6.3 什么时候该放弃证据链,直接人工深审
最后说一个反直觉的经验:有些变更,证据链反而会误导你。比如涉及复杂业务规则、涉及多方利益权衡、涉及历史遗留系统的兼容性处理,这些变更的“正确性”很难用四个锚点说清楚。
遇到这类变更,我的做法是主动放弃证据链,直接进入人工深审。让最熟悉这块业务的人,花一个小时仔细读代码、跑场景、跟产品确认。证据链是给“可验证的变更”用的,不是给“需要判断的变更”用的。分清楚这两类变更,比盲目追求流程化更重要。
我现在的判断标准很简单:如果这个变更的“正确性”可以用测试用例覆盖,那就走证据链;如果它的“正确性”依赖于业务判断,那就走人工深审。两条路并行,不互相替代。
这套东西跑了大半年,最大的感受是:AI 写代码不是问题,问题是我们的评审能力没跟上。证据链 Skill 不是什么高深的技术,它就是把“评审时该看什么”这件事,从隐性经验变成了显性流程。而一旦流程显性化了,团队里每个人都能按同一套标准来判断“敢不敢合并”,这才是真正的效率提升。