fix: correct account stats pricing priority order

Priority was wrong:
- Before: custom rules → LiteLLM (when ApplyPricingToAccountStats) → nil
- After:  custom rules → totalCost (when ApplyPricingToAccountStats) → LiteLLM → nil

When ApplyPricingToAccountStats is enabled, use the request's actual
client billing cost (before multiplier) as account_stats_cost, instead
of recalculating from LiteLLM per-token prices which produced incorrect
values for per-request billing mode.

LiteLLM model pricing is now the final fallback (priority 3), used only
when neither custom rules nor ApplyPricingToAccountStats apply.
This commit is contained in:
erio
2026-04-13 16:45:10 +08:00
parent 42f8ef3315
commit 98c9d51791
4 changed files with 19 additions and 6 deletions

View File

@@ -1 +1 @@
0.1.110.24
0.1.110.27

View File

@@ -11,10 +11,12 @@ import (
//
// 优先级(先命中为准):
// 1. 自定义规则(始终尝试,不依赖 ApplyPricingToAccountStats 开关)
// 2. ApplyPricingToAccountStats 启用时,用模型定价文件LiteLLM中上游模型的标准价格计算
// 3. nil → 走默认公式
// 2. ApplyPricingToAccountStats 启用时,直接使用本次请求的客户计费(倍率前的 totalCost
// 3. 模型定价文件LiteLLM中上游模型的默认价格
// 4. nil → 走默认公式total_cost × account_rate_multiplier
//
// upstreamModel 是最终发往上游的模型 ID。
// totalCost 是本次请求的客户计费(倍率前),用于优先级 2。
func resolveAccountStatsCost(
ctx context.Context,
channelService *ChannelService,
@@ -24,6 +26,7 @@ func resolveAccountStatsCost(
upstreamModel string,
tokens UsageTokens,
requestCount int,
totalCost float64,
) *float64 {
if channelService == nil || upstreamModel == "" {
return nil
@@ -40,8 +43,17 @@ func resolveAccountStatsCost(
return cost
}
// 优先级 2模型定价文件LiteLLM/fallback中上游模型的标准价格
if channel.ApplyPricingToAccountStats && billingService != nil {
// 优先级 2渠道开启"应用模型定价到账号统计"时,直接使用客户计费(倍率前)
if channel.ApplyPricingToAccountStats {
cost := totalCost
if cost <= 0 {
return nil
}
return &cost
}
// 优先级 3模型定价文件LiteLLM默认价格
if billingService != nil {
return tryModelFilePricing(billingService, upstreamModel, tokens)
}

View File

@@ -7598,6 +7598,7 @@ func (s *GatewayService) recordUsageCore(ctx context.Context, input *recordUsage
ImageOutputTokens: result.Usage.ImageOutputTokens,
},
1, // requestCount
cost.TotalCost,
)
}

View File

@@ -4582,7 +4582,7 @@ func (s *OpenAIGatewayService) RecordUsage(ctx context.Context, input *OpenAIRec
usageLog.AccountStatsCost = resolveAccountStatsCost(
ctx, s.channelService, s.billingService,
account.ID, *apiKey.GroupID, statsModel,
tokens, 1,
tokens, 1, cost.TotalCost,
)
}