Token 成本的三个杠杆
大模型账单有个反直觉的地方:它和请求量不成正比。同一个接口、同样的调用次数,上下文组织方式不同,账单能差出好几倍。
原因是计费按 token 算,而 token 的消耗集中在三个可以动手的地方。这篇讲这三个杠杆,以及一个最容易算错账的陷阱。
1. 杠杆一:输出比输入贵得多
各家定价的共同形态是:输出单价显著高于输入单价(常见是数倍)。
这条决定了优化方向的优先级——先砍输出,再砍输入。
具体做法:
- 明确要求输出长度上限,并在提示词里给出预期篇幅
- 不要让模型复述上下文里已有的内容("请先总结一下你看到的内容再回答"这类指令,等于把输入又买了一遍输出价)
- 结构化输出比自由文本省:要它输出 5 个字段的 JSON,比要它写一段包含这 5 个信息的散文便宜
2. 杠杆二:缓存
各家都提供了 prompt caching:把一段前缀内容缓存起来,后续请求命中就按远低于输入的单价计费。
以 Anthropic 的定价结构为例(5 分钟 TTL):缓存写入约为基础输入价的 1.25 倍,缓存读取约为 0.1 倍。也就是说,一段被反复使用的前缀,第二次开始的边际成本降到十分之一。
要让缓存真的命中,有四条必须知道:
2.1 有最小长度门槛,且各家机制不同
不是什么都能缓存。Anthropic 是显式标记:在请求里打断点,最小可缓存长度要逐模型查表——512 / 1024 / 2048 / 4096 并存,和模型大小、新旧都没有单调关系(最新的两代旗舰门槛低到 512,而 Haiku 4.5 反而是 4096),以官方表格为准。低于门槛时静默不缓存、不报错,只能靠响应里的 cache_creation_input_tokens 和 cache_read_input_tokens 是否都为 0 判断。
OpenAI 的机制按代际分开:GPT-5.6 之前是自动的——不用标记,前缀超过约 1024 token 就按 128 token 的粒度尝试匹配最长公共前缀;GPT-5.6 及以后改成了和 Anthropic 类似的显式断点 + prompt_cache_key,1024 仍是硬下限,且缓存写入要另付 1.25 倍。接的是哪一代模型,直接决定你要不要写断点代码。老机制的代价是命中率不完全由你控制——请求会被路由到不同机器,前缀缓存跟着机器走。想提高命中率,要让同类请求尽量稳定落到同一处(保持请求形态稳定、避免频繁改工具定义)。
Gemini 的隐式缓存门槛随代际变化(2.5 系约 2048,3.x / 4 代是 4096),另提供显式的 context caching 可以自己建缓存对象——但它在 Gemini 4 及之后的模型、以及 Interactions API 上已不支持,用不用得上要看具体模型,别默认有。
一句话:Anthropic 靠"你标得对",OpenAI 靠"前缀够稳"。两家的优化手法不一样,别把一套经验直接搬过去。
2.2 断点必须放在"稳定前缀"的末尾
缓存是对从开头到断点为止的这段内容做的哈希。如果断点放在每次都变的内容上(时间戳、用户输入、随机 ID),那每次都是一次新的写入,永远命中不了。
正确的做法是把内容按稳定性排序:最稳定的放最前(系统指令、工具定义、长文档),易变的放最后(用户当前这句话)。
会破坏缓存的操作也要知道:修改工具设置、改动是否包含图片,都会让缓存失效。
2.3 TTL 与并发可见性
缓存生命周期默认是 5 分钟,每次命中会刷新。所以真正要关心的是"两次调用之间的间隔",而不是"一次调用有多慢"。如果两轮对话间隔经常超过 5 分钟,可以选 1 小时 TTL(写入单价更高,用命中率回本)。
还有一个容易忽略的约束:并发的请求要等第一个响应开始之后,才能看到刚写入的缓存。冷启动时同时打进来十个请求,前几个都会各自写一遍,谁也命中不了谁。所以"预热"这件事是有意义的——在流量高峰前先发一次稳定的长前缀请求。
另外,"读取约 0.1 倍"只是常见档位。不同模型、不同缓存时长档位的折扣并不一样(有的档位低到 0.025),算成本时以定价页为准,别拿一个系数套所有模型。
断点该打在哪、哪些动作会让缓存整段失效、命中率怎么归因,单独展开在《提示缓存怎么才命中》里——那一篇讲的都是"排布",不是配置。
prompt caching 是供应商侧的缓存,命中后仍然要生成。还有一层应用侧的语义缓存——命中后连模型都不调用,代价是可能拿错答案,阈值和适用边界见《语义缓存的命中边界》。
3. 杠杆三:上下文预算
上下文长度乘以单价,再乘以轮数——多轮对话的成本是复利增长,因为每一轮都要把之前所有内容重新送一遍。
这跟《上下文是有限预算》里讲的是同一件事的两面:那边讲的是"模型看不过来",这里讲的是"每一轮都在重复付费"。
对应的做法:
- 该压缩就压缩,别让历史无限增长
- 检索内容控制条数(《重排修不了召回》里给过保留 5 到 10 条的常见配置)
- 工具结果清理:很早之前的工具返回,对当前步骤没用却一直占着预算
4. 杠杆四:批量接口
前面三个杠杆都在"单次调用"里省。还有一个杠杆在调用方式上:把能等的活攒起来,走批量接口。
主流厂商的批量接口(OpenAI Batch、Anthropic Message Batches、Gemini Batch)通常给五折,代价是异步——提交一个 job,几小时到 24 小时内出结果,SLA 按"最长完成时间"算。它适合的场景很明确:
- 离线打标、批量翻译、批量摘要、评测集回归
- 知识库入库时的抽取与改写
- 日志的事后归类、工单的批量分类
不适合的都一样:用户在等结果的路径。判断标准只有一条——这个结果晚六小时出来,业务能不能接受。
工程上要注意三点:job 有生命周期(提交 → 处理中 → 过期),结果要按自定义 id 对回去(别依赖顺序),失败项要能单独重提。很多团队的成本问题不是单价高,而是该走批量的活走了实时。
5. 一个最容易算错账的陷阱
开了缓存之后,input_tokens 这个字段的含义变了。
以 Anthropic 为例,实际输入量是三段之和:
总输入 = cache_read_input_tokens + cache_creation_input_tokens + input_tokens
其中 input_tokens 只表示最后一个缓存断点之后、未被缓存的那部分。如果缓存了一篇长文档,那么 input_tokens 可能只有几十——它不再是"总输入"。
直接用 input_tokens 去算成本的看板,在开启缓存的那一刻就会开始低估,而且低估幅度会越来越大。正确做法是三段加起来算,并且把缓存读写分开统计(这样才能看出缓存策略到底有没有生效)。
6. 怎么建成本可见性
埋点的最小集(详见《给大模型链路装仪表》):每次调用记模型名、输入/输出 token、缓存读/写 token、所属用户或租户。
有了这些之后,成本看板应该回答三个问题,而不只是显示一个总额:
每个用户/租户花了多少。 这是做配额和定价的基础,也是发现异常调用的第一步。
每个功能花了多少。 同一个产品里,问答、摘要、改写三类功能的单均成本可能差一个数量级。不拆开看,就不知道该优化哪一个。
单位成本趋势。 总成本涨了可能是业务量涨了,也可能是某次改动让上下文变长了。看"每次成功任务的成本"比看总额有用得多——这也呼应《RAG 评测指标怎么选》里的思路:绝对值会漂移,相对变化才反映改动本身的影响。
7. 三条能立刻做的
- 把系统指令和工具定义整理成稳定前缀,把易变内容挪到后面(这是缓存生效的前提)
- 成本看板改成按三段 token 求和,并把缓存命中率单独放一个指标
- 给输出加长度约束——这是单价最高、也最容易被忽略的那一块
这三条降的是总量。等总量稳住之后,下一个问题通常是"到底是哪一行功能花掉的"——把总账拆到租户、功能和单次任务,以及超预算之后系统该怎么拦,见《成本归因与预算熔断》。