Skip to content

[Bug] Usage cost calculation ignores service-tier and long-context pricing multipliers #313

Description

@zzl360

What problem do you want to solve?

当前 Usage Keeper 的费用计算只应用模型基础单价和静态 price_multiplier,没有应用请求的 service tier 以及长上下文动态加价,因此本地统计费用会明显低于实际上游账单。

相关历史讨论:

Reproduction and evidence

我们使用一份真实上游账单导出进行脱敏汇总,并使用 Keeper 当前模型价格逐行重算:

  • 时间范围:2026-07-15 00:00:07 至 2026-07-16 12:09:40,Asia/Shanghai
  • 请求记录:33,092 条
  • Keeper 当前静态计价重算:$301.45788483
  • 上游实际计费:$365.97417553
  • 差额:$64.51629070
  • 上游比 Keeper 高:21.40%

差额主要来自:

  • gpt-5.6-sol$63.87928735
  • 缺少价格映射的 codex-auto-review$0.53907190
  • gpt-5.4$0.09793152

逐请求核对显示:

  • 普通 default 请求与 Keeper 基础价格一致。
  • priority 请求存在额外计费倍率。
  • gpt-5.6-sol 超过约 272K 输入上下文后存在长上下文加价。
  • priority 与长上下文同时出现时,加价可能叠加。

原始账单包含 API Key 名称和 IP,因此这里不公开上传;如维护者需要,可以另行提供脱敏后的逐行对账结果。

Current code path

UsageCostSubject 已包含 ServiceTier

type UsageCostSubject struct {
Model string
ModelAlias string
ServiceTier string
ExecutorType string
Tokens helper.UsageTokenCostInput

Calculate() 只根据模型选择基础价格,未使用 ServiceTier

func (r *UsageCostResolver) Calculate(subject UsageCostSubject) UsageCostResult {
pricing, matchedModel, matchedBy, ok := r.matchPricing(subject.Model, subject.ModelAlias)
if !ok {
return UsageCostResult{Available: !helper.UsageTokenInputRequiresPricing(subject.Tokens)}
}
return UsageCostResult{
Cost: helper.CalculateUsageTokenCostBreakdown(subject.Tokens, pricing),
Available: true,
PricingStyle: pricing.PricingStyle,
MatchedModel: matchedModel,
MatchedBy: matchedBy,
}

当前费用公式只应用静态模型倍率:

// CalculateUsageTokenCostBreakdown 按普通输入、缓存读取、缓存写入和输出四段独立计价。
func CalculateUsageTokenCostBreakdown(input UsageTokenCostInput, pricing entities.ModelPriceSetting) UsageTokenCostBreakdown {
input = clampUsageTokenCostInput(input)
breakdown := calculateUsageTokenCostBreakdown(input, pricing)
return scaleUsageTokenCostBreakdown(breakdown, modelPriceMultiplier(pricing))

最新版已经分别保存 service_tierresponse_service_tier,但费用解析器尚未使用后者,也没有长上下文阈值配置。

Expected behavior

建议延续 #232 中维护者提出的简化模型:

final cost = base token cost
           × service-tier multiplier
           × long-context multiplier
           × custom model multiplier

具体需要:

  1. 明确计费应使用请求 service_tier、实际 response_service_tier,还是按提供商契约选择;尤其要正确处理 auto
  2. 支持 service-tier 倍率,而不是要求每个 model+tier 重复配置完整输入、缓存和输出价格。
  3. 支持按模型配置长上下文阈值及倍率。
  4. 历史数据迁移必须保留现有聚合记录,不能清空后依赖可能已经过期删除的 raw events 重建。
  5. 对缺少价格或别名映射的模型给出明确告警,避免静默按 0 计费。

Additional context

这不是把某个模型基础价格简单翻倍就能解决的问题:普通 default 请求当前计价正确。如果直接修改基础价格,会导致普通请求被高估。动态倍率需要按每条 usage event 的 tier 和上下文条件应用。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions