多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

带证据链的代码评审:解决AI生成代码不敢合并的痛点

带证据链的代码评审:解决AI生成代码不敢合并的痛点 AI 写代码已经不是新鲜事。过去大半年我观察到身边团队一个很有意思的转折大家从“赶进度写需求”变成了“天天审代码”——因为 AI 生成代码的速度实在太快了一个下午能给你吐出一两千行但合并按钮却没人敢点。Git 里堆了一堆未合并的分支PR 开了两周还在“Reviewing”真正卡住的不是代码量而是信任。今天想跟你聊的是我最近在实践的一套东西一个带证据链的代码评审 Skill。它解决的恰好就是“敢不敢合并”这个问题。如果你也在用 AI 辅助写代码或者你是团队里负责 review 的人这篇内容大概率对你有用。1. 为什么 AI 写代码越来越快我们却越来越不敢合并1.1 产出爆炸信任赤字先说现象。以前一个功能单子下来开发自己写写完自己 review 一遍基本就敢合。现在呢开发把需求丢给 AIAI 五分钟出一版代码开发自己都还没读明白更别说 review 了。我见过一个真实数据某个业务分支AI 贡献了 70% 的代码行数但合并周期从原来的 2 天拉长到 9 天。原因不是代码质量一定差而是人对 AI 产出的代码缺乏掌控感。你知道它会说话但不知道它有没有骗你。这里说的“骗”不是故意撒谎而是 AI 生成代码时有很强的“表面正确性”。它能写出结构完整的函数、加上注释、配上看似合理的异常处理但边界条件、并发安全、数据一致性这些深水区它经常是“想当然”的。人一眼扫过去代码能看懂但“看懂”和“敢合并”是两回事。1.2 不敢合并的三个心理关卡我在团队里做过小调查问大家“为什么 AI 写的 PR 不敢快速合”答案高度集中在三个点不知道 AI 到底改了什么。它可能在同一段代码里做了 5 处修改但在 summary 里只写了 2 处或者反过来把大改动包装成“小重构”。这种信息差会让人本能地不放心。不知道改动影响面有多大。一个工具函数被改了调用它的地方有 30 处AI 说“不影响”可你没法验证每一处。尤其是跨模块的公共方法AI 自己都不一定清楚全量调用链。不知道测试是不是真的过了。CI 确实显示绿色但这个测试是不是针对这次改动的是不是覆盖了关键路径跑测试的代码和这次改动的代码版本是否一致快速合过几次之后总有一次会栽在这上面。这三个关卡本质上是同一个问题评审需要的是证据链而 AI 给的大多是解释。1.3 解释会骗人证据不会这是我这段时间最深的体会。你让 AI 解释它的代码它能给你写出三大段理由每条听起来都合理。但“合理”不等于“正确”。合并代码时人需要的不是理由而是可验证的事实比如改了哪个文件、哪一行为什么改对应的需求单号是多少新增的测试用例长什么样输入输出是什么是不是真的能覆盖这个改动有没有跑过全量回归跑了哪些用例结果如何有没有兼容性风险、性能风险、数据迁移风险这些风险有没有实际证据支撑判断。有人会觉得这些不都是基本功吗是。但问题是当 AI 把代码量放大十倍之后人的“基本功”不够用了。你不可能逐行 review 一千行 AI 生成的代码还同时去翻二十个文件。所以我们需要一个工具把“找证据”这件事自动化把“看证据”这件事结构化。2. 代码评审 Skill把“靠谱评审”固化成一套可执行流程2.1 Skill 是什么不是插件是一套行为准则你可能会想Skill 是什么当前主流的 AI 编程环境下Skill 可以理解为一组目录化的“技能包”里面有规则说明、检查清单、输出模板能告诉 AI 面对某个任务时应该按什么流程走而不是自由发挥。它和普通提示词最大的区别是强约束不是给 AI 一个“请帮我 review 一下这段代码”的提示而是让它按一套固定的、带结构化产出的流程执行。举个例子。以前我用 Cursor 或 Claude 看代码让它做评审它给我的是一段流畅的段落读起来很舒服但你没办法拿它当评审依据。因为这里面没有“结论”没有“证据位置”没有“验证步骤”。而 Skill 的核心是把它变成一份报告每一句结论后面都必须有证据没有证据的结论自动标注为“猜测”。类比一下Skill 就像是把你团队里最资深那个 reviewer 的工作习惯写成了一本操作手册。他 review 时先看什么、遇到什么情况会打回、什么情况才放行全部变成规则和模板。AI 照着执行输出的不是“读后感”而是“审查记录”。2.2 证据链的三条硬标准我设计这个 Skill 时对“证据链”下了三条硬标准缺一条都算不合格可追溯任何一条评审结论必须能追到具体的代码位置文件路径 行号 代码片段不能是“感觉这里有问题”。可复现任何一条“通过”或“风险”必须附上一个可执行的验证命令或测试用例其他人拿到报告后能自己跑一遍。可反驳结论必须给出置信度并且明确交代没覆盖到的场景。也就是说AI 要承认自己“没看到的角落”而不是把所有东西都说成“没问题”。这三条标准看起来简单实际执行起来要命。因为 AI 默认的说话习惯是“流畅表述”你让它给出置信度它通常会写得很自信。所以 Skill 里必须写清楚置信度低于 80% 的结论一律放到“需人工确认”区不能混进“通过”区否则证据链就是摆设。2.3 证据链的成熟度分级为了让团队对“证据到底够不够”有个统一尺子我习惯把证据链分成四个等级评审报告里必须标注等级名称含义合并参考L0无证据只有结论没有出处纯 AI 推测打回必须补证据L1有出处结论指向具体代码位置但没有测试验证可讨论不可直接放行L2有验证附带了可复现的测试命令和用例结果可以进入人工复核阶段L3有回归全量测试、兼容性、性能等关键试验全部有记录通常是放行级别但仍需人工点头这个分级的目的是让 AI 不再“假装自信”。以前它可能给你一句“这个重构安全”现在它必须说“这个重构符合 L2 证据标准测试命令是 X输出为 Y建议人工确认调用方 Z”。当你把报告里所有结论都按这个分级标出来合并决策就变成了一个很简单的动作有没有 L0 和 L1 的结论混进了“可合并”区。3. 手把手构建一个带证据链的代码评审 Skill3.1 Skill 目录结构先搭一个最小可用的骨架下面是我实际在用的一个最小化结构你完全可以从这个开始不需要一上来就搞得很复杂skills/ code-review/ SKILL.md checklist/ blocking.md warning.md suggestion.md templates/ review-report.md每个文件职责如下SKILL.md定义 Skill 的触发条件、总体目标、执行步骤和输出格式要求是 AI 读到的第一份指令。checklist/存放具体的检查清单按“阻断项 / 警告项 / 建议项”分文件这样每次评审可以按优先级加载不会让 AI 一次性把所有规则都背出来。templates/review-report.md评审报告的 Markdown 模板强制 AI 按固定结构输出避免它自由发挥。3.2 SKILL.md 里的核心指令这个文件是整个 Skill 的灵魂。我的版本里开头是这样写的# Code Review Skill ## 目标 在合并前对指定分支/提交进行深度代码评审输出一份带证据链的评审报告。 所有结论必须遵循三级证据标准可追溯、可复现、可反驳。 ## 触发条件 - 用户要求“评审代码”“review PR”“分析本次改动”时触发 - 默认评审范围当前分支相对主干的最新 diff ## 执行步骤 1. 先获取完整 diff 清单统计改动文件数和行数 2. 识别改动文件中的核心模块、公共函数、配置文件 3. 按 checklist/blocking.md 逐项检查每项必须填写证据 4. 按 checklist/warning.md 检查输出风险矩阵 5. 最后用 templates/review-report.md 生成报告。 ## 硬规则 - 所有结论必须包含文件路径、行号、代码片段、置信度 - 置信度低于 80% 的结论一律放入“需人工确认”区 - 禁止使用“整体安全”“没有问题”这类无证据表述 - 未覆盖到的情况必须显式声明不能隐藏。这里值得说明的是“硬规则”里的最后一条。你如果用过 AI 评审一定见过它喜欢在结尾来一句“整体来看改动质量较高可以合并”。这种话对合并决策毫无价值甚至有害。Skill 里必须把它列为违反规则强制 AI 要么给证据要么闭嘴。3.3 检查项设计阻断项 / 警告项 / 建议项检查项是这个 Skill 真正产生价值的部分。我按危害程度分成三级每一级都要求证据字段。阻断项Blocking意思是只要命中任意一条就不允许合并。我目前配置了这些数据迁移或 schema 变更没有回滚方案敏感信息密钥、Token、个人数据被硬编码或写入日志并发读写场景出现了非原子操作且无锁或事务保护错误处理吞掉异常catch 之后没有日志也没有向上抛新增或修改的公共函数没有调用方兼容分析。每条阻断项在生成结论时都要有“违反位置”和“为什么严重”的具体证据。比如[阻断] 文件 src/auth/token.go 第 42 行错误处理分支 catch 后仅打印空行日志 无 stack trace丢失原始错误信息。影响线上排查问题时无法定位根因。 置信度92%警告项Warning不强制打回但必须提醒人工关注。我常配置的有新增代码重复率超过阈值对老接口的调用没有处理废弃警告新增依赖过大或来源不明测试用例覆盖了主路径但没有覆盖异常分支代码格式和现有风格有明显不一致。建议项Suggestion属于锦上添花可合并后再处理。比如命名优化、注释补充、性能微优化等。检查项的具体内容每个团队应该按自己的技术栈来调。比如你用的是 Java 和 Spring和我的 Go/Node 环境肯定不一样。Skill 的好处就在这规则是文件随时可以改不像人的习惯那么难调。3.4 评审报告模板让结论可以直接投票评审报告模板是整个 Skill 的出口决定了 AI 的输出质量。我的模板核心结构如下# 代码评审报告 ## 评审范围 - 分支feat/xxx - 对比基线main - 改动文件数XX - 改动行数XX / -XX ## 总体结论 - 可合并性通过 / 不通过 / 需人工确认 - 阻断项数量X - 警告项数量X - 建议项数量X ## 阻断项如有默认不通过 | 位置 | 问题描述 | 证据 | 置信度 | ## 警告项 | 位置 | 问题描述 | 证据 | 置信度 | ## 需人工确认区 所有置信度低于 80% 或缺少证据的结论统一放这里。 ## 验证记录 - 构建命令及输出 - 测试命令及用例列表 - 未执行的验证项要注意模板里“需人工确认区“是绝对不能少的。这是证据链完整性的兜底。如果你省掉这个区AI 会把所有不明确的结论混在正文里说出来反而更难让 review 者判断哪些该信、哪些不该信。把不明确的集中在一起人工一眼扫过去就知道哪里要花时间。3.5 和 Git 流程的结合让报告跟着 PR 走Skill 不是跑完就完后面要接到 Git 工作流里才有价值。我目前的实践是三种方式叠加本地跑在提交前用git diff拿到改动直接调用 Skill 生成预评审报告可以提前发现低级问题CI 里跑在 PR 流水线里加一步自动用评审 Skill 分析本次 diff把 Markdown 报告作为 PR Comment 贴上去人工打开 PR 第一眼看到的不再是”测试通过/失败“而是一份评审结论合并前检查把阻断项数量作为合并门槛的软指标比如阻断项大于 0 时会在 GitHub/GitLab 的合并检查里显示红色提示禁止合并。在这里必须强调一个原则Skill 的输出只是参考合不合并永远由人决定。后面第五部分我会专门聊人机边界这里先记住不要让 CI 自动合并哪怕阻塞项为 0。4. 一次“不敢合并”的复盘与几个实战踩坑4.1 一次真实复盘表面绿色线上超时讲一个我实际遇到的场景。当时我们用 AI 重构了一段工具函数功能是把一批用户数据从 A 格式转换成 B 格式。AI 改完后单元测试全绿CI 也是绿的看着可以直接合。但我多留了个心眼把改动前后的数据量对比了一下发现输入数据里有一种边界情况空数组传入时原代码会直接返回空AI 改完的版本会走一遍循环再返回空逻辑上没错但会额外创建一个临时数组。单次看无所谓可这个函数线上每秒被调用几万次多一次分配就意味着多几万次 GC。当时如果没有人工这一层检查合并之后大概率表现为“服务偶尔延迟增多”排查起来极其痛苦。后来我用现在这套 Skill 跑了一次复盘发现它应该能在“警告项”里抓住两个点函数在空输入、单元素输入、大数组输入三种情况下的性能特征没有对比证据改动后的分支没有做基准测试只验证了功能正确性。你看如果当时有证据链要求AI 在报告里就会暴露这两个缺口我们合并前的决策就完全不同。这件事让我确信评审 Skill 的价值不是抓住 bug而是把“没验证过的东西”亮出来。4.2 踩过的四个坑每个都真实坑 1AI 自己评自己容易自我安慰。让同一个模型既写代码又评审自己的代码它天然倾向于维护自己生成的逻辑。后来我把评审和生成分成两个环节甚至用不同模型做评审情况好很多。如果团队只有一种 AI 工具至少做到让 AI 在评审时假设“这段代码是别人写的”并且把生成时的对话上下文重置避免它顺着生成的思路走。坑 2证据字段写得太泛变成了空话。一开始我的 Skill 只要求“附上证据”AI 就给我写“已运行测试验证”但没给命令和结果。后来我在模板里强制规定证据必须包含实际执行过的命令原文、输出摘要、涉及的测试文件路径。没有这三样就把这条结论降到 L1进“需人工确认区”。坑 3规则堆太多一次评审刷上万字。最初我从网上抄了一堆检查清单加起来几十项结果每次评审报告长到没人看。后来做了分类和抽样阻断项必须全量逐项检查警告项可以按文件量抽检建议项默认不展开。报告长度控制在几百行以内才能送到决策者眼前。坑 4把“低风险”当“无风险”。AI 最擅长的就是在你不注意的时候用“轻微”“低风险”“不影响现有功能”这种词替代结论。我在 Skill 里加了一条硬规则禁止使用任何程度副词代替证据。要说低风险必须有证据说明为什么低而不是说一个“低”字。4.3 常见问题速查表现象原因解决办法报告里没有文件行号模板里没硬性要求在模板“证据”列强制填文件路径和行号缺失时自动归入需人工确认区结论全是“需人工确认”规则过严或模型能力不足调整置信度阈值或换更强模型跑评审每次评审太慢检查项太多或 diff 过大拆分 diff按模块评审检查项抽样执行AI 评审和生成结果一致抓不出问题模型陷入自我验证循环换模型评估、重置上下文、假设是别人的代码报告没人看输出太长太绕用“总体结论”一句话先行细节折叠在表格里除了这些我再分享一个实用小技巧先用git diff --stat让 AI 判断改动规模再决定要不要完整评审。比如只有几行配置变更时跑一个几十项检查的完整 Skill 纯属浪费而核心模块改了 500 行就必须上完整评审流程。现在我的 Skill 里预设了三档“评审深度”根据 diff 大小自动选择。5. 从个人习惯到团队规范这样落地才不会被抵制5.1 先试点不要一上来全组推行评审 Skill 这种东西如果直接要求全组每天跑大概率会被当成形式主义。我建议的路径是先在你自己的项目里跑两周把报告模板调到大家都愿意看的程度然后找一个正在开发新功能的团队试点让他们在 PR 评论里贴一份报告等觉得确实能用再推广到全组。试点阶段要注意观察一个信号人工 review 者是否愿意基于报告做二次审查。如果报告只能作为“已跑过评审”的打卡凭证那说明证据链设计失败了。真正有效的报告应该让人工 reviewer 觉得“我只需要盯着需人工确认区看其他地方可以快速扫过”省掉他自己去翻代码的时间。5.2 设合并门槛但留人工裁决的出口落地时可以给合并流程设一道软门槛阻断项数量必须为 0否则不允许合并警告项不超过 3 个且每一项都要有明确的处理计划“需人工确认区”面积超过报告三分之一时不允许一键合并必须有评审者逐条点过。注意这个门槛是“软”的不是“硬”的。因为规则再完善也有误报。真要遇到紧急线上修复阻断项超了也得合。但“允许打破规则”和“默认就能突破规则”是两回事我建议所有破例合并都留一个备注原因后续复盘可以看到哪些规则需要调整。5.3 人机边界Skill 是筛子人是最终裁决者这是我最想强调的一点。AI 写代码、AI 评审代码、AI 生成证据链这些都可以自动化但“合并”这个动作语义上等同于“我确认这份改动符合我的要求”这是一种责任不应该交给自动化流程。我见过一些团队走到另一个极端Skill 跑得顺利CI 也绿了于是有人把合并改成自动执行。结果某次 AI 生成的代码有隐蔽性能问题全自动流程直接合并上线出问题后连个能接受质询的人都没有。这件事之后我把 Skill 的输出定位调整了一行说明报告永远只回答“证据是否足够”不回答“是否应该合并”。后者是人的判断。5.4 把证据链沉淀成团队资产最后提一个有长期价值的事维护你的 Skill 规则文件。每次人工评审发现了 Skill 没抓出来的问题就在 checklist 里加一条每次报告里有 AI 反复用模糊表述就在硬规则里补一个禁令每次团队换了技术栈就调整检查项的优先顺序。这个 Skill 会像 wiki 一样越用越符合团队实际。我在实际操作中发现这个过程本身就是团队经验沉淀的过程。过去资深工程师的心得存在脑子里人走了经验就断了。现在心得变成 SKILL.md 里的一条规则、模板里的一个字段新人接手时天然继承。代码评审从个人手艺变成了组织能力这可能比短暂提升合并速度更有意义。最后再分享一点个人体验。这套带证据链的评审 Skill 我用了快三个月最大的改变不是 bug 数量变少了其实也没有明显减少而是合并前的焦虑感大幅下降。以前对着 AI 生成的一大段代码总有种“不知道哪里会炸”的不安现在打开报告看到 L0 和 L1 的结论都被标出来放在“需人工确认区”我知道该往哪里盯心里就踏实了。一个小技巧是把它和 commit message 模板配合起来每次合并时把评审报告编号写进 commit 里比如refs review#128之后排查线上问题时能顺着编号一路追回当时的证据链。这东西不复杂但长期坚持下来你会发现自己对 AI 代码的态度从“不敢合”变成了“敢审着合”。
返回列表