导语:agentic 服务的成本大头不在模型单价,而在缓存与调用编排;这篇给出了可复制的降本路径。
Cloudflare 的 AI 代码评审单次成本,从 4 月时的 1.19 美元一路涨到 8 月底的约 2.46 美元。9 月中旬起,团队让自己的智能体去查 token 都花在哪、并大幅削减。如今在代码质量高 effort 模式下,单次评审平均只要 0.77 美元,较启动优化前最贵两周的均值 2.43 美元下降 68%;中位耗时从 4 分 09 秒降至 1 分 32 秒。节省中约 40% 来自评审器代码与工程改动,其余来自模型与 effort 的实验调整。最大的单项节省,来自让每次会话的首个请求命中缓存前缀。
我们上次在 4 月写博客介绍 AI 代码评审时,一次评审的平均成本还是可以接受的 1.19 美元。到 8 月底,这个数字飙到了约 2.46 美元。我们并没有做重大架构调整:协调器仍然把工作分派给同一批专项评审器,同样的风险分级决定评审强度。
9 月中旬前后,我们让自家智能体去搞清楚这些 token 都去了哪里,并激进地削减。在代码质量高 effort 下,现在一次评审平均只要 0.77 美元,比我们动手前最贵的两周均值 2.43 美元下降了 68%。我们的主要目标是降本,但在这个过程中也顺带优化了评审器本身——现在中位评审只要 1 分 32 秒,而此前是 4 分 09 秒。
节省中约 40% 来自评审器代码的改动与优化,其余来自对"用哪些模型、让它们投入多少 effort"的实验。
一次评审的成本是怎么翻倍的
下图显示了自 3 月以来每个工作日一次评审的平均成本。图中固定了评审层级的构成,因此某天大评审偏多不会扭曲数据。
单次评审成本稳步上升:1.22 美元(3 月)→ 1.44 美元(6 月)→ 1.74 美元(7 月),最后到 2.32 美元(8 月)。其中一小部分原因是更多评审落进了最贵的层级(3 月为 59%,8 月升至 65%)。我们相信原因很简单:模型正在变得更强、更能干。自然地,工程师提交的改动更大、更复杂,于是更多改动落入我们的"完整评审"层级。不过我们发现,成本上涨的大部分其实来自这几个月里的模型变更。
8 月初,我们把所有评审器迁到 Anthropic 模型,单次任务成本从 1.38 美元抬到 2.03 美元。之所以这么选,是因为在我们的评测中,Anthropic 模型在这个特定工作负载上表现优于其他模型。
我们的内部规范评审器 Codex,因性能与可靠性取舍最终落在 Claude Opus 4.7 上,单次评审成本从约 0.25 美元涨到 8 月的 0.88 美元,比协调器智能体本身还贵。
缓存命中率也在上升,从 4 月的 85.7% 升到 9 月的 97%;但每次评审的 token 数翻了三倍多,从 91 万涨到 299 万。即便缓存读取单价很低,在三倍 token 上保持高命中率,花费依然高得多。
自上次发文以来还变了什么?
最大的变化之一是评审器现在跑在 OpenCode v2 上,这是对 v1 的彻底重写。在把所有评审从 v1 切到 v2 之前,我们在每个 canary 仓库里用 v1 和 v2 同时跑了一遍对比影子测试。两者在我们测试的合并请求中,批准决策的一致率达 98%,于是我们在 10 月初一次性全部切换并删掉了 v1 代码。在相同模型下比较两天的数据,v2 上的完整层级评审快约 13%。我们还在试验其他运行内部 AI 评审器的方式,包括纯粹跑在 Durable Objects 上(借助 pi-durable)。希望能很快分享更多进展,敬请关注。
那么,token 都去哪了?
就在我们开始专注成本优化之前,AI 评审的支出结构是:输出 token 约占 23%,缓存写入占 43%,缓存读取占 34%。这意味着大部分钱花在了模型已经看过、或马上又要再看一遍的上下文上。
放到单次会话里看就完全说得通了。代码质量评审器平均每次评审发起 16.6 次大模型调用,在这些调用中向缓存写入 7.2 万 token、读回 108 万 token,因为每次调用都会把整段对话作为上下文发出去。一次会话的成本同时随调用次数和上下文规模增长,而在过去几个月里,我们把这两项都慢慢抬了上去。
值得花几分钟读一下 Anthropic 的 prompt cache 是怎么工作的。它缓存的是提示中已由大模型计算过的部分,称为前缀(prefix),因为只对对话开头的消息生效,对中间或结尾无效。这意味着后续请求可以复用更早的前缀,直到对话中与已缓存内容不同的那一段为止。在我们的场景里,harness 工具、系统提示以及 AI 评审会话开头的消息极少变化,因此非常适合前缀缓存。前缀只有在缓存断点结束处才会被存储。写入缓存的成本是正常输入价的 1.25 倍,读取是 0.1 倍;一条缓存条目若无人读取,5 分钟后过期。
也就是说我们有两件事可做:让每次会话的首个请求从缓存读取而不是写入,以及让每次会话用更少的调用。
在所有仓库之间共享同一个缓存前缀
从 9 月 14 日起,评审器开始记录每个评审器首次大模型调用的 token 用量,以及首块 system block 按发给供应商的原样的哈希值。
数据显示,会话的首个请求命中缓存前缀的比例只有 14% 到 26%。而每次会话都以相同的工具定义和相同的智能体提示开头——这部分在我们评审的每个仓库里都完全相同,约 1.1 万到 2.1 万 token——因此几乎全部本该命中缓存。
问题出在 OpenCode v1 构造系统提示的方式:它把我们的智能体提示、以及一段包含工作目录与日期的环境信息拼成一个 block,并且只在这个 block 的末尾放了唯一的缓存断点。共享的那部分从来没有单独存过,于是一个仓库里的评审永远无法复用另一个仓库评审已写入的内容。
9 月 16 日,我们在每个智能体提示的末尾加了一个标记,并用一个插件钩子在该标记处把 block 一分为二。前半部分现在以所有任务共享的字节结尾,并获得了自己的断点。为保持这一点,我们不得不把它前面的任何仓库专属内容都移走——可用技能列表被禁用,工具描述也不能在任务之间变化。
同一天,我们还把内部规范(Codex)评审器的参考索引(一张内部规范表、一个技能文件和一份参考文件清单)直接放进了它的提示里。此前每次会话都要花前三轮用工具调用去读这些文件。它每轮的调用次数从 15.9 降到 9.6,每轮成本从 1.12 美元降到 0.72 美元。
这些改动合计把单次评审成本从 2.47 美元降到 2.02 美元,而且发布一上线,下降就立刻看得见。
更少的调用,更少的钱
下一批改动在 9 月 21 日和 23 日上线。它们单独看都不算亮眼,但合起来把每次评审的成本又削掉了约 0.20 美元。
改动 / 此前发生了什么 / 改动效果:
移除评审器用不了的工具:子评审器能看到"发布最终评审评论"那个工具。在 57% 到 76% 的会话中它们会尝试调用,被服务端校验拒绝,然后再花一次调用恢复。效果:省掉一次无效调用,且每个子评审器请求里少了约 2900 token 的工具定义。
并行读取文件:在代码质量评审器 64% 的回合里,模型只发起一次工具调用,通常是读单个文件。效果:评审器在首次响应中就读取共享上下文和全部补丁,上限 150 KB。
在重复评审时跳过部分评审器:我们约三分之二的任务是对同一合并请求的第二次或更晚的评审,常常有三个评审器没有新内容可看。效果:在完整层级的重复评审中,AGENTS.md 评审被跳过 56%,性能评审跳过 23%,文档评审跳过 13%。
评审发布后即停止:OpenCode 会把结果回传给模型再跑一轮,让它重读整段对话去写一个没人看的摘要。效果:每个任务约省 0.07 美元。
把"慢的评审器"和"坏掉的供应商"区别对待:评审器撞上自身时限时,此前被当成供应商故障、并以同样的时限重新开始。效果:配合更长的时限和更低的 effort,安全评审器超时率从 1.8% 降到几乎为零。
取消已取消的任务:GitLab 的 Kubernetes executor 在任务被取消时不会给任务脚本发信号。在 446 个被取消任务的样本中,有 358 个一直跑到评审结束。效果:任务每 15 秒自查一次状态,若已取消就停止。
最复杂的一项改动,是让三个评审器共享一个前缀。代码质量、安全与性能评审器现在发出完全相同的首个请求:同样的工具、同一份共享规则文件,然后是包含全部补丁的合并请求;各自的指令放在这之后。我们确保其中一个写入缓存、另外两个从缓存读取。
一条缓存条目在写入它的响应开始流式返回之后才能被读取,而三个评审器是同时启动的。于是第二、第三个会等第一个的响应开始(最多 20 秒)再发自己的首个请求。这略微拖慢了它们,但每个评审器约省 9 美分。
更换模型与 effort
下图是 9 月至今的同一条曲线,并标出了每次改动。
当我们按每次发布与配置变更切分这段时期时,会发现代码改动带来的节省反而是较小的一部分。
在 1.67 美元的总降幅中,代码改动贡献 0.65 美元,模型与 effort 调整贡献 1.06 美元。每一步都是拿变更前后的工作日时段做对比,因此这不是一次统计上严谨的对照实验。
协调器自 8 月起同时跑着三种模型与 effort 组合。在同一模型下,完整层级任务在 medium effort 下完成时间快 20%,于是我们砍掉了另外两种。在后一次随机分流中,Opus 5.5 在 medium 下相较 Opus 5,在评审结果与关键发现数量上没有可测量的差异,于是我们切换了。Opus 5.5 在 high effort 下比 medium 更贵,却没有带来有意义的发现增长。
Opus 5.5 每 token 比 Opus 5 便宜,但价格只贡献了降幅中的约 0.20 美元,其余来自发送与生成更少的 token。自 9 月初以来,每次评审的缓存读取下降 82%、缓存写入下降 54%、输出下降 67%。
最近一次变更是换模型。10 月 3 日,我们把每个 Sonnet 评审器按 50/50 分流到 Sonnet 5 与 Sonnet 5.5。两天半之后,Sonnet 5.5 在代码质量场景每轮便宜 62%、性能 58%、安全 47%。两个模型每 token 单价相同,因此节省全部来自用了更少的 token。在完整层级评审中,5.5 发布的 critical 与 warning 级发现数量与 Sonnet 5 大致相当,于是 10 月 5 日我们全部迁到了 5.5。
在 Sonnet 5.5 的 medium effort 下,代码质量评审器每轮只发 1.7 次大模型调用(此前为 6.2 次),超过一半的轮次一次调用就完成——意味着它没有打开仓库里的任何其他文件。在 high effort 下每轮 3.4 次调用。我们曾担心这会让评审变浅,这一点在下面的质量章节里有交代。
为了验证更大的层级上提高 effort 能否把发现找回来,自 10 月 5 日起,代码质量评审器在 5.5 上按 medium 与 high effort 做了 50/50 分流。一天之后,high effort 每轮贵 61%,但多发布 58% 的 critical 与 warning 级发现。折算下来每次评审约多花两美分,而下面的质量章节显示这些额外发现是值得的,所以我们正把代码质量迁到 high effort。本文中的成本数字已按此计算。
延迟
我们本没打算让评审变快,但更少的调用也意味着更少的等待,也就是更快的评审和更开心的工程师。
最慢的那些评审改善最大。在 9 月 14 日前的四周里,37.9% 的评审耗时超过 5 分钟,现在只有 0.7%。今天的 99 分位,比 4 月时四分之三的评审还要快。各个层级都在变快:完整层级中位从 5 分 16 秒降到 1 分 54 秒,lite 从 2 分 58 秒降到 1 分 14 秒,trivial 从 77 秒降到 30 秒。
到 8 月时,中位评审比我们 4 月报告的数字慢了 14%,99 分位慢了 48%,所以这部分工作有相当一部分只是让我们回到了原来的水平。
评审质量
如果更便宜的评审同时找到的问题也更少,那就不值了——而这里的第一张图看起来正是这样。
在代码质量跑 Sonnet 5.5 high effort 后,它发布的 critical 与 warning 级发现比 8 月下旬少了 40%。保持在 medium effort 的安全与性能评审器,分别少了 56% 和 71%。严重发现数量的下降本身并不能说明是漏掉了真问题,还是砍掉了噪声,所以我们从两个方向看了它。
第一,我们检查作者是否真的对评审器标记的内容采取了行动。对 critical 与 warning 级发现的样本,我们对比被评审的提交与作者的下一次推送,若发现所指向的代码行发生了变化,就计为"已采取行动"。距离发现 30 到 40 行的代码行在各时期约有 15% 的概率发生变化,这为"碰巧发生的编辑"提供了基线。
改动前,作者对代码质量评审器 34% 的严重发现采取了行动;现在是 59%。评审器标记的东西更少了,但被标记的更可能促成改动,因此每 1000 次评审中促成改动的发现数大致持平:现在是 132,此前是 145,落在误差范围内。四个评审器合计,促成改动的严重发现从每 1000 次评审 229 条升至 321 条。
第二,我们让两个来自不同供应商的模型,对三个 Sonnet 评审器的 657 条发现做盲评,每条附带其所指的 diff,且不知道来自哪个时期。分歧交给第三个模型裁决。每条发现被标注为重要、次要、重复、错误或无法验证,其严重度则被标为公允、过高或过低。
消失的大部分是次要发现,加上一些重复项和评审依据 diff 无法验证的发现。每条评审的重要发现数从改动前的 0.28 变为现在的 0.30,置信区间重叠。更大的变化在严重度上:改动前,评审依据把每评审 0.46 条 critical 或 warning 级发现评为"比其应得的更严重";现在是 0.14,下降 70%,这是本次研究中最清晰的结果。critical 发现的下降,很大一部分是评审器不再把次要问题叫成 critical。
所以答案取决于评审器。对 high effort 下的代码质量来说,消失的主要是噪声和被抬高的严重度,它找到的真问题和以前差不多。medium effort 确实丢了真发现:在随机分流中,medium 下代码质量促成改动的发现约为 high 下的四分之一,这正是我们要把它迁到 high 的原因。性能也丢了真发现:评审依据发现每评审重要性能问题减少约 64%,实际相当于每 24 次完整层级评审少约 1 条重要发现。安全下降约四分之一,但不具统计显著性。两者目前仍在 medium effort,下一步就是在 high 上测试。
两种方法都不完美。作者改动被标记的代码行,说明他做了些什么,不说明那条发现是对的。评审依据本身也是模型,每组只有 35 到 66 条发现。"现在"这个窗口也只有一天长。即便如此,两种方法相互印证,且都不支持"代码质量找到的真问题变少了"这一结论。
可靠性也保持住了。没有得出结论就结束的评审从 0.79% 降到 0.27%,安全评审器的重试从 3.5% 降到 0.04%。
我们走到了哪里
现在一次评审平均成本是 0.77 美元而不是 2.43 美元,中位耗时是 1 分 32 秒而不是 4 分 09 秒。最大的单项节省,来自检查每次会话首个请求到底把什么发给了供应商,并找到一种让这些消息在提交、合并请求与仓库之间尽可能一致地排序的办法。其余的成本节省,来自不懈地试验不同模型与 effort 组合,同时确保把对某些模型的先入偏好放到一边。
更便宜的评审并不自动等于更差的质量,但也不自动等于没问题。high effort 下的代码质量找到的真问题和以前差不多,噪声更少、被抬高的严重度大幅减少。medium effort 下的性能丢了真发现,安全可能也是,所以下一步是在 high effort 下测试这两者。如果你在任何规模上运行智能体,我们建议先查两件事:每次会话的首个请求是否真的从缓存读取;以及在你付费的那个 effort 水平上,评审器是否仍然能找到真问题。
如果你在旧金山的 Cloudflare Connect 现场,我会在我的专场"是时候自己造,而不是买"(It's time to build, not buy)里讲我们如何自研而不是采购这套评审器,时间是 10 月 20 日(周二)太平洋时间中午 12:30。1:10 PM 起我也会在 Speaker Connection Lounge,欢迎来问本文里任何数字。

扫一扫,或长按识别二维码
关注艾瑞网官方微信公众号