跳转到内容

成本追踪

成本追踪让你能够实时了解每个 AI 模型的花费。网关会统计每个请求的输入和输出令牌数,应用按模型定价的费率,并累计支出,使你无需外部工具即可监控成本。

每个在网关注册的模型都有一个定价配置,指定每 1000 个输入令牌和每 1000 个输出令牌的美元成本。请求完成后,网关从模型响应中提取令牌用量,分别计算输入成本和输出成本,然后求和得出请求总成本。

单个请求的计算公式为:

input_cost = (prompt_tokens / 1000.0) * input_per_1k
output_cost = (completion_tokens / 1000.0) * output_per_1k
total_cost = input_cost + output_cost

成本以十微美元精度(1 个内部单位 = 0.0001 美元)在内部追踪,以避免浮点数累加误差。每次记录成本时,美元值乘以 10,000,四舍五入到最接近的整数,并原子性地加入累计总额。当你读取总额时,除以 10,000 即可返回美元值。

所有通过指标和配置暴露的公开成本值均以美元为单位。

成本追踪器提供两种方法:

方法行为
calc_cost计算指定模型和用量的成本,但不更新累计总额。适用于提交请求前的预检或成本预估。
record计算成本,原子性地更新累计总额,然后返回计算出的美元值。这是每次成功请求后调用的方法。

记录使用宽松的原子排序(relaxed atomic ordering),因此来自不同线程的并发请求可以无竞争地一起记录成本。代价是,在高流量期间对 total_cost_dollars 的快照可能会遗漏最近几微秒内的更新,但总额最终会收敛。

网关预置了若干常见模型的定价。你也可以通过 with_pricing 提供自己的定价表。

模型每千令牌输入成本每千令牌输出成本
gpt-4o$2.50$10.00
gpt-4o-mini$0.15$0.60
gpt-3.5-turbo$0.50$1.50
claude-3-opus$15.00$75.00
claude-3-sonnet$3.00$15.00
claude-3-haiku$0.25$1.25

定价表中未列出的模型在记录请求时累计成本为零。对未知模型调用 calc_cost 的返回值为 0.0

网关使用各模型提供商在响应体中报告的令牌计数。这些是模型的 tokenizer 计算出的语义令牌数,而非基于字符的近似估算。AIUsage 结构体携带提供商报告的 prompt_tokenscompletion_tokens

如果模型响应不包含用量信息,该请求的成本为零。网关不会尝试从原始文本内容估算令牌数。

你可以提供自定义定价表来覆盖内置默认值,或为默认表中不存在的模型添加定价。向 CostTracker::with_pricing 传入一个 HashMap<String, ModelPricing>,其中每个条目以 f64 美元金额定义 input_per_1koutput_per_1k

cost:
pricing:
gpt-4o:
inputPer1k: 2.50
outputPer1k: 10.00
claude-3-sonnet:
inputPer1k: 3.00
outputPer1k: 15.00
custom-model:
inputPer1k: 1.25
outputPer1k: 5.00

使用自定义定价时,会完全替换内置默认值。请为你希望定价的每个模型都添加条目。

当与多租户配置结合使用时,成本追踪与租户级别的支出上限集成。每个租户可以有一个可选的美元 cost_limit。网关调用 check_cost_limit,将租户当前的累计成本与上限进行比对。如果租户超出限制,后续请求将被阻止,直到成本被重置或上限被提高。

成本追踪器通过 total_cost_dollars 暴露以美元为单位的累计总成本。你可以通过标准指标端点暴露该值,并用 Prometheus 抓取。常见的运营模式包括:

  • 当总成本超过每日或每周预算时触发告警。
  • 通过定期抓取并计算增量来观察成本趋势。
  • 使用按模型追踪来拆分各模型的支出(配置独立的追踪器实例,或在应用代码中追踪模型级别的成本)。

追踪器支持通过 reset 方法将总额归零。这对于临时部署、按计费周期的核算,或需要干净成本基线的集成测试套件非常有用。重置是原子的:在线程之间调用 reset 和记录调用是安全的。

CostTracker 使用 AtomicU64 作为累计总额,这意味着来自不同 tokio 任务或线程的并发 record 调用不需要外部同步。使用 Relaxed 排序的原子 fetch_add 对指标场景中单调递增的计数器提供了足够的一致性。

请注意,calc_cost 完全不与 record 同步。如果你调用 calc_cost 进行预检估算,然后在另一个线程上调用 record,这两个操作是独立的,calc_cost 的结果是一个时间点快照,不会反映该记录操作。