
接大模型 API 之前,大部分人只看一眼单价,跑起来才发现账单比估算高出一截。问题通常不在单价,而在没搞清三件事:token 怎么数、上下文怎么计费、缓存怎么用。
这篇把这三件事讲清楚。**具体单价各家常变,以官方定价页为准**,这里讲的是结构,结构几年内不会变。
## token 不是字
模型处理文本的最小单位是 token,不是字符也不是词。经验值:
- 英文大约 1 个 token ≈ 4 个字符,或 ≈ 0.75 个单词;
- 中文通常 **1 个字 ≈ 1 到 2 个 token**(取决于分词器,这是中文比英文贵的主要原因)。
所以别用「字数 × 单价」估算,误差能到一倍。正确做法是**在代码里直接读 API 返回的 usage 字段**,那个才是计费依据。
## 输入和输出分开计价,输出贵得多
这是第二容易踩的坑。一次调用的费用是:
```
费用 = 输入 token × 输入单价 + 输出 token × 输出单价
```
输出单价通常是输入的 3 到 5 倍——因为生成是逐 token 的串行过程,占用算力的时间远长于一次性读入。
直接影响决策:
- 让模型「简要回答」不只是风格问题,是省钱;
- 要求输出 JSON 时,**键名也算输出 token**,能短则短;
- 长文档摘要比长文档问答贵。
## 真正的杀手:上下文是累计计费的
模型本身没有记忆。多轮对话之所以「记得」,是因为客户端每轮都把**完整历史重新发一遍**。
假设每轮新增 500 token,聊 20 轮:
```
第 1 轮发送: 500
第 2 轮发送: 1000
...
第 20 轮发送: 10000
总计输入: 约 10.5 万 token
```
**成本随轮次大致呈平方增长**,而用户感受只是「多聊了几句」。这就是为什么一个看起来很轻量的对话机器人,账单能翻着涨。
对应的办法:
- **滑动窗口**:只保留最近 N 轮;
- **历史摘要**:超过阈值就把前面的对话压缩成一段摘要再塞回去;
- **无状态设计**:能单轮解决的任务就不要维护会话。
## 缓存:前缀命中能省一大截
主流 API 都提供 prompt caching:如果本次请求的前缀与前一次一致,命中部分按折扣价计(通常便宜不少,具体倍数看各家文档)。
要让缓存真的命中,前提是**前缀必须逐字节相同**。实践中要注意:
- 系统提示词要放最前面,且**不要塞时间戳、随机数**进去;
- 工具定义、few-shot 样例这些固定内容放在前半部分;
- 变化的内容(用户输入、检索结果)放在最后。
顺序一乱,缓存就全失效。这一条的收益在长系统提示的场景下非常明显。
另外,对时效性不敏感的任务用 **Batch API**(异步批量)通常有对折优惠,适合离线批处理。
## 三条马上能做的
1. **记日志**:每次调用把 input/output token 打进日志,别等到账单出来才知道;
2. **设上限**:给每个用户/任务设 token 预算,超限就降级到小模型或直接拒绝;
3. **分级路由**:不是所有请求都需要最强的模型。分类、抽取、简单摘要用便宜的小模型,复杂推理才上旗舰——这一条通常能省掉一半以上成本。
## 小结
算 API 的账,记住三句话:**token 不等于字数;输出比输入贵;上下文是每轮重发的。**
把这三件事想明白,再加上缓存和分级路由,成本基本就可控了。剩下的就是持续监控——跟服务器资源一样,不测量的东西一定会失控。
---
**说明**:本文为通用技术实践整理,涉及的具体价格、折扣倍数与缓存策略以各厂商官方定价页与文档为准。
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法