Skip to content

13 · 成本与模型路由:把每一笔 token 花在刀刃上 ​

LLM 服务的成本不是"账单上的一个数",而是每一笔请求的构成。本篇讲清 Token 成本模型、四层降本手段(路由/缓存/精简/批处理)与预算治理,给出一套"先测量、再优化"的方法论。

速览卡 ​

项内容
一句话定位模型调用为什么会花钱、钱花在哪、怎么在不损失质量的前提下把钱省下来
核心内容成本的完整构成、Token 成本模型、模型路由(规则/分类/级联)、三级缓存、批处理、预算与告警
读完能回答一次调用到底花了多少?为什么"换大模型"常常不是最优解?70% 的调用能不能用便宜模型?
相关板块G05 · 工程化与 LLMOps | G12 · 上下文工程 | C21 · AI 服务可靠性

一、先看清成本的完整构成 ​

很多人以为"成本 = API 账单"。真实成本至少五层:

层级内容前端类比
模型调用输入 token + 输出 token + 缓存写入每个接口的服务器费用
配套算力向量化(embedding)、重排、RAG 检索每张图的压缩/转码费用
失败成本重试、超时、Agent 死循环请求失败后重复请求的浪费
工程与人力调 prompt、建评测、维护写代码本身
人工兜底审核、客服、二次确认客服人力

铁律:先记账(每次调用落库 token + 成本),再谈优化。不记账的"降本"都是拍脑袋。


二、Token 成本模型:看懂一次调用花多少钱 ​

2.1 基本公式 ​

text
单次成本 = 输入 token × 输入单价 + 输出 token × 输出单价 + 配套成本

三个"不直观"的点:

点说明
输出比输入贵多数供应商输出单价显著高于输入,所以"让模型少说废话"直接省钱
上下文非线性注意力开销随序列长度增长,塞进第 10 万个 token 的边际成本远高于第 1 千个 [易变]
缓存写入也算钱长 prompt 的第一次写入会贵,命中缓存后会便宜

2.2 一个可运行的估算函数 ​

python
# 粗估:给一个"单位成本"落到每个业务动作
def estimate_cost(input_tokens: int, output_tokens: int,
                  in_price: float, out_price: float) -> float:
    return input_tokens * in_price + output_tokens * out_price

# 更实用的:按业务动作统计,而不是按请求统计
def cost_per_action(action_calls: list[dict]) -> float:
    total = 0.0
    for c in action_calls:
        total += estimate_cost(c["in"], c["out"], c["in_p"], c["out_p"])
    return total

上生产前先跑一遍成本仿真:把线上请求的 token 分布导出来,代入真实单价,算出日/月成本,再决定要不要上大模型。


三、模型路由:让 70% 的调用用便宜模型 ​

3.1 为什么路由收益最高 ​

多数服务的调用根本不需要旗舰模型——分类、抽取、简单问答,小模型就够。路由的核心不是"挑模型",而是给每个任务定一个"够用"的模型:

任务类型建议模型档位理由
命名实体抽取、格式转换小模型结构性强,大模型优势用不上
意图分类、路由本身小模型 / 规则决定"接下来谁回答"就够了
复杂推理、长文档分析旗舰模型质量敏感
多语言、创造性写作中档模型质量与成本折中

3.2 三种路由实现 ​

方式怎么判断适用前端类比
规则路由关键词/长度/字段判断意图边界清晰的场景路由守卫/中间件
分类器路由用一个小模型或传统分类器打标签意图多且规则写不动把重活分给"专科"处理
级联(Cascade)先用便宜的,效果不达标再升级质量要求高但多数请求简单先试缓存,未命中再请求

3.3 级联:先用便宜的,不达标再升级 ​

python
def answer(query: str) -> str:
    # 第 1 跳:便宜模型快速作答
    ans = cheap_model(query)
    if is_confident(ans):        # 自评/结构校验通过才放行
        return ans
    # 第 2 跳:升级到旗舰模型,只对"难样本"花大钱
    return flagship_model(query)

陷阱:级联的"判断是否达标"本身会花钱。自评 token 也算成本,要把它算进总账;能靠规则/结构校验(JSON 解析、长度校验)判断就不要让模型自评。


四、三级缓存:把重复的钱省到趋近 0 ​

缓存命中条件适合风险
精确缓存prompt 完全一致固定模板请求几乎无
前缀缓存前面一大段一致系统提示 + 固定模板缓存一致性
语义缓存语义相近(向量相似度)FAQ、常见问法误命中给错答案
python
import redis, numpy as np

def semantic_get(r: redis.Redis, query_vec: np.ndarray, threshold: float):
    # 简版:遍历历史问题向量,相似度超阈值即命中
    for key in r.keys("qa:*"):
        stored = np.frombuffer(r.hget(key, "vec"), dtype=np.float32)
        if (query_vec @ stored) > threshold:
            return r.hget(key, "answer")
    return None

语义缓存 ≈ 前端的 memoization,但键不是精确的。必须带租户隔离:A 用户的答案不能缓给 B 用户看。


五、批处理与离线:把实时性换成折扣 ​

场景用批处理吗说明
在线对话❌要实时
日报/周报总结✅定时跑,错峰便宜
批量分类/打标✅纯吞吐,无交互
评测集跑分✅离线批量最划算

很多平台对批量/异步请求有单独计价(通常比实时便宜),且天然错峰。把"不要求即时返回"的任务从在线挪到批处理,是成本结构里最干净的一块。


六、预算治理:让成本可预测 ​

工具干什么
单位业务成本每个"回答/订单/用户"花多少,而不是总账单
分维度记账按功能、租户、模型、Prompt 模板拆
预算 + 告警日/月预算的 70% / 90% 告警,超限熔断
成本回归每次改 prompt / 模型 / 路由,都跑同一组用例看成本变化
text
成本日报:功能 → 调用数 → 输入/输出 token → 平均单价 → 日成本 → 环比

前端类比:这就像性能预算(bundle 体积、LCP)——你不设预算,它就悄悄失控。


自检清单 ​

  • [ ] 每次调用都落库:模型、token 数、单价、成本
  • [ ] 给"简单任务"配了便宜模型或小模型
  • [ ] 有规则/分类/级联三种路由中的至少一种,且算过自评成本
  • [ ] 有精确 + 前缀 + 语义三级缓存中的至少一种,且做了租户隔离
  • [ ] 把不要求实时的任务挪到了批处理
  • [ ] 有单位业务成本 + 分维度报表 + 预算告警

常见误区 ​

误区事实
"成本就是 API 账单"配套算力、失败重试、人工兜底往往更大
"换旗舰模型就能解决一切"多数任务用不上旗舰;先路由再换模型
"缓存只要加个字典就行"语义缓存要算相似度、带租户隔离、处理失效
"级联反正先用便宜的"自评本身花 token,可能比直接上旗舰还贵
"批处理没收益"离线批量单价更低且错峰,是成本结构里最干净的一块
"先上线再治理"不记账就没有数据,成本失控后很难回查

动手练习 ​

练习 A:给现有服务做一次"成本体检" ​

导出最近一周的调用日志(模型、输入/输出 token、是否命中缓存),回答:

  1. 哪些调用的输入特别长?(上下文有没有浪费?见 G12)
  2. 哪些调用其实是"简单任务"却用了旗舰模型?
  3. 有多少次调用命中语义缓存(相似问题反复问)?

练习 B:实现一个规则路由 + 级联 ​

选一个你线上的任务,先用规则把明显简单的分流到小模型;再对小模型结果做一次结构校验(解析 JSON、检查必填字段),校验不过才升级旗舰。对比改造前后的日成本与错误率。

练习 C:搭一张成本日报 ​

用 Redis + 定时任务(见 C15 定时任务),把每次调用记账,每天生成"功能 × 模型 × 成本"日报,并设 70% / 90% 预算告警。


延伸方向 ​