自研代码审查机器人把 PR 合并时间砍掉一半一次工程复盘原文Vapi Blog《How an in-house review bot cut our PR merge time in half》https://vapi.ai/blog/ai-code-review-bot起点是一个以「天」计的评审队列Lat Ware 开始做 Pedantic Review Bot 的时候Vapi 的一个 PR 从打开到合并平均要 130 多小时也就是五天以上。Vapi 已经为两个 AI 评审工具付了钱但在他们自己的代码库上这两个工具都没抓到 Lat 早期提示词抓到的问题。关键不在「自研更聪明」而在于自研把两件事放到一起权衡一次评审的成本和它发现的问题。用他的话说他当时是在和以「天」计的评审时间竞争所以可以允许机器人一次评审花 20 分钟——商业产品做不到这一点。机器人现在审查 Vapi 工程师开的每一个 PR平均合并时间降了一半到 65 小时。一次评审是怎么跑的PR 打开即触发草稿也算作者可以主动 机器人再跑一遍。已经审过的 commit 会被跳过重复事件不会触发第二次付费评审。每条行内发现以一句加粗总结开头带一个严重度标记从绿色吹毛求疵到红色阻塞合并。第二个机器人 Pedantic Architecture Review Bot 专门找设计问题它是在一个设计缺陷漏过原版机器人之后建的。那个缺陷的特征是单看任何一行代码都看不出来的设计问题。架构机器人用的提示词几乎一样只是把「可能的问题」换成「可能的高层设计模式问题」并且需要更高的推理强度。它写报告只有和具体位置绑定的发现才留行内评论。它还有一个复杂度过滤器2026 年 9 月 2 日到 10 月 2 日之间763 次架构工作流运行只产出了 33 份报告。踩坑一第一版话太多第一版留下的评论多到 Lat 把它命名为 Pedantic。其中很多针对的是这个 PR 本来就碰到的、早就存在的问题。团队的说法是它的评论读起来像草率的 AI 输出而且他们说得有道理。他反复改提示词让评论更短、更容易照着做。抱怨随着工程师开始细读评论、并发现发现本身是准确的而慢慢消失。修掉「正在改动的代码里既有的问题」也就成了团队维护工作的一部分——既然不可能一次修完机器人就把这类工作限制在当前正在改的代码上。踩坑二让机器人先证明自己的结论机器人不会在没核实过的情况下提出异议。分析 job 会先检出这个 PR在报告一条发现之前智能体可以去追调用方、去跑它怀疑会失败的测试或者写一个小复现。这里有一个值得抄的架构决定分析与发评论是两个 job。分析会话被剥掉了 Git 凭据只把发现写进一个 JSON 文件第二个 job 校验这个文件并发出评论不执行智能体写下的任何东西。它能评论但不能批准、不能推送由工程师决定要处理哪些。// 示意分析 job 写下的发现文件字段为示意非官方格式{pr:4821,findings:[{file:src/router.ts,line:118,severity:blocker,summary:流量切换与发布比例的应用顺序反了,verified_by:trace_callers}]}一个月里它抓到了什么2026 年 9 月 2 日到 10 月 2 日机器人审了 1694 个 PR在 276 个里面提出了 363 条阻塞级发现。其中一半以上涉及构建、测试、CI 或部署其余涉及运行时行为和计费。有几条测试类的发现是绿色的 CI 勾根本盖不住的有一次改动把测试断言换成了测试运行器永远不会收集的 Storybook story。有一个 benchmark 声称成功实际上一个测试都没跑。在一个流量切换改动里架构机器人抓到两次写入的顺序错了后端先把流量切到新版本然后才应用「发布比例 0%」。在那个时间窗里一个本来不该有任何流量的发布吃到了全部流量。101 版提示词的实验以及一次被推翻的结论Lat 为这个机器人试过接近 200 条提示词。有一次被记录下来的实验是在同一个 PR 上测试 101 版开场指令其它一切保持不变——代码库上下文、diff、作用域规则、JSON 输出格式。101 次运行产出 803 条原始发现归并成 57 个不同的问题。一个 AI 裁判在不知道某个问题被多少次运行报过的情况下逐条判定32 个真、24 个假、1 个无法验证。没有任何一次运行找到超过 10 个真问题。报告一开始把更激进的那版提示词判为赢家。Lat 拒绝了这个结论因为计分没有充分惩罚假阳性——报得越多的提示词得分越高但每多报一条无论真假工程师都要多查一条。按他的本意把假阳性加权之后赢家变回原来那条极简提示词Please aggressively review [PR link] for possible problems. Post what you find as inline comments. Dont sacrifice on making the problem easy to solve. Give a one-sentence summary in bold at the top of each comment. Assign a severity rating from the range , with being nitpicks and being blockers.两个可迁移的结论关于「检查什么、怎么报告」的指令比「你是什么角色」的人设更有效把严重度符号原样写死能让输出格式更一致。多次便宜的运行胜过一次最贵的运行既然没有哪一次运行能找到全部问题Lat 就想知道固定预算该怎么花。他还在自己的代码库上比较了不同模型——理由是公开榜单测的是供应商挑的任务那些任务可能和他们的代码库长得很不一样。实验对象是一次真实重构它把一个终止保护从服务入口挪走了但仓库里的 lint 测试仍然要求这个保护留在入口所以这次改动会挂掉 lint 门禁。配置成本严重度加权得分代码评审3 次 extra-high 强度$12.32244合计代码评审1 次 maximum 强度$12.3035.5平均设计评审3 次 extra-high 强度$6.36668合计设计评审1 次 maximum 强度$11.2051平均两种比较里三次 extra-high 都胜过一次 maximum成本持平或更低。原因也合理每一次额外运行会重复更多前面已经找到的东西边际收益递减。而那个已知的阻塞问题非常难抓194 次代码评审运行里只有 8 次发现了那个 lint 失败195 次设计评审运行里只有 2 次。踩坑三什么算「在范围内」几个 GPT-6 配置在原文提示词下几乎什么都不报理由是父提交里已经存在的问题不在本次评审范围内。Lat 加了一句话Include errors already present in the parent.在代码评审实验里GPT-6 Astra 每轮的严重度加权分从 0.3 涨到 24.2。但这句话会过度纠正在设计实验里GPT-6.1 Sol 拿到的分全部来自既有问题没有一分和这个 PR 自己的设计有关。另外要注意其它模型没收到这句指令所以它们的分数不能和它直接比较。一条有用的发现应该说明问题是被这个 PR 引入的还是本来就存在。工程师可能两种都想修但需要这个区分来决定要不要合并。还没测到的部分以及六条可迁移经验作者自己把边界写得很清楚101 版实验里每条提示词只在一个 PR 上跑过一次判定还是 AI 做的模型对比也只用了一个 PR都需要在更多 PR 上重复才能推广。月度数据里有些架构报告是刻意对几个月前已合并的 PR 重跑不算「合并前抓到」。活动报告也还没跟踪工程师最终采纳或驳回了哪些发现。所以下面这六条比那些具体分数更值得带走你的评审队列决定了延迟预算。人在等几天机器人花几分钟就已经是改善。让评审者跑代码而不是只读代码。让「读不可信代码的智能体」远离「能发评论的那个 token」。把假阳性当成本算。Lat 的实验里正是这一条让极简提示词胜出。先试几次便宜的运行再决定要不要买那一次最贵的。明确告诉评审者既有问题算不算在范围内。最后是那个更普遍的方法与其相信公开榜单不如在自己的代码库上跑实验——用你自己的代码、你自己的成本口径去做 A/B。Lat 的原话是实验才是真相浮出来的地方。模型几个月就会换代他也打算在新模型出来后重跑这些实验但这些结论应该能活得更久一些。文中涉及的具体模型、工具与配置以官方文档为准未验证最新版本。
阅读完成 · 觉得有帮助?