
1. 从“能写”到“敢合”AI 代码评审的真实分水岭过去一年我身边几乎所有团队都在用 AI 写代码。补全、生成、重构、写测试效率提升是肉眼可见的。但有意思的是真正让大家卡住的不是“AI 能不能写出能跑的代码”而是“这段代码到底能不能合并进主干”。我见过太多这样的场景AI 一口气生成了三百行改动逻辑看起来没问题测试也过了但 review 的时候没人敢点那个 merge 按钮。为什么因为说不清楚这段代码为什么这么改、改了哪些边界、有没有引入隐性依赖、跟原来的设计意图是否一致。换句话说AI 写代码之后真正稀缺的不是生成能力而是“证据链”。这也是我最近特别关注“代码评审 Skill”这个方向的原因。所谓 Skill在这里指的是给 Agent 或者 AI 助手封装的一套可复用的能力单元它不只是提示词而是包含输入约定、执行步骤、输出格式、判断标准的完整流程。一个带证据链的代码评审 Skill核心目标就是让每一次合并决策都有据可查而不是靠“感觉应该没问题”。这篇文章适合三类人看一是正在用 AI 辅助开发、但 review 流程还没跟上的工程师二是想给团队搭一套 AI 协作规范的 tech lead三是对 Agent、Skill 开发感兴趣想找一个真实落地场景练手的人。我会从为什么需要证据链讲起拆解一个代码评审 Skill 应该包含哪些核心模块然后给出可复现的实现思路和实操中踩过的坑。先抛一个我自己的结论没有证据链的 AI 代码评审本质上只是把“人不敢合”变成了“AI 说能合”风险并没有消失只是被转移了。真正有价值的 Skill是能把 git diff、上下文、测试结果、影响范围、决策理由串成一条可追溯的链路。2. 为什么普通 AI Review 给不了你安全感2.1 “看起来没问题”是最危险的评审结论大多数人用 AI 做代码评审的方式很简单把 diff 贴进去问一句“这段代码有什么问题”。AI 会给你一堆看起来很有道理的建议比如“建议增加空值判断”“这里可能有并发问题”“变量命名可以更清晰”。这些建议不能说错但问题是——它们和“能不能合并”之间隔着一道巨大的鸿沟。我实测过很多次同一段 diff换个问法AI 的结论可能完全相反。你问“这段代码有风险吗”它能列出一堆风险你问“这段代码能合并吗”它往往说“整体看起来可以但建议进一步测试”。这种模糊结论对 review 决策毫无帮助。评审的本质不是找问题而是判断“在当前上下文下这次变更是否可接受”。2.2 缺少上下文AI 只能猜代码评审最依赖的东西不是 diff 本身而是 diff 之外的上下文这个函数被谁调用、这个配置在哪些环境生效、这个改动对应的需求是什么、之前的 commit 为什么这么设计。普通 AI Review 拿到的只有 diff它不知道这些所以只能基于“通用最佳实践”给建议。举个真实例子。有一次 AI 建议我给一个内部工具函数加参数校验理由是“防止非法输入”。听起来很对但这个函数只在启动阶段被调用一次参数来自硬编码配置加校验纯属多余还会让启动失败时更难排查。AI 不知道这个上下文所以它的建议在局部正确、在全局错误。2.3 证据链到底指什么我说的证据链不是让 AI 写一篇长篇大论而是让评审结论背后有可验证的支撑。具体来说一条完整的证据链至少包含这几层变更意图这次改动想解决什么问题来自哪个需求或 issue。变更范围改了哪些文件、哪些函数、哪些配置影响面有多大。行为差异改动前后程序行为发生了什么变化边界条件是否改变。验证证据有哪些测试、日志、手动验证可以支撑“行为符合预期”。风险判断剩余风险是什么是否需要额外监控或回滚预案。普通 AI Review 只覆盖了第三层的一部分而且往往是猜的。一个合格的代码评审 Skill要把这五层都串起来输出一份“可决策”的报告而不是“可参考”的建议列表。3. 拆解一个带证据链的评审 Skill 该有哪些模块3.1 输入层不只是 git diff很多人做 Skill 的第一个误区就是只把 diff 当输入。diff 是核心但远远不够。我在实际搭建时输入层至少包含这几类信息输入类型作用获取方式git diff变更内容主体git diff main...HEADcommit message变更意图线索git log关联 issue/需求业务背景手动关联或从分支名提取变更文件清单影响范围git diff --name-only测试结果验证证据CI 输出或本地测试日志项目规范判断标准团队约定的 lint/规范文件这里有个实操细节diff 不要只取HEAD要取目标分支到当前分支的完整差异。我踩过的坑是只取最后一次 commit 的 diff结果漏掉了前面几个 commit 引入的依赖变更评审结论直接失真。3.2 分析层把 diff 翻译成行为变化分析层是整个 Skill 的核心。它要做的事情不是“找 bug”而是“描述行为变化”。我通常把它拆成几个子步骤结构化 diff把原始 diff 按文件、按函数、按逻辑块切分而不是一大坨文本。识别变更类型是新增功能、修复缺陷、重构、配置调整还是依赖升级。不同类型评审重点完全不同。追踪调用关系对被修改的函数找出调用方和被调用方判断影响是否外溢。对比行为差异用自然语言描述“改动前会怎样、改动后会怎样”尤其是边界条件。这一步的关键是让 AI 做它擅长的事归纳和对比而不是做它不擅长的事凭空判断风险。你让它描述行为差异它做得很好你让它判断“能不能合并”它就开始含糊。3.3 验证层测试不是万能但没测试万万不能验证层要回答一个问题这次变更的行为有没有被验证过注意不是“测试有没有过”而是“测试有没有覆盖到这次变更的关键路径”。我见过太多“测试全绿但线上出事”的案例原因是测试覆盖的是旧行为新改动的分支根本没被测到。所以验证层要做的是检查变更涉及的分支、条件、异常路径是否有对应测试。检查测试结果是“新增测试通过”还是“旧测试没挂”。如果没有测试覆盖明确标注为“未验证风险”而不是默认通过。提示验证层不要追求“自动判断测试是否充分”那太难了。更务实的做法是“列出变更点逐条标注是否有测试覆盖”把判断权交回给人。3.4 输出层一份能直接用于决策的报告输出层决定了这个 Skill 好不好用。我的经验是报告要短、要结构化、要能直接对应到 merge 按钮。我常用的格式是这样的## 变更摘要 一句话说明这次改了什么。 ## 行为变化 - 改动前... - 改动后... - 边界变化... ## 影响范围 - 直接影响... - 间接影响... ## 验证情况 - 已覆盖... - 未覆盖... ## 剩余风险 - 风险点... - 建议动作... ## 合并建议 可合并 / 有条件合并 / 不建议合并注意最后一行一定要给出明确倾向而不是“请自行判断”。有条件合并时要写清楚条件是什么比如“需要补充 XX 场景测试”或“需要在灰度环境观察 XX 指标”。4. 用 Agent 跑通评审流程从 diff 到报告4.1 环境准备与最小可行链路要跑通一个评审 Skill不需要一上来就搞复杂框架。我用最小链路验证过核心就三样一个能读 git 仓库的 Agent、一套结构化的提示词模板、一个输出报告的文件。如果你用 Python 做大致流程是这样import subprocess def get_diff(basemain): result subprocess.run( [git, diff, f{base}...HEAD], capture_outputTrue, textTrue ) return result.stdout def get_changed_files(basemain): result subprocess.run( [git, diff, --name-only, f{base}...HEAD], capture_outputTrue, textTrue ) return result.stdout.strip().split(\n) def get_commit_messages(basemain): result subprocess.run( [git, log, f{base}..HEAD, --prettyformat:%s%n%b], capture_outputTrue, textTrue ) return result.stdout拿到这些之后把它们拼成一个结构化输入交给 Agent 分析。这里的关键不是代码多复杂而是输入要分块、要带标签让 AI 清楚哪部分是 diff、哪部分是 commit、哪部分是文件清单。4.2 提示词模板的写法约束比自由更重要我试过很多版提示词最后发现最有效的不是“请你仔细分析”而是明确约束输出结构和判断标准。比如你是一个代码评审助手。请基于以下输入输出一份评审报告。 输入 - 变更意图{commit_messages} - 变更文件{changed_files} - 变更内容{diff} - 测试结果{test_result} 要求 1. 用“改动前/改动后”描述行为变化不要只复述 diff。 2. 影响范围要区分直接和间接。 3. 验证情况要逐条标注是否有测试覆盖。 4. 剩余风险要具体不要写“可能存在风险”这种空话。 5. 最后给出明确的合并建议可合并 / 有条件合并 / 不建议合并。这个模板的核心是第 1 条和第 5 条。第 1 条逼着 AI 做行为翻译第 5 条逼着 AI 给结论。中间几条是防止它输出空泛内容。4.3 实测中 Agent 最容易犯的三个错第一个错是过度自信。AI 经常在没看到测试结果的情况下直接说“测试应该没问题”。解决办法是在提示词里明确没有测试证据时必须标注“未验证”不允许推断。第二个错是忽略间接影响。比如改了一个工具函数AI 只分析这个函数本身不追踪调用方。解决办法是在分析层加一步“调用关系追踪”哪怕只是简单 grep 函数名也能大幅提升准确度。第三个错是结论摇摆。同一份 diff跑两次可能给出不同建议。这通常是因为提示词里判断标准不明确。我的做法是把“合并建议”的判定规则写死比如“存在未覆盖的关键路径测试时只能给有条件合并或不建议合并”。4.4 把评审结果接回工作流Skill 跑通之后下一步是接回工作流。我目前的做法是在 CI 里加一个可选步骤生成评审报告并作为评论贴到 PR 上。注意是“可选”不是“强制阻断”。原因很简单AI 评审目前还不具备阻断合并的可靠性它的价值是辅助决策不是替代决策。如果你用 GitHub Actions大致是这样- name: AI Review run: python review_skill.py review_report.md - name: Comment uses: actions/github-scriptv6 with: script: | const fs require(fs); const body fs.readFileSync(review_report.md, utf8); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body });这样每次 PR 都会多一份结构化报告reviewer 可以对照着看而不是从零开始读 diff。5. 让评审结论真正可信几个关键设计取舍5.1 为什么我坚持“证据优先于判断”在设计 Skill 时有一个根本取舍是让 AI 直接给判断还是让 AI 先给证据、再由规则或人给判断。我坚定选后者。原因是 AI 的判断不稳定但 AI 的归纳能力很稳定。你让它描述“改了什么”它几乎不会错你让它判断“能不能合”它经常飘。所以我的 Skill 里AI 负责生成证据链合并建议由一套明确规则生成。比如有未覆盖的关键路径测试 → 最多“有条件合并”。影响范围涉及公共接口 → 最多“有条件合并”。纯文档或注释变更 → 可直接“可合并”。涉及配置或依赖变更 → 必须标注“需人工确认”。这套规则不复杂但它让结论变得可预期、可解释。5.2 diff 太大时怎么办实测下来diff 超过一千行时AI 的分析质量会明显下降。我的处理方式是分片评审按文件或按逻辑块切分每片单独生成证据最后再汇总。汇总时只保留行为变化和风险点不重复细节。另一个技巧是优先评审高风险文件。比如配置文件、公共库、数据库迁移脚本这些优先分析纯样式或文案改动可以简化处理。这样能在 diff 很大时保住关键部分的评审质量。5.3 怎么处理“AI 说没问题但人觉得有问题”这种情况太常见了。我的经验是不要试图让 AI 说服人而是让 AI 把“它认为没问题的理由”写清楚。如果理由站不住脚人自然会发现。比如 AI 说“这个改动不影响其他模块”但报告里没有调用关系分析reviewer 一眼就能看出证据不足。反过来如果人觉得有问题但说不出具体在哪也可以让 AI 针对某个点深入分析。Skill 的价值不是给答案而是给一个可以追问的结构。5.4 评审 Skill 和普通 lint 的边界有人会问这不就是高级 lint 吗不是。lint 检查的是语法和风格评审 Skill 检查的是行为和影响。lint 能告诉你“这行不符合规范”评审 Skill 要告诉你“这个改动会让某个边界条件从 A 变成 B而 B 没有被测试覆盖”。两者层次完全不同也不能互相替代。我在实际使用中会把 lint 结果作为评审 Skill 的一个输入而不是让 Skill 重复做 lint 的事。这样分工清晰lint 管规范Skill 管决策证据。6. 实操心得那些文档里不会写的细节6.1 先跑通“只读”版本再考虑自动化我见过不少人一上来就想做全自动评审加自动合并结果要么误报太多没人用要么漏报太多不敢用。我的建议是先做一个只读版本只生成报告不阻断、不自动操作。跑上一两个月看看报告质量稳不稳定再考虑接入更多自动化。这个阶段最重要的指标不是“发现了多少问题”而是“reviewer 有没有真的看这份报告”。如果没人看说明报告要么太长、要么没用得改。6.2 报告长度控制在“一屏能看完”我最初做的报告特别详细每个文件都分析一遍结果没人看。后来改成“摘要 关键风险 合并建议”控制在一屏以内使用率立刻上来了。细节可以折叠或放在附录但核心结论必须一眼可见。6.3 把“未验证”当成一等公民很多评审工具喜欢把“没发现问题”等同于“没问题”。这是最危险的。我的 Skill 里“未验证”是一个明确的输出状态和“已验证通过”同等重要。reviewer 看到“未验证”就会知道这里需要人工确认而不是默认安全。6.4 定期回看误报和漏报任何评审 Skill 都需要迭代。我每个月会抽时间回看这个月被合并的 PR看看哪些报告说“没问题”但后来出了问题哪些报告说“有风险”但其实是误报。这些案例是最好的改进素材比拍脑袋改提示词有效得多。6.5 团队规范要写进 Skill而不是靠 AI 猜每个团队都有自己的规范比如“公共接口变更必须加测试”“配置变更必须走审批”。这些规范如果只写在文档里AI 是不知道的。我的做法是把它们写成明确的规则作为 Skill 的一部分。这样评审结论才能贴合团队实际而不是通用最佳实践。7. 从代码评审延伸出去Skill 化思维的通用价值做完这个代码评审 Skill 之后我最大的收获其实不是评审本身而是Skill 化思维。所谓 Skill 化就是把一件模糊的、依赖个人经验的事情拆成输入、步骤、判断标准、输出四部分让 AI 能在约束下稳定执行。这个思路可以迁移到很多场景。比如测试用例生成、接口文档维护、发布检查清单、甚至周报整理。核心都是一样的不要让 AI 自由发挥而是给它一个结构让它在这个结构里做它擅长的事。回到代码评审这件事。AI 写代码之后真正难的是“敢不敢合并”。而“敢”不是靠勇气是靠证据。一个带证据链的评审 Skill做的就是把这件靠感觉的事变成一件靠证据的事。它不会让所有合并都变得毫无风险但它能让每一次合并决策都有迹可循。我在实际使用中体会最深的一点是当评审报告能把“改了什么、影响什么、验证了什么、还剩什么风险”讲清楚时merge 按钮就不再那么可怕了。这大概就是证据链真正的价值。