推理成本最坑的地方不是单价,而是单价乘以你控制不了的分母:一段用户输入的长短、模型自选的回长、命中率、重试次数、并发峰值,全都不是采购时能定价的东西。于是"一个月花多少"这个问题在架构定稿前无人能答,等到账单出现,能做的手段只剩砍功能。成本治理要在设计阶段就把四件事定下来:钱花在哪个环节、哪些请求可以便宜、缓存能吃掉多少、贵的那条路挂了怎么退。
1. 成本构成拆解
| 组成 | 随什么增长 | 相对量级 | 可控性 |
|---|---|---|---|
| 输入 token | 历史长度、检索条数、系统提示 | 中 | 高,压缩与裁剪都有效 |
| 输出 token | 生成长度、是否思维链、重试 | 通常高于输入单价 | 中,靠约束与长度上限 |
| 缓存读写 | 命中率、前缀稳定性 | 命中部分显著便宜 | 高,但设计错了就归零 |
| 并发资源 | 峰值 QPS、单请求占用显存/时长 | 体现在容量与排队 | 中,靠限流与批处理 |
输出侧通常更贵,原因不是计费表写得偏心,而是生成是逐 token 串行的:输出 token 直接占用解码时间,输入 token 可以并行预填。所以省钱的第一直觉应该是"少让它说",而不是"少给它看"。
由此定下顺序:先限输出、再砍输入。反过来做,常是花两周裁剪检索,账单只降几个点。
2. 四个杠杆的作用面与代价
| 杠杆 | 作用面 | 典型收益 | 代价 |
|---|---|---|---|
| 模型档位 | 单价与延迟 | 大 | 质量下降,需按任务验证 |
| 提示长度 | 输入侧 | 中 | 上下文不足导致答偏 |
| 输出长度 | 输出侧 | 大 | 信息不全、格式被截断 |
| 缓存 | 重复请求 | 大且无质量损失 | 只对重复有效,命中率是赌博 |
收益不线性叠加:模型降档砍掉大头后,再砍提示长度可能换来质量断崖却只省几个点。先做收益最大且质量无损的——通常缓存第一,输出约束第二。
3. 模型路由:判据与误判风险
按复杂度分流是性价比最高的一招,难点全在"怎么判断复杂度"。
| 判据 | 可靠性 | 误判表现 |
|---|---|---|
| 输入长度 | 低 | 长输入可能是简单的格式转换 |
| 任务类型标签 | 中高 | 标签体系不全,落进默认档 |
| 历史相似请求的实际档位 | 中 | 冷启动无历史 |
| 小模型先试 + 置信度判断 | 高 | 判断本身也要花钱 |
| 显式由调用方声明 | 最高 | 调用方会一律声明"复杂" |
前两条是"看起来合理但经常错"的典型:长度与难度相关性很弱,一段 30k token 的合同只需要抽三个字段,而一句"证明这个不等式"很难。按长度路由是最常见的误判源。
ROUTE = {
"extract": {"tier": "small", "why": "结构化抽取,输出可校验"},
"classify": {"tier": "small", "why": "标签有限,错可兜底"},
"summarize":{"tier": "mid", "why": "压缩质量影响下游"},
"reason": {"tier": "large", "why": "多步推理,降档明显掉分"},
"unknown": {"tier": "mid", "why": "默认中档,靠反馈修正"},
}
# 误判兜底:低档输出未通过校验 → 升级重跑(成本仍低于全量用高档)
兜底升级是路由能成立的前提。没有校验与升级,路由就是纯降级。
4. 语义缓存与精确缓存
| 类型 | 命中条件 | 命中率量级 | 主要风险 |
|---|---|---|---|
| 精确缓存 | 请求逐字节一致 | 低到中,取决于重复度 | 几乎无 |
| 语义缓存 | 向量相似度超阈值 | 中到高 | 串答案:相似但不同的问题返回旧答案 |
| 分段缓存 | 前缀一致(系统提示、长文档) | 高 | 前缀被污染则全失效 |
语义缓存的核心参数是阈值:
semantic_cache:
embed_model: EMBED_MODEL
threshold: 0.92 # 起点,按业务校准;越低命中越高,串答案越多
scope: "per_tenant" # 绝不跨租户共享
ttl: 7d
invalidate_on: [prompt_version_change, corpus_update]
store_raw_answer: true # 便于人工复核串答案
三个决定不能省:阈值用真实查询集校准(在相似度分布里找"同义不同问"与"近义不同答"的分界);命中可复核(存原问题与原答案);提示版本变更即全量失效。
串答案的典型形态:问"A 方案的缺点"却命中"B 方案的缺点",句式一样使相似度高达 0.95,答案读起来完全通顺——所以说它致命。
精确缓存的适用面比想象中大:模板化请求、状态查询、同一文档的重复解析、幂等的结构化抽取。这些场景用语义缓存反而是给自己找麻烦。
5. 批处理与异步的空间
| 场景 | 可否批 | 省钱来源 | 延迟代价 |
|---|---|---|---|
| 离线标注、评测跑批 | 可 | 批量接口与错峰调度 | 无(本就不实时) |
| 夜间报表生成 | 可 | 低峰资源 + 大批次 | 小时级 |
| 内容审核 | 多为可 | 延迟容忍度高 | 秒到分钟 |
| 对话首响 | 不可 | — | 首 token 延迟即体验 |
批处理的省钱逻辑是两条:单次调用摊薄固定开销,以及把负载挪到资源便宜或空闲的时段。延迟预算是筛选条件:只有"用户可以等"的请求才进批,判据是业务 SLA 而不是技术可行性。
6. 成本可视化:算不出单次成本的四个原因
| 维度 | 切法 | 用途 |
|---|---|---|
| 按功能 | 场景标签 | 找出最贵的功能线 |
| 按用户 | 租户/账号 | 定价、限额、滥用识别 |
| 按任务类型 | 路由标签 | 验证路由是否真的省钱 |
| 按模型 | 供应商 + 型号 | 谈价与迁移依据 |
算不出单次成本,通常是这四件事没做:
1. 请求没有贯穿的 trace_id → 无法把一次用户操作的多段调用归并
2. 只记总量不记 token 分项 → 输入/输出/缓存混在一起,无法定位
3. 重试与降级调用未打标 → 一次成功请求的真实成本被低估
4. 共享资源(检索、向量库)未按请求摊分 → 单次成本漏项
第 3 条最隐蔽:一次成功回答背后可能是一次重试加一次降级升级,账面只算一次。计量要记尝试不是成功。
7. 预算控制的三层
| 层 | 机制 | 生效速度 | 用户体验 |
|---|---|---|---|
| 限流 | QPS / 并发上限 | 毫秒 | 排队或 429 |
| 配额 | 日/月 token 或金额上限 | 分钟 | 到顶后拒绝或降档 |
| 熔断 | 成本速率异常时断流 | 秒 | 功能不可用 |
三层解决不同问题:限流防瞬时打爆,配额防月度超支,熔断防异常放大(提示词 bug 导致输出暴涨)。只做配额最危险——配额月底才发现,熔断当场发现。
budget:
per_request: {max_out_tokens: 800, max_retries: 2}
per_tenant: {day: TOKEN_QUOTA, month: TOKEN_QUOTA_X30}
circuit: {trigger: cost_rate > BASELINE * 3, window: 5m, action: degrade_to_mid}
与体验的冲突不可避免。缓解办法是分级降档而非直接拒绝:超额后切低档并标注"精简模式",好过报错。
8. 降级链与质量告知
请求 → 精确缓存命中? → 返回
→ 语义缓存命中(≥阈值)? → 返回并标记 cached
→ 主模型(超时 T1 / 预算内)→ 成功返回
→ 中档模型(超时 T2)→ 成功返回,标注 degraded
→ 模板回复 / 检索原文摘录 → 标注 fallback
→ 明确失败(不静默返回空串)
降级链的设计要点:
- 每一档都有超时预算,总预算固定、分档递减,否则降级本身变成新的慢。
- 降级必须可观测、质量必须告知用户:"精简模式""参考摘录"这类标注不能省,静默降级比报错更伤信任。
- 不静默返回空:空串会被上游当成有效答案继续处理。
9. 成本与质量的权衡表
| 任务 | 值得用贵模型吗 | 判据 |
|---|---|---|
| 多步推理、规划 | 是 | 降档后错误率明显上升且难以校验 |
| 结构化抽取 | 否 | 输出可被 schema 校验,错了能重试 |
| 分类打标 | 否 | 标签有限,错分成本低 |
| 面向客户的最终文案 | 是 | 质量直接对收入 |
| 内部检索问答 | 否 | 有原文可核对 |
判据统一成一句:错误能否被廉价发现并纠正。能被校验的用便宜模型,不能被校验的用贵模型。
10. 资源侧省钱
| 手段 | 适用 | 注意 |
|---|---|---|
| 批次合并 | 高 QPS、短请求 | 批次越大,尾延迟越长 |
| 实例规格调整 | 自托管推理 | 显存决定能否装下模型与 KV 缓存 |
| 冷启动优化 | 弹性伸缩 | 模型加载时间常被低估 |
| 量化 | 自托管、质量可接受 | 需按任务回归验证 |
自托管与 API 的分界点不在单价而在利用率:利用率低到固定成本摊不下去时,按量付费更省。分界点按自己的峰值/均值比算,不套别人的结论。
11. 排错:账单降不下来的五种情况
| 现象 | 根因 | 处理 |
|---|---|---|
| 优化后成本几乎不变 | 优化了输入,输出才是大头 | 先限输出长度与思维链 |
| 缓存命中率接近零 | 前缀含时间戳/随机 ID | 稳定内容前置,逐字节一致 |
| 路由上线后质量投诉 | 降档无校验兜底 | 加 schema 校验与升级重跑 |
| 高峰期费用突刺 | 无并发上限,请求重试放大 | 限流 + 熔断 + 指数退避上限 |
| 语义缓存答非所问 | 阈值过低或跨租户共享 | 按真实集校准阈值,隔离 scope |
12. 边界:什么时候优化本身就不划算
| 情境 | 为什么不适用 | 替代 |
|---|---|---|
| 请求量很小 | 开发与运维成本高于省下的钱 | 先做输出长度上限即可 |
| 强实时场景 | 不能批、不能排队 | 只做缓存与模型档位 |
| 缓存命中率天然低 | 长尾查询、个性化强 | 别上语义缓存,改做提示瘦身 |
| 质量不可校验 | 降档风险不可控 | 保持单一高档模型,优化提示 |
| 合规要求可追溯原文 | 缓存与摘要都改变证据链 | 原文留存,成本让位合规 |
收益曲线先陡后平:前 30% 的工作拿到大部分节省,之后每一分都要用质量或工程量换。停手信号很明确——再降一档要新增一套校验体系,而省下的钱不够养它。
13. 自测
- 为什么输出侧通常比输入侧贵?这如何改变优化顺序?
- 按输入长度做模型路由,最典型的误判是什么?
- 语义缓存的阈值该怎么定,为什么不能拍?
- "算不出单次成本"最常见的一个遗漏项是什么?
- 限流、配额、熔断各自防的是哪种失控?
- 什么信号说明成本优化该停手了?