LLM如何重构代码评审:从全量人肉Review到AI预筛+人工判断 最近 Hacker News 上有一个讨论挺能反映当下团队心态的问题Ask HN: What happens to code review process when using LLMs?。表面上看它是问LLM 能不能替人做代码评审但实际上这个帖子真正想问的是当评审流程里多了一个永远在线、不累、还话多的 AI 参与者之后原本那条成熟的 code review 流程到底会发生什么哪些环节被保留哪些环节被重构又有哪些环节会悄悄失效。很多团队的现状是这样一个 PR 提交上去reviewer 可能要过半天甚至一天才有空打开。好不容易打开看到 1200 行 diff里面有 200 行是格式调整300 行是改注释真正有逻辑变化的只有几处。reviewer 一边忍着烦躁跳过噪音一边担心自己是不是漏掉了什么关键问题。最后评论里既要指出这个方法命名不符合规范又要讨论这个缓存策略在高并发下有风险一场评审下来真正涉及设计权衡的讨论可能只占了十分钟。这时如果有一个 LLM 提前把格式、命名、明显空指针、遗漏异常处理这些低层问题过滤掉reviewer 的工作体验确实会好很多。但新的问题马上出现了AI 给的意见到底听不听AI 说看起来没问题谁对最终合并负责如果开发者把 AI 的意见当成标准答案无脑采纳代码评审体系里最重要的人为责任机制会不会被架空我的判断是LLM 不会让代码评审消失也不应该让它消失。它真正改变的是评审流程的重心分布——AI 负责低层检查和信息压缩人负责意图判断和架构决策。换句话说这不是加了一个自动化工具箱而是把原有的全量人肉评审重新拆成了机器预筛 人工判断两层流程的位置、节奏和责任边界都被重新定义了。1. 为什么这个问题值得重新审视从目标上看代码评审从来不只是找 bug。它承担了三件不同的事防止明显缺陷进入主干把代码知识在团队内传递在合并之前形成这是对的的共同判断。这三件事的价值密度差异很大而 LLM 对它们的介入深度也不同。对于防止明显缺陷进入主干LLM 确实能做出很大贡献它擅长识别模式化的代码问题而且不会因为连续看了多个 PR 就疲劳。对于传递代码知识LLM 只是加速了信息整理真正的知识沉淀仍然发生在人和人的讨论里。至于形成共同判断LLM 很难承担因为它没有业务目标也不为线上故障负责。这个帖子值得重新讨论还因为它暴露了一个容易被忽略的误区很多人把评审和检查混为一谈。传统评审里reviewer 是在一堆低层问题中寻找少量真正的风险这个过程消耗了大量注意力。LLM 介入之后低层检查被剥离出去人的注意力应该被集中到真正需要判断的部分。但如果团队没有主动调整流程LLM 就会变成一个评论噪音制造机在 PR 页面刷几十条意见反而让评审体验恶化。这篇文章主要面向三类读者正在为团队设计评审流程的技术负责人开发节奏快、reviewer 长期不够用的开发者负责代码质量平台和工程效能体系的工程师。读完可以知道 LLM 在评审流程里适合放到哪个位置、怎么接入、怎么验证效果、怎么避开那些会让评审失真的坑。2. 传统代码评审机制回顾先看清基线讨论变化之前先把传统流程画一条基线。一个典型的评审流程是这样的开发者完成功能分支整理成 PR或 MR触发 CI 构建和测试测试通过后评审者打开 diff 页面逐行查看发现问题就留行内评论开发者回复、修改、再次提交评审者反复确认后点击 Approve最后拥有权限的人合并代码。在流程正常运转的团队里这套机制是有效的但它隐含着三种成本。第一种是等待成本。评审者通常有自己的开发任务从一个上下文切换到另一个上下文并理解一个陌生模块需要的时间远比想象中高。PR 一旦排队合并速度就会被拖慢。第二种是注意力成本。reviewer 要在大量看起来不对劲但其实无关紧要的代码里找到真正的高风险项这是一件高度消耗耐心的工作。第三种是质量波动成本。评审质量高度依赖评审者当天的状态和经验新人容易只盯着格式和命名经验丰富的人才会去追问并发、缓存一致性、异常恢复路径这类问题。与此同时传统评审还有一个被普遍低估的价值知识传递和团队共识形成。新人通过评审学习代码规范和历史背景老手通过讨论把一个设计决策为什么是这个样子讲清楚。这个环节很难被 AI 取代也不应该被取代。如果未来某个流程设计把人与人的讨论整个拿掉那节省的其实是团队长期能力的建设成本。所以传统流程真实的矛盾点在于人的时间大量消耗在低层检查上真正需要人类判断的设计讨论反而没有足够时间。LLM 的切入点就在这里——它不必替代人它可以把人从第一类工作中解放出来让注意力集中到第二类工作上去。3. LLM 在代码评审中扮演的四个角色在真实工程里LLM 参与评审并不是一种形态。更准确地说它可以同时扮演四个角色只是每个角色的可靠性不同对流程的意义也不同。3.1 低层问题过滤器这是 LLM 最稳定、最不容易翻车的角色。给它一段 diff它能快速识别出空指针风险、未处理的异常路径、越界访问、资源未关闭、重复代码、命名风格不一致、缺少单元测试等问题。这些恰恰是传统评审里最消耗时间也最让人烦躁的部分。把它们交给模型相当于让 reviewer 打开 PR 时先拿到一份已经过滤掉低层噪音的清单。这个角色有明显的天花板。它看到的只是当前 diff不理解这个 PR 背后的业务动机也不知道改动对应的历史设计决策。它报出的必改项往往是规则层面的问题不是业务风险层面的问题。也就是说低层过滤器只能做这里看起来有问题的检视不能做这个改动会不会破坏业务一致性的判断。3.2 评审摘要器摘要可能是 LLM 在评审流程中价值最被低估的能力。一个大型 PR 可能涉及十几个文件的改动直接看 diff 会让人产生强烈的拖延心理。模型可以快速输出一份结构化摘要改了哪些模块、新增了什么接口、哪些文件是纯重构、哪些改动触碰了核心数据结构、哪些调用方可能受影响。这份摘要的价值在于降低了进入评审的心理门槛。reviewer 不需要自己从零梳理代码变化而是可以直接带着摘要进入具体代码区域。但摘要也存在一个明显风险摘要是一种信息压缩压缩一定会丢失细节。如果 reviewer 只看摘要不看关键 diff那它就会变成新的盲区来源。更麻烦的是摘要里的任何模糊表述会产生先入为主的影响把评审者带向错误方向。3.3 自动化风险分类器第三个角色是给问题分级。让模型按必改、建议、可选输出评审意见相当于在传统的发现问题和提交评论之间插入了一个优先级排序器。reviewer 不需要逐条处理几十条评论只需要优先看必改级别的高风险项。这个角色的难点在于分级标准需要团队自己定义。如果团队不把什么算高风险告诉模型它就只会按照训练数据里的通用安全认知来分类可能把方法名不够长标成必改把同一个事务里先写再读的缓存不一致标成建议。要让这个角色真正可用必须配合一套持续维护的评审规则和评测集否则它只能提供一种看似智能的噪音。3.4 设计权衡的陪伴者第四个角色经常被忽略。LLM 其实很适合作为设计讨论的陪聊者把当前方案、约束条件和担心的点发过去让它把 trade-off 列出来。它不能替工程师做决定但它可以把那些可能被忽略的选项快速摆出来帮助形成更完整的思考框架。你可以把下面这段问题发给评审模型 当前实现在订单查询接口中加入了 Redis 缓存缓存键包含用户 ID 和查询时间段。 请帮我列出 1. 这个方案最大的三个可靠性风险 2. 如果不引入缓存有没有等价的性能方案 3. 如果必须引入缓存失效策略应该怎么设计才能与数据库回写保持一致。在这个场景下模型的价值不是判断方案对不对而是用低成本的方式逼迫自己把问题从不同角度过一遍。它的结论只能用来扩展思路不能作为最终架构决策。真正拍板的人仍然是要对线上后果负责的工程师。4. 引入 LLM 前后的流程对比把传统评审和 LLM 参与后的评审放在一起比较会更直观地看到变化发生在哪里。流程维度传统人工评审LLM 参与后的分层评审评审起点PR 提交后等待 reviewer 开启提交前或提交后立即触发 AI 预检低级问题处理人工逐行发现模型自动过滤人只看列表人工注意力分布在整个 diff 中集中在高风险项和设计决策上评审等待时间取决于 reviewer 空闲时间AI 预检分钟级返回人工阶段可安排知识传递通过人与人的评论和回复实现需要主动保留AI 摘要只是辅助责任归属批准者个人承担合并责任仍然是人在承担AI 不承担评审氛围存在情绪和批评压力机器预筛可降低冲突感但不能完全消除这张表反映出的核心变化可以概括为三点。第一评审前移。过去评审是提交之后的一道闸门现在模型可以在开发者本地运行时就给出提示开发者有机会在 push 之前就处理掉一批低级问题。第二评审范围变宽。传统评审只针对当前 PR 的 diff但模型可以把当前 diff 与代码库的历史改动模式对照找出那些这次改动可能影响到的旧逻辑。这相当于给评审增加了一层边界影响分析而这个工作如果完全靠人来做成本会非常高。第三评审变轻。reviewer 面对的从全部 diff变成摘要 高风险项 需要决策的问题清单。评审的重心从看代码转向做判断。这个转变如果处理到位评审效率会显著提升如果处理不到位就会出现一种更隐蔽的风险reviewer 过度信任模型的摘要跳过关键 diff导致真正的问题漏检。5. LLM 代码评审的实际接入方式落地 LLM 评审并不只有接入一个 AI 机器人这一种形态。更合理的架构是三层并行。第一层是开发者本地的自检层在 push 之前用脚本对本地 diff 做快速预筛。第二层是 CI 集成层在 PR 提交后自动触发模型评审把结构化意见作为 review 评论或 Bot 报告贴到 PR 页面。第三层是人的审批层具备合并权限的 reviewer 仍然按自己的节奏阅读关键 diff处置 AI 标记的高风险项并最终 approve。三层职责不同每一层都不应该被另一层替代。5.1 本地辅助检查示例下面是一个本地辅助检查脚本的通用示意。它读取当前分支与主干分支的 diff调用模型服务生成评审结果。注意这只是一个流程示例实际接入时需要按你的模型服务商文档调整请求字段。# 文件路径scripts/review_helper.py # 使用方式python scripts/review_helper.py --base origin/main import argparse import json import os import subprocess def get_diff(base: str) - str: 获取当前分支相对 base 的差异只截取前 8000 个字符用于评审。 result subprocess.run( [git, diff, base], capture_outputTrue, textTrue, checkFalse, ) return result.stdout[:8000] def build_prompt(diff_text: str, context: str) - str: 构造评审提示context 由开发者补充业务目标。 return f这是一个代码评审请求请只输出评审意见不要修改代码。 需要特别关注空指针、并发、资源泄漏、数据一致性。 请区分三个级别必改 / 建议 / 可选。 需求上下文 {context} 代码 diff {diff_text} def call_review_endpoint(prompt: str, endpoint: str, api_key: str) - str: 调用模型服务。这里使用通用请求格式请以实际服务商文档为准。 import urllib.request payload json.dumps({ model: your-review-model, prompt: prompt, temperature: 0.2, }).encode(utf-8) request urllib.request.Request( endpoint, datapayload, methodPOST, headers{ Authorization: fBearer {api_key}, Content-Type: application/json, }, ) with urllib.request.urlopen(request, timeout60) as response: data json.loads(response.read().decode(utf-8)) return data.get(choices, [{}])[0].get(text, ) def main(): parser argparse.ArgumentParser() parser.add_argument(--base, defaultorigin/main) parser.add_argument(--endpoint, defaultos.environ.get(REVIEW_ENDPOINT)) parser.add_argument(--context, default) args parser.parse_args() if not args.endpoint: raise SystemExit(请通过环境变量 REVIEW_ENDPOINT 提供模型服务地址) diff_text get_diff(args.base) if not diff_text.strip(): print(没有发现差异跳过评审。) return prompt build_prompt(diff_text, args.context) api_key os.environ.get(REVIEW_API_KEY, ) review_result call_review_endpoint(prompt, args.endpoint, api_key) print(review_result) if __name__ __main__: main()这里有三点要特别提醒。第一不要在脚本里写死 API Key通过环境变量注入是最基本的要求。第二这个脚本把 diff 发给了外部模型服务如果项目包含商业机密或强合规数据需要先确认是否允许外发建议在内网私有化环境调用模型服务。第三git diff默认只截取 8000 字符是因为大多数评审场景并不需要把全部 diff 送入模型限制长度可以降低上下文成本和控制噪音。5.2 CI 自动评审示例本地脚本只能服务开发者一个人。要让评审意见沉淀在 PR 页面需要把脚本挂到 CI 流水线。# 文件路径.github/workflows/ai-review.yml # 简化示意实际使用前请根据仓库安全策略评估权限 name: ai-code-review on: pull_request: types: [opened, synchronize] permissions: contents: read # 只读代码内容 pull-requests: write # 需要让机器人以评论方式写入评审意见请评估仓库是否允许 jobs: review: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkoutv4 with: fetch-depth: 0 - name: Run AI Review env: REVIEW_ENDPOINT: ${{ secrets.REVIEW_ENDPOINT }} REVIEW_API_KEY: ${{ secrets.REVIEW_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python scripts/review_helper.py \ --base origin/main \ --endpoint $REVIEW_ENDPOINT \ --context 本 PR 目标...由维护者补充这个 YAML 只是一个流程示意关键在于理解它做了什么PR 每次打开或更新时自动用当前 diff 调用模型服务然后通过后续脚本把输出提交到 PR 评论。真正接入的时候需要额外写一段把 review_result 通过 GitHub API 提交评论的代码或者对接你自己团队使用的代码托管平台。pull-requests: write这个权限需要特别评估。它意味着 CI 机器人可以写 PR 评论如果你不信任当前仓库的公共代码权限边界就不要给这个权限改成把评审结果输出到 CI 日志由 review 者自行查看效果依然存在只是没有直接在 PR 页面展示那么醒目。5.3 让评审更有效的 Prompt 模板最后给一个可以沉淀下来作为团队模板的评审提示。它的设计思路是先给模型一个明确的角色定位再告诉它业务上下文最后规定输出格式。缺少业务上下文是 AI 评审产生噪音的首要原因。# Code Review Prompt Template 你是这个代码库的审查助手。你只输出评审意见不修改代码。 审查重点 1. 明显的运行时错误、空指针、并发风险、资源泄漏 2. 数据一致性问题和异常路径 3. 对业务意图无法判断的部分明确标记为需要作者确认。 要求 - 所有意见按严重级别分组必改 / 建议 / 可选 - 对每条意见引用 diff 中的关键行 - 如果在 diff 中看不到完整上下文不要凭猜测下结论。 业务上下文由作者填写 - 本 PR 的目标 - 受影响模块 - 相关历史 PR 或 issue Diff 内容这个模板真正执行的时候如果模型服务支持结构化输出可以用 JSON 格式约束解析会更方便。如果只是用它来做人工 review 的辅助保持文字格式也完全可以。 ## 6. 运行结果与效果验证 接入 LLM 评审之后团队最应该关心的不是它有没有输出意见而是输出意见的质量是否支撑流程变化。先看预期输出长什么样再谈怎么验证。 ### 6.1 预期输出示例 下面是理想化示意不代表模型一定会给出完全相同的结果 text 评审摘要 - 改动模块auth 认证、用户表结构、订单查询接口 - 高风险项2 个 1. token 缓存未设置过期时间可能导致权限滞留过长必改 2. SQL 拼接包含用户输入存在注入风险应改用参数化查询必改 - 建议项3 个 1. 用户表结构变更未提供数据迁移脚本建议 2. 新增方法缺少单测覆盖建议 3. 与订单查询接口耦合的缓存键命名不稳定建议如果输出中出现必改级别但理由含糊或者引用行不存在的意见就说明模型没有在合理读取 diff可能需要调整上下文输入方式或降低温度。6.2 验证评审效果的四个维度不要凭感觉评价 AI 评审好不好建议用四个指标持续观察。第一个是误报率。AI 标记的问题里最后被团队确认真的有问题、需要改的比例。误报率太高团队就会失去对 AI 意见的信任最后把整份评审报告跳过。第二个是漏报率。合并之后一段时间内线上暴露出来的缺陷里有多少是 AI 评审没有提到的。漏报率决定了它能否当第一层过滤器。第三个是人工注意力转移度。观察 review 者的时间是不是真的从低层问题转移到了设计讨论。如果 AI 加了进来reviewer 还是在逐行看全量 diff那这个接入就是失败的。第四个是评审周期和返工率。AI 预检能减少来回提意见的轮次但要注意不要把返工率下降归功于 AI需要同时看代码复杂度是否变化。更稳妥的验证方法是建立一个评测集。把过去两个月内真实出现过的带缺陷 PR收集起来脱敏后作为回放样本。每次调整模型版本、prompt 或代码切片策略时都在评测集上跑一遍记录发现缺陷数和误报数。这个评测集的价值远大于任何一次凭感觉的验收。7. 常见问题与排查方法LLM 评审接入过程中团队会遇到几类典型问题。下面把现象、原因和排查方向整理成表。问题现象可能原因排查方向解决方案AI 输出大量格式问题真正的逻辑问题没提prompt 没有限制审查重点模型在追求全面回答查看原始 prompt、输入 diff 是否被截断在 prompt 中明确只报逻辑风险去掉通用代码风格要求AI 给出不存在的 API、类名或配置项模型幻觉参考信息不在上下文中复检引用来源看是否要求模型引用文件路径强制模型只基于给定 diff 和代码库知识作答如支持检索则开启同一 PR 每次评审结果不一致temperature 设太高、输入切片不稳定重跑两次比对差异将 temperature 调低到 0.1 以下固定模型版本开发者无脑采纳 AI 意见流程未区分参考建议和审批决策看 review 过程和 merge 权限设置明确 AI 意见只是参考human approve 必须保留代码内容被外发到外部服务整库 diff 或密钥被送入模型请求检查脚本日志、出网策略和 secret 管理私有化部署模型/内网代理禁止 secrets 进入 prompt限制 diff 截取范围AI 评论刷屏PR 页面噪音很大没有按严重级别过滤输出分析评论类型占比只输出必改级别和真正的高风险项可选意见单独生成报告第一个问题最常见。很多人拿到模型评审结果时会发现它写了一大堆风格建议关键逻辑问题反而一个没提。原因通常是 prompt 里没有告诉模型这个团队已经有 linter 和 code style 规范不需要你重复模型就默认要全面检查。解决方式是把范围收得很窄。第二个问题也很典型。模型很可能编造一个看起来很有道理的 API 建议。出现这种情况时不要直接追问第二次让模型再想想那样通常会得到同样自信的错误答案。正确做法是给模型明确约束没有在给定 diff 或代码索引里出现过的 API一律不要推荐或者在输出中标注不确定。第三个问题容易被忽视。如果模型服务默认的采样参数比较高同一个 PR 每次跑的结论会完全不同。代码评审需要一个可复现的基线所以评审场景里的 temperature 应该设得尽可能低同时锁定模型版本避免底层模型升级后输出风格漂移。第四个问题是管理问题而不是技术问题。如果团队现在出现开发者看到 AI 说 OK 就敢直接 merge的苗头说明流程需要尽快补上强制 approve 机制。8. LLM 代码评审的工程最佳实践接入 LLM 评审半年之后真正能让团队受益的往往不是模型调参技巧而是下面这几条工程原则。8.1 给 AI 设定边界而不是给它授权不管 AI 在评审中扮演什么角色它都不应该拥有 merge 权限甚至不应该拥有确认没有问题的最终发言权。比较稳妥的做法是AI 输出一份结构化的评审报告人负责解释和处置其中每一条必改项最后 approve 的人仍然对合并负责。这里有一个容易踩坑的设计像 CI 一样要求AI 评审通过才能 merge。这会让模型成为一个无人负责的守门员。如果它出现幻觉给出一个覆盖关键风险的错误判断团队会莫名其妙地在最后一道防线失守。更合适的设计是把 AI 当作默认的 reviewer 之一它参与评审但不独占评审。8.2 上下文质量是评审质量的上限同样的模型给它只给一个裸 diff和给它需求背景 影响范围 历史相关 PR 摘要输出质量完全是两回事。建议在仓库里维护一份review-context.md由 PR 作者在创建 PR 时花 30 秒钟更新目标、影响面和关键取舍。AI 评审时自动把这份文件拼进 prompt。没有上下文时模型只能做代码形态层的检查有了上下文才有了做业务意图层检查的可能。对 LLM 评审来说prompt 里多一段需求描述收益远比调整模型参数来得大。8.3 安全边界和最小权限用 LLM 评审的团队必须正视代码外发问题。企业仓库的代码本身就是敏感资产把整库 diff 发给外部模型服务之前至少要确认三点业务数据是否包含个人隐私或客户敏感字段源代码保密协议是否禁止外发模型服务所在地域和数据处理条款是否符合合规要求。安全性上核心硬性要求是任何文件名、密钥、内网地址、个人身份信息都不能出现在 prompt 中。最稳妥的方案是把模型服务部署在内网或私有化环境只让它访问与当前 PR 相关的代码切片而不是拥有整个仓库的读取权限。CI 里使用的 token 也要遵循最小权限只给当前仓库且尽量只读。8.4 用评测集持续测量前面提到过评测集。这里再强调一次LLM 评审不是接上就能用的服务而是一个需要持续校准的系统。团队可以每两周从真实合并记录中抽几个有代表性的 PR 作为回放样本让模型重新评审人工对比模型是否发现当时真实出现的问题。每次修改 prompt、调整模型版本或改变 diff 切片长度之后都要在评测集上跑一遍。这个习惯可以防止一种隐蔽退化你以为 AI 在变好实际上只是因为最近 PR 变简单了。8.5 保留必要的人工讨论和知识沉淀如果流程最终变成AI 输出意见 - 作者照着改 - 再生成一点意见 - 循环到 AI 满意那团队就丢掉了一个关键环节为什么这个设计和那个设计之间的取舍是当前最优解。让人工评审回归到它最擅长的工作上被写下来的知识会更准确reviewer 可以在 PR 评论里解释这里为什么不用缓存或这个抽象为什么不值得做这些讨论是模型无法替代的也是未来新成员进团队时最宝贵的资料。知识传递不能只依赖 AI 生成的摘要。9. 结论与后续学习方向代码评审在 LLM 时代不会消失但它的形态确实在发生变化。过去评审是人对代码逐行负责的过程现在它正在变成AI 预筛低层问题、人聚焦意图判断和架构决策的层次化流程。对这个变化最准确的理解不是AI 取代了 reviewer而是人的注意力被向上推动了。对团队而言接入 LLM 评审的核心动作不是部署一个 BOT而是重新设计流程让模型在低层检查中发挥作用让人在需要判断的地方保持权威。哪一层出了问题流程就会出问题。AI 的误报会消耗信任人的怠惰会制造盲区两者都会让评审体系变差所以评测集、上下文注入和安全边界必须从一开始就设计进去。这个方向上值得继续深入的内容不少。比较前沿的一类是多智能体评审让不同模型分别关注安全性、性能和架构一致性而不是一个模型做全量检查。另一类是让评审意见带上更强的证据链直接引用具体文件和行号减少幻觉引用。还有一类是仓库级上下文评审模型不再只看一个 diff而是结合代码历史、相关 issue 和上一次重构的讨论来做建议。这三条都会进一步推动评审流程的变化。最后说一句实在的把 LLM 当成团队里那位需要你不断补充上下文、只能看到局部、偶尔会自信地说错话的实习评审员来用坚持 human approve 的底线它就能把 code review 里最痛苦的那部分解放出来。坚持这个原则的前提始终是对谁为这行代码负责这个问题保持清醒。