2300 字
约 7 分钟
12
S22-A28 · Token 的账:为什么"同一个功能"两次报价差三倍

一个客服问答功能,上线前按"每次调用 1,800 token × 每天 2,000 次 × 单价"算出每月约 3,000 元。第一个月账单 9,200 元。查用量日志:日均调用次数对得上,但平均每次消耗的 token 是 4,900,不是 1,800。

三个偏差叠在一起:多轮对话让输入按轮次累积、每次回答比预估长、以及一批"超时重试"的调用没产出一分钱价值。所以"报价"与"账单"的差距从来不在单价,而在你没算进去的那些 token。


1. 一次调用其实有四项计价

项 计费方式 典型单价关系
输入(prompt) 按 token 1×
输出(completion) 按 token 3–4×
缓存写入 按 token(一次性) 1.25× 左右
缓存命中 按 token(折扣) 0.1× 左右

第二行是报价阶段最容易低估的:输出单价是输入的几倍。所以"回答变长一点"在成本上的影响,比"prompt 多几句话"大得多。

第四行则是省钱的唯一杠杆,但它有前提——前缀必须逐字节稳定(详见第 4 节)。

// 同一个功能的两种输出风格,成本差一倍
简洁模式:  输入 1,200 + 输出 200   → 1,200 × 1 + 200 × 3 = 1,800 单位
详细模式:  输入 1,200 + 输出 800   → 1,200 × 1 + 800 × 3 = 3,600 单位
// 输入没变,只因为"回答更长",成本翻倍

2. 多轮对话的成本是 O(N²),不是 O(N)

第 N 轮的输入包含前 N−1 轮的全部内容。所以 10 轮对话的总输入量 ≈ 1+2+…+10 = 55 个"单轮输入"。

轮次 本轮输入 累计输入(相对单轮)
1 1× 1×
3 3× 6×
5 5× 15×
10 10× 55×
20 20× 210×

第四行就是"客服功能"的账单来源:一次 10 轮的会话,成本是单次问答的 55 倍,而用户感知只是"聊了 10 句"。

// 两种会话策略的成本对比(10 轮,每轮新增 300 token)
全量携带:  输入总量 55 × 300 = 16,500 token
滑窗(3 轮): 输入总量 ≈ 10 × 900 = 9,000 token        ← 省 45%
摘要 + 滑窗:输入总量 ≈ 3,600 token + 摘要调用成本     ← 省 70%+
// 代价:滑窗会丢早期约束,摘要会丢细节 —— 这是产品决定,不是技术决定

3. 重试与取消:付了钱但没拿到东西

情况 成本 有无产出
正常完成 1× 有
超时后重试成功 2× 有(第一次白付)
超时后重试仍失败 2×+ 无
用户取消(服务端未停) 1× 无(生成仍在跑)
流式中断但后端跑完 1× 部分

第四行与 S21 的中断主题相关:断连不等于取消,服务端若没收到取消信号会把剩余 token 全部生成完——账单照付,用户早走了。

// 一次"重试放大"的真实形状
基础调用 4,000 token/次,失败率 12%,重试 2 次
有效成本 = 4,000 × (1 + 0.12 + 0.12×0.012) ≈ 4,485 token
// 看起来只多 12%,但如果失败原因是"超时"(每次跑满上下文),
// 实际放大约 20%–25%,而不是账单上看到的 12%

4. 缓存命中:省钱的唯一杠杆,也是最脆的

前缀缓存(prompt caching)只对完全相同的开头生效。任何一处不同——包括空格、时间戳、用户名的位置——都会让它从"命中"变成"未命中"。

前缀内容 是否稳定 命中
固定的 system prompt + 工具描述 稳定 ✅
每请求注入的当前时间 不稳定 ❌(整段失效)
用户信息放在 system 里 每用户不同 部分命中
动态内容放在末尾(user 消息) 稳定前缀 ✅

第二行是最常见的自毁动作:为了"让模型知道现在几点",在 system prompt 里拼了 当前时间:…,于是缓存永远不命中。正确做法是把可变内容放到末尾。

// 前缀设计的唯一原则:稳定的在前,易变的在后
[system: 角色 + 规则 + 工具 schema]  ← 永不变
[retrieved: 检索片段]                ← 每次变,但在末尾之后
[user: 问题 + 当前时间]              ← 最后
// 顺序一乱,前面的缓存全部作废

5. 归因:三个维度缺一不可

没有归因就没有优化方向。最小可用口径是三元组:

维度 回答什么 怎么打
功能 哪个功能在烧钱 调用入口打标
租户/用户 谁在用得多 请求头带 id
任务类型 哪类任务贵(问答 vs 摘要 vs 生成) 按 prompt 模板分类

归因的价值不只是报表——它同时是异常检测:某租户的平均轮次从 3 涨到 12,通常意味着产品侧改了交互,或者上游在死循环重试。而这类异常在总成本曲线上只是一个「缓慢上升的斜坡」,很难被单独发现。三者的组合还能直接指向动作:"某租户 + 摘要类 + 10 轮以上会话" 这个组合如果占了 40 % 成本,优化方向就明确了(限制轮次或改摘要策略),而不是笼统地"优化 prompt"。


6. 排错:五种"账单比预期高"

现象 八成原因 处理方向
平均 token 是预估的 2–3 倍 多轮累积 滑窗 / 摘要
缓存命中率接近 0 前缀里有动态内容 把可变内容挪到末尾
用量稳定但成本涨 输出变长(模板改了) 查输出 token 分布
某天成本翻倍 重试风暴 查超时与失败率
单租户占比异常 无配额 按租户限流

第二行值得单独强调:命中率 0 时,账单通常是"应该有 60 % 折扣却没拿到"的差额,而不是"忽然变贵"。所以它是"一直贵",只是没人对比过。

-- 一个可用的成本查询(按功能 × 任务类型聚合)
SELECT feature, task_type,
       COUNT(*) AS calls,
       SUM(input_tokens)  AS in_tok,
       SUM(output_tokens) AS out_tok,
       SUM(cache_hit_tokens) AS cached,
       ROUND(SUM(input_tokens + output_tokens * 3) / COUNT(*)) AS avg_unit
FROM llm_usage_log
WHERE dt = CURRENT_DATE - 1
GROUP BY feature, task_type
ORDER BY avg_unit DESC;
-- 判据:avg_unit 明显高于"单轮基准"的行,就是多轮累积的重灾区

7. 边界:什么时候不该优化 token

场景 为什么不必 说明
调用量很小 省下的钱 < 优化成本 先看总量
质量是硬约束(医疗/法务) 省钱会降质 不优化输入
已在预算内 无收益 只监控
延迟比成本重要 缓存可能增延迟 权衡
一次性任务 无长期成本 不管

判断口径一句话:成本优化的顺序是"先归因、再改策略、最后才抠 prompt"——因为大头永远在"多轮累积"与"输出变长",而不是"某句话写长了三个字"。而缓存是唯一"改一处、永久生效"的杠杆,前提是前缀稳定。


8. 自测

  1. 一次调用有哪四项计价?哪一项的单价通常是输入的几倍?为什么这会放大"回答变长"的影响?
  2. 多轮对话为什么是 O(N²)?10 轮相对单轮是多少倍?
  3. "超时重试"的实际放大比例为什么常高于失败率本身?
  4. 前缀缓存失效的最常见原因是什么?正确的前缀顺序应该怎么排?
  5. 成本归因的三个维度分别回答什么?为什么缺一个就无法定向优化?
  6. 成本优化的正确顺序是什么?什么情况下根本不该优化?

9. 一句话总结

Token 账单的偏差几乎从不在单价,而在"没算进去的那些":多轮累积是 O(N²)(10 轮 = 55 倍单轮)、输出单价是输入的 3–4 倍(回答变长比 prompt 变长更贵)、重试与未取消的生成是"付钱无产出"。唯一"改一处永久生效"的杠杆是前缀缓存,而它只对"稳定前缀"生效——把动态内容挪到末尾即可。判据:先归因(功能 × 租户 × 任务类型)、再改策略、最后才抠 prompt。

S22-A28 · Token 的账:为什么"同一个功能"两次报价差三倍
https://www.clxhxhhr.top/posts/6753/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。