大模型调用单价上涨后,如何判断真实成本
作者:da吃一鲸8862026.11.10 15:51浏览量:1简介:模型单价上涨不等于总账单同步上涨。多轮任务中的上下文累积、缓存命中、输出长度和成功率,同样决定最终花费。本文拆解单价、用量与任务轮次之间的关系,给出可复用的成本估算公式和代码示例,并说明如何通过上下文管理控制开销,帮助团队在选型和预算前做出可验证的判断。
一、单价与总成本是两个问题
大模型服务通常按输入 token、命中缓存的输入 token、输出 token 分别计价。单价是每百万 token 的价格,它是一个固定参数。总成本则是各类 token 用量乘以对应单价,再把所有轮次的结果加总。两者经常被混为一谈。某个模型的单价翻倍,同一任务的账单未必翻倍。反过来,单价下降也可能因为模型需要更多轮次才能完成任务,让总花费不降反升。
判断成本时,需要同时回答三个问题:完成一次任务需要多少次请求,每次请求消耗多少各类 token,各类 token 的单价是多少。只看单价,只能得到一个局部结论。
二、用切披萨理解单位价格
同一张披萨切成 8 块,每块 2 美元,总价 16 美元。切成 16 块,每块 1.25 美元,总价 20 美元。第二种切法的单价更低,但人吃下的披萨量没有变化,所以总支出更高。
这个类比对应到模型调用中,可以这样理解。单价相当于每块披萨的价格。有效工作量相当于真正吃下去的那部分,也就是完成任务所需的有效 token 和有效步骤。如果一个模型能用更少的 token 和更少的步骤解决问题,即使单价偏高,总成本也可能更低。如果一个模型单价低,却需要反复试错,总用量就会被放大。
因此,比较模型时应当比较“完成同一任务的总成本”,而不是比较“每百万 token 多少钱”。
三、多轮交互中的成本放大机制
在对话式或代理式的工作流中,每一轮请求通常会带上完整历史,包括之前的提问、模型回复、工具返回结果等。这意味着输入 token 会随轮次持续增长。
假设初始上下文为 2000 token,每轮新增约 1500 token(包括工具返回和模型输出),共运行 10 轮。第 k 轮的输入量约为 2000 + 1500 × (k − 1)。10 轮累计输入约为 87,500 token,累计输出按每轮 500 token 计算为 5,000 token。输入量的增长近似于轮次的平方关系,轮次越多,后期每一轮的输入成本越高。
这类场景有两个特点。第一,任务目标不够清晰,模型需要“做一步、看一步”,轮次难以预先确定。第二,每一步都依赖上一步的反馈,无法批量合并请求。在这种情况下,输入单价和缓存单价对总成本的影响,比单次问答时更明显。
输出 token 的价格通常高于输入 token。长篇回复、冗长的推理过程或不必要的解释,会在输出侧快速累积费用。控制输出长度与控制输入长度同样重要。
四、上下文管理策略对成本的影响
上下文管理方式直接决定每轮的输入规模。常见策略有四种,各自的成本特征不同。
1. 完整保留历史。 实现最简单,信息无损失。但输入随轮次增长,适合轮次少、单轮信息量小的任务。
2. 摘要压缩。 定期把历史对话压缩为摘要,只保留摘要和最近几轮。输入规模可控,但生成摘要本身需要消耗 token,而且摘要可能遗漏关键细节,导致后续返工。返工的成本需要计入总账。
3. 分段会话加外部记录。 把长任务拆分为多个会话,每个会话开始时只带入必要的状态。状态信息写入外部存储,例如任务清单、决策日志、关键参数表。每次只读取当前步骤需要的内容。这种方式能有效控制单轮输入,代价是增加了状态设计和恢复的工程复杂度。
4. 检索式引入上下文。 将历史内容切分后存入索引,每轮只检索与当前问题相关的片段。适合知识量大、但每步只需局部信息的场景。检索质量不稳定时,模型可能缺少关键依据,需要额外的校验步骤。
部分计费方案会按上下文长度分档,超过某个阈值后单价发生变化。评估时需要核对计费规则中是否存在此类分档,并把分档边界纳入成本模型。
缓存是另一项关键因素。如果多轮请求的前缀内容保持稳定,缓存命中率会明显提高,输入成本随之下降。为了提高命中率,应当把不变的指令、角色设定和参考资料放在请求的前部,把每轮变化的内容放在后部。
五、配额与计费维度的区分
同一个模型的使用入口可能有多种,例如交互式对话、开发工具内嵌调用、直接接口调用。不同入口的配额和计费方式可能相互独立。
配额规则需要关注以下几点:
- 计量单位是按会话条数、按 token 数,还是按时间窗口计算。
- 不同入口之间是否共享额度,是否存在单独的每日或每周上限。
- 额度耗尽后,系统是中断服务、降级到其他模型,还是按超额单价计费。
- 降级策略是否会改变输出质量,进而影响任务的成功率和返工次数。
这些规则决定了实际可用额度,也决定了团队应当把哪些任务放在哪个入口运行。
六、评估框架:从单任务成本到单位成功成本
一套可靠的评估方法通常包含以下步骤。
- 建立标准任务集。选择 20 到 50 个代表真实业务的任务,覆盖简单、中等和复杂三个层次。
- 记录每次运行的轮次、输入 token、缓存命中 token、输出 token。
- 按计费规则计算每个任务的成本。
- 判断每个任务是否成功,统计成功率。
- 计算单位成功成本,即总成本除以成功任务数。
单位成功成本是最关键的指标。一个单价较低的方案如果成功率偏低,需要更多重试,单位成功成本可能高于单价较高但一次完成率高的方案。
下面的代码给出成本计算的基础实现。其中的价格参数为示意值,不对应任何具体服务。
from dataclasses import dataclassfrom typing import List, Tuple@dataclassclass Pricing:input_per_m: float # 每百万未命中缓存的输入 token 单价cached_per_m: float # 每百万命中缓存的输入 token 单价output_per_m: float # 每百万输出 token 单价@dataclassclass RoundUsage:input_tokens: int # 本轮输入 token 总数(含缓存部分)cached_tokens: int # 本轮命中缓存的输入 token 数output_tokens: int # 本轮输出 token 数def task_cost(rounds: List[RoundUsage], p: Pricing) -> float:"""计算单个任务在所有轮次中的总成本。"""total = 0.0for r in rounds:fresh = r.input_tokens - r.cached_tokenstotal += fresh * p.input_per_m / 1_000_000total += r.cached_tokens * p.cached_per_m / 1_000_000total += r.output_tokens * p.output_per_m / 1_000_000return totaldef cost_per_success(results: List[Tuple[List[RoundUsage], bool]],p: Pricing,) -> float:"""计算单位成功成本:总成本除以成功任务数。"""total = sum(task_cost(rounds, p) for rounds, _ in results)successes = sum(1 for _, ok in results if ok)if successes == 0:return float("inf")return total / successesif __name__ == "__main__":# 示意价格,单位为任意货币单位pricing = Pricing(input_per_m=2.0, cached_per_m=0.2, output_per_m=10.0)# 模拟 10 轮任务:输入从 2000 逐轮增加 1500,输出每轮 500,无缓存rounds = []for k in range(10):rounds.append(RoundUsage(input_tokens=2000 + 1500 * k,cached_tokens=0,output_tokens=500,))print(f"单任务成本: {task_cost(rounds, pricing):.4f}")
运行上述示例,10 轮无缓存任务的输入成本约为 0.175,输出成本约为 0.05,合计约 0.225。若把前缀内容改为缓存命中,输入成本会明显下降。评估时应当分别统计两种情况,以确定缓存策略的实际收益。
七、落地建议
- 选型前先定义标准任务集,用同一套任务比较不同方案,避免凭单价做判断。
- 同时记录成本、耗时和成功率,计算单位成功成本,作为主要决策指标。
- 把不变的指令和参考资料放在请求前部,提高缓存命中率。
- 对长任务采用分段会话和外部状态记录,控制单轮输入规模。
- 限制输出长度,要求模型只返回结构化结果或必要信息,减少输出 token 的浪费。
- 核对计费规则中的配额、分档边界和超额策略,把这些条件写入成本模型。
- 定期用真实流量回放评估结果,因为任务分布变化会改变各项成本的权重。

登录后可评论,请前往 登录 或 注册