Appearance
成本速算:这个功能每次调用多少钱
1. 本节产出
掌握一套估算公式和一张可复用的测算表,能对任意 AI 功能在写代码之前给出单次调用成本和月度账单量级,并知道五个最常见的账单失控点。
2. 前置依赖
- 00-03 版本矩阵
- 需要理解 Token 是什么,见 00-05 术语表 的「Token」条目
3. 为什么要在动手前先算钱
AI 项目和普通后端项目最大的区别:每一次业务调用都在烧真金白银,而且费用随流量线性增长。
三个真实翻车场景:
| 场景 | 发生了什么 | 损失 |
|---|---|---|
| 内部问答上线第一天 | 没做缓存,同一批员工问了同样的三个问题几百次 | 首月账单远超预算 |
| Agent 加了重试 | 失败自动重试 3 次,错误期间每次调用都在计费 | 高峰期账单翻了数倍 |
| 上下文越塞越多 | 把整个历史对话都带上,单次请求 tokens 线性膨胀 | 单价不变但总量暴涨,且延迟同步变差 |
算钱这件事,早算一天省一个月。
4. 核心原理:成本由四个因子相乘
单次成本 = 输入 tokens × 输入单价
+ 输出 tokens × 输出单价
+ (如有)Embedding tokens × Embedding 单价
+ (如有)Rerank 调用次数 × Rerank 单价月度账单 = 单次成本 × 日均调用次数 × 30
要算准,关键是估准 token 数。这是 Java 工程师最容易估错的一步,因为直觉是按「字数」算。
Token 与字数的换算
| 文本类型 | 换算经验值 |
|---|---|
| 英文 | 1 token ≈ 4 个字符 ≈ 0.75 个单词 |
| 中文 | 1 个汉字 ≈ 0.6~1.5 token(取决于模型分词器,涉及生僻字、代码片段会更高) |
| 代码 | 比自然语言贵,缩进与符号都会占 token |
提示:永远不要靠估算签约。上线前用真实数据跑一遍,读响应里的
usage字段核对——这是唯一的准确数。
四个因子怎么估
以「企业文档问答」为例,典型的 token 构成:
| 部分 | token 估算 | 说明 |
|---|---|---|
| System Prompt | 100-500 | 指令、约束、格式要求 |
| 检索到的上下文 | Top-K 段数 × 每段 token | 决定性因素,K=5、每段 400 token 就是 2000 |
| 历史对话 | 保留轮数 × 每轮 | 多轮会话下会不断累积 |
| 用户当前问题 | 20-200 | 通常可以忽略 |
| 输出回答 | 100-1000 | 可以设置上限控制 |
可以看到:上下文是多轮 Agent 场景下最大的成本项。这也解释了为什么后面所有优化(切分粒度、Top-K、缓存、上下文压缩)最终都指向同一件事——少传 token。
5. 操作步骤
步骤 1:建一张自己的价格表
价格会变,不要抄网上过期数字。做法是在那一刻去厂商官网的定价页抄下来,填进这张表:
| 模型用途 | 厂商/模型 | 输入单价 (元/千 token) | 输出单价 (元/千 token) | 抄录日期 |
|---|---|---|---|---|
| 主力对话 | ||||
| 廉价任务(分类/摘要) | ||||
| Embedding | ||||
| Rerank |
提示:输出单价通常显著高于输入(常见是数倍)。这意味着「让模型少说废话」直接省钱,把
max_tokens设置合理既是性能优化也是成本优化。
步骤 2:用真实请求取 token 数
Spring AI 的响应里带用量信息:
java
ChatResponse response = chatModel.call(prompt);
Usage usage = response.getMetadata().getUsage();
System.out.printf("prompt=%d, completion=%d, total=%d%n",
usage.getPromptTokens(), usage.getCompletionTokens(), usage.getTotalTokens());跑十次代表性请求取平均,比估算准得多。
步骤 3:套公式算月度
代入:
日均调用 = DAU × 人均调用次数
月度成本 = 单次成本 × 日均调用 × 30步骤 4:给一个决策样例
假设一个内部文档问答:单次输入 2500 token(含检索上下文),单次输出 400 token,日调用 500 次。设输入单价为 a 元/千 token,输出为 b 元/千 token:
单次 = 2.5a + 0.4b
月度 = (2.5a + 0.4b) × 500 × 30 = 37500a + 6000b把 a、b 换成你表格里的真实数字,就得到月账单。写方案时把中间过程留下,业务方问「为什么这么贵」时,你能当场拆给他们看。
6. 验证清单
- [ ] 建立了自己的价格表,并标注抄录日期
- [ ] 用
usage字段核对过至少一种典型请求的真实 token 数 - [ ] 算出的月度成本,先乘 1.3 作为含重试和意外的预算值
- [ ] 确认已设置
max_tokens,避免输出失控 - [ ] 明确了高峰期的调用量上限(不设限的系统在异常时会把预算烧穿)
7. 生产避坑
- 调试期的打印就是双倍计费。每打印一次完整响应你就多花一次看不见的钱。开发环境建议把 temperature 调低、输出长度调小,并且不要在生产日志里记录完整 prompt/response(同时也合规)。
- 重试是隐形成本放大器。失败重试在账单上同样计费,尤其是模型超时这种场景——请求其实可能已经到达服务端。做法:重试只对幂等、且明确是连接类错误的场景开,同时给重试总量设熔断。
- Embedding 的钱别忽略。入库时看着是一次性成本,但文档更新频率一高就是持续支出。增量更新(只重算变更文档)和幂等设计在这里直接等价于省钱。
- 长上下文不是免费的灵丹妙药。很多团队发现「模型支持超长上下文」就干脆全塞进去,结果是延迟和成本同步恶化,而检索质量未必更好。
- 缓存命中率要单独度量。精确缓存(完全相同请求)和语义缓存(相似请求)能省下的比例差异巨大,别在方案里拍脑袋写「预计节省 50%」——这会被业务方当成承诺。
8. 延伸与锚点
- 思考题:你的场景里,输入和输出哪个占比更高?如果输入占大头 → 攻上下文压缩与缓存;如果输出占大头 → 攻约束格式和
max_tokens。 - 代码锚点:
ch00-04-cost-calculation - 下一章:00-05 术语表
- 后续深化:02-18 成本治理与降级(待编写)、04-07 成本治理与预算告警(待编写)