AI 代码审查如何降本 68%:缓存复用与调用优化

Cloudflare AI Bl7 天前

AI 代码审查的成本上涨,不一定是架构发生了大变化,也可能是模型选择、上下文长度和调用次数共同累积的结果。

这个案例中,系统依旧采用“协调器分配任务、多个专项审查器执行”的架构,但单次审查成本从 4 月的约 1.19 美元,升至 8 月底的约 2.46 美元。

经过一轮优化,在代码质量审查保持高推理强度的配置下,单次平均成本降至 0.77 美元,相较优化前成本最高的两周平均值 2.43 美元,下降约 68%。审查耗时中位数也从 4 分 09 秒缩短到 1 分 32 秒。

一、缓存命中率很高,为什么账单仍在上涨?

系统的缓存命中率从 4 月的 85.7% 提升到了 9 月的 97%,但每次审查处理的 token 总量也从 91 万增加到 299 万。

命中率提高,并不能抵消上下文规模大幅增长带来的成本。 即使缓存读取便宜,反复读取巨量上下文仍会产生可观开销。

优化开始前,推理费用大致分为:

  • 输出 token:23%;
  • 缓存写入:43%;
  • 缓存读取:34%。

以代码质量审查器为例,每次审查平均调用模型 16.6 次,累计写入缓存约 7.2 万 token、读取约 108 万 token。由于每轮调用都会携带对话上下文,调用次数与上下文长度会共同推高成本。

因此,团队把重点放在两件事上:让首次请求也能复用缓存,以及减少每次审查的调用轮数。

二、修正缓存边界,让不同仓库共享固定前缀

每个审查会话都有约 1.1 万至 2.1 万 token 的通用工具定义和代理提示词,按理说应当很容易复用。但实际测量发现,会话首次请求的缓存命中率只有 14%—26%。

问题出在系统提示词的拼接方式:

  1. 先放入通用代理提示词;
  2. 再追加工作目录、日期等环境信息;
  3. 仅在整个块的末尾设置缓存断点。

这样一来,通用部分没有被单独缓存。不同仓库的环境信息不同,也就无法共享这个前缀。

修复方法是把通用提示词与环境信息拆开,在通用部分末尾单独设置缓存断点,并确保其前面没有仓库特定内容,工具描述在不同任务间也保持一致。

这里的关键是:不仅要有相同内容,还要让相同内容处于可独立复用的前缀边界内。

与此同时,团队把内部规范审查器反复读取的参考索引直接放进提示词,省去了开头读取这些文件的工具调用。该审查器每次运行的模型调用次数从 15.9 次降至 9.6 次,成本从 1.12 美元降至 0.72 美元。

这两项调整上线后,整体单次审查成本从 2.47 美元降至 2.02 美元。

三、减少无效调用,比压缩提示词更直接

接下来的优化并不复杂,但覆盖了多个容易被忽视的浪费点:

优化措施 发现的问题 调整方式或效果
隐藏无权使用的工具 子审查器会尝试发布最终评论,被服务端拒绝后再花一轮调用恢复 移除工具,避免无效调用,并减少约 2900 token 的工具定义
并行读取文件 代码质量审查器 64% 的轮次只调用一个工具,通常只读取一个文件 在首次响应中批量读取共享上下文和补丁,读取量上限为 150 KB
跳过无变化的专项复审 约三分之二的任务是同一合并请求的第二次或后续审查 对没有新增相关内容的专项审查直接跳过
发布评论后立即结束 评论发布成功后,模型还会读取完整对话,生成无人查看的总结 每个任务节省约 0.07 美元
区分超时与服务故障 审查超时被当成服务故障,以相同限制重新执行 配合延长时限、降低推理强度,安全审查超时率从 1.8% 降至接近零
真正停止已取消任务 抽查的 446 个已取消任务中,358 个仍运行到审查结束 每 15 秒检查任务状态,取消后停止运行

这些调整合计使每次审查成本进一步下降约 0.20 美元。

四、多个审查器也能共享同一份上下文

代码质量、安全和性能审查器需要查看相同的合并请求与补丁。团队因此把它们的首次请求整理成统一结构:

  • 相同的工具定义;
  • 共享规则文件;
  • 包含全部补丁的合并请求内容;
  • 最后再追加各自的专项指令。

这样,三个审查器便能共享前面的缓存内容。

但缓存写入存在时序约束:写入请求开始流式返回后,其他请求才能读取这份缓存。因此,第二、第三个审查器会等待第一个开始返回,最长等待 20 秒。

这会增加少量启动延迟,但另外两个审查器每个可节省约 0.09 美元。

五、工程优化之外,还要评估模型和推理强度

按团队的估算,约四成节省来自代码与流程优化,其余来自模型及推理强度调整。

例如,同一模型下,采用中等推理强度的完整审查任务完成时间缩短了约 20%。部分对比中,更高推理强度增加了费用,却没有带来有意义的发现数量提升。

不过,这些数据需要谨慎理解:团队明确指出,按每次发布和配置变化前后的工作时段进行比较,并不构成严格的受控实验。不同优化之间的收益也不宜直接视为可独立相加的因果效果。

对多代理系统的启示

这次实践更值得复用的是排查顺序,而非某个具体模型配置:

  1. 拆开看账单:区分输出、缓存写入和缓存读取费用。
  2. 单独检查首轮请求:总体缓存命中率可能掩盖首次请求的浪费。
  3. 检查缓存边界:通用内容与动态内容应分开组织。
  4. 追踪每轮调用的用途:优先清除权限错误、重复读取和无用收尾。
  5. 检查任务生命周期:已取消、已完成的任务,不应继续消耗推理资源。
  6. 用评估决定模型配置:更贵的模型或更高推理强度,并不自动意味着更有价值的审查结果。
评论

请登录后发表观点

暂无数据