学习手册 / 成本与模型路由课程官网 ↗

CHAPTER 07 / 推理与系统

成本与模型路由

把每次调用的账单,变成每个成功任务的成本。

进阶建议阅读 25 分钟,练习另计自编配套教程
读完这一章,你应该能
  • 计算调用成本与成功任务成本,解释二者为何可能反向变化
  • 设计带预算、验证与升级条件的模型路由
  • 用固定任务集比较路由策略,而非凭模型印象选择

先确定你在为什么付钱

假设你正在做一个文档问答 Agent。一次用户问题可能触发检索、三次模型调用、一次格式修复。用户购买的是有证据的正确答案,账单却按调用和资源累计。只盯着单次 token 价格,会忽略轮数、重试、工具服务和失败后的人工处理。先定义一个任务的边界,从收到问题到通过验收或终止,所有尝试都计入同一笔账。

可以建立两层指标。调用层记录输入、输出、缓存读写 token 和模型;任务层记录总成本、成功与否、总耗时以及终止原因。成功任务成本 = 所有任务尝试的总成本 ÷ 成功完成的任务数。失败任务的开销仍在分子中;成功数为零时应标记为不可用,不要返回零。API 价格会变化,实验中保存采用的价格表与日期。自托管也有 GPU 使用时长和空闲容量成本,不能把免费额度当成长期成本。

一个便宜模型反而更贵的算例

以下价格全部是假设值,仅用于算术。模型 A 每次任务平均花费 0.02 元,成功率 40%;模型 B 平均花费 0.04 元,成功率 90%。各做一百个同分布任务,A 花 2 元得到 40 个成功,成功任务成本为 0.05 元;B 花 4 元得到 90 个成功,约为 0.044 元。单次价格低并没有带来更低的有效成本。

若一次调用使用 4,000 个未缓存输入 token、1,000 个输出 token,假设两类单价分别为每百万 2 元和 8 元,则成本为 0.008 + 0.008 = 0.016 元。存在缓存时要按供应商实际计费分类,避免既把缓存 token 算作普通输入,又重复收取缓存费用。再把一次任务的所有调用求和,最后按独立验收结果统计成功数。

把路由写成可观察的决策

路由可以发生在任务开始前,也可以在中途升级。开始前用可获得的信号分组,例如输入长度、是否涉及多个文件、是否需要复杂工具;中途则依据可执行检查、格式错误或明确的失败状态升级。不要用答案看起来流畅,或者模型自报“很有信心”,直接代替经过校准的质量信号。

一个起步策略是:简单任务先走小模型,检查失败再走大模型,最多升级一次。假设小模型成本 0.01 元,升级率 30%,大模型每次 0.05 元,则平均成本为 0.01 + 0.3 × 0.05 = 0.025 元,尚未计入验证器。成功率需要实际测量,因为验证器会误接收错误答案,也会把正确答案误判为失败。测试失败后的升级也会增加尾部延迟,应同时设定成本、轮数与总时限。

本机实验:从任务账本比较策略

把下面代码保存为 cost_lab.py,用 python3 cost_lab.py 运行。它只用标准库,不调用付费模型。每行表示一个完整任务,成本已经包含该任务内部的重试。示例账本是人为构造的,目的是检查统计口径,不能据此断言某种路由永远更好。

runs = {
    "small": [(0.02, True)] * 4 + [(0.02, False)] * 6,
    "large": [(0.04, True)] * 9 + [(0.04, False)],
    "routed": [(0.01, True)] * 7 + [(0.06, True)] * 2
              + [(0.06, False)],
}
for name, rows in runs.items():
    total = sum(cost for cost, ok in rows)
    success = sum(ok for cost, ok in rows)
    cps = total / success if success else float("inf")
    print(name, f"success={success}/{len(rows)}",
          f"total={total:.3f}", f"cost/success={cps:.4f}")
assert abs(sum(c for c, ok in runs["routed"]) - 0.25) < 1e-9

预期 small、large、routed 的成功任务成本分别约为 0.0500、0.0444、0.0278。把 routed 的一次成功改为失败,成本保持不变,再观察指标上升。随后用自己的 JSONL 运行记录替换账本,给每个 task_id 保留最终一次验收和所有尝试费用。

预算控制要和错误恢复一起设计

预算不是一句“尽量省钱”的提示词。执行器应在每次调用前检查剩余额度,在调用后扣减真实用量,并记录停止原因。即将耗尽时可以返回已验证的局部结果、要求缩小问题,或保留检查点等待继续。若工具动作有副作用,重试前先检查动作是否已经成功,避免一边省模型费用,一边重复创建资源。

缓存固定说明、减少无效检索和缩短不必要的输出,通常比随意删掉关键上下文更容易解释。并行子任务可能缩短墙钟时间,却增加总计算量。每项优化都应回答:省掉了哪些工作,是否改变任务难度,是否让失败转移到用户手上。压缩后的提示词要经过同一组任务验收,不能只比较 token 数。

比较时保留分组和失败样本

把固定任务集分成开发集和保留测试集,在开发集调阈值,最后只用保留集报告结果。对简单、困难、长上下文和工具密集任务分别统计,防止整体平均值掩盖某类任务退步。少量随机任务的百分点变化可能只是噪声,可以对同一任务做多次试验,并报告样本量与波动范围。

最终保留一张策略表,列出成功率、成功任务成本、延迟分位数、升级率和失败类型。若两套策略都满足质量底线,再按产品预算选择。最常见的误区是删除昂贵失败样本、把拒答算作成功、让不同模型得到不同工具权限,或一边换模型一边改提示词;这些操作都会让比较失去解释力。

LEARN BY DOING

为你的 Agent 写一份成本决策记录

  1. 选取至少 20 个固定任务,明确机器可检查的成功条件,并标注任务难度。
  2. 设计全用小模型、全用大模型、小模型失败后升级三个策略;没有 API 时先生成包含失败记录的模拟账本。
  3. 对每个 task_id 聚合所有调用和重试费用,统计成功率、成功任务成本及延迟。
  4. 写下路由触发条件、最大升级次数和超预算后的返回行为。

验收标准

  • 三种策略使用相同任务与验收器,失败任务费用没有被过滤。
  • 能复算至少一个任务的完整账单;零成功策略不会输出零成本。
  • 明确区分模拟结果与真实测量,并说明一个路由失败案例。
下载配套离线实验包 ↓ · 脚本使用模拟模型与数据,运行无需 API。

合上书,检查一下

先作答,再看解释。答错的地方,正好是值得再读一遍的地方。

1. 某策略尝试 100 个任务,共花费 12 元,成功 60 个。成功任务成本是多少?
2. 哪种信号最适合作为代码任务升级模型的起点?

配合本章看视频

下面按本站章节主题选配。为什么没有采用原课录播 →

本次尚未找到适合作为本章主课的公开路由策略视频。下面这讲只补充推理服务侧的成本与性能取舍;任务路由、失败回退和成功任务成本仍请结合本章教程与原始资料学习。

YouTube · 英语同主题参考 · 非 CS2680 原课

Stanford CS336 · Lecture 10: Inference (Spring 2025) ↗

用同一套性能模型串起推理成本、KV cache 与批处理,是系统部分的主参考课。对应第 7 章时只补充服务侧成本取舍,不代替模型路由策略。

带着问题看 · prefill 与逐 token 解码的计算/内存差异;TTFT、延迟、吞吐之间的取舍;KV cache 大小、continuous batching 与 PagedAttention;量化和 speculative sampling 的不同精度保证。

查看来源与观看说明 →

继续读原始资料

完成状态与自测成绩独立记录。