fix(billing): 计费始终使用用户请求的原始模型,而非映射后的上游模型
当账号配置了模型映射(如 claude-sonnet-4-6 → glm-5.0)时,系统错误地 使用映射后的上游模型名计算费用。由于上游模型(如 glm-5.0)在定价系统中 没有价格配置,导致计费失败后被静默置为 0,用户不被扣费。 修改 forwardResultBillingModel 优先返回请求模型名,并移除 OpenAI 路径 中 BillingModel 字段对计费模型的覆盖逻辑。
This commit is contained in:
@@ -895,14 +895,16 @@ func TestOpenAIGatewayServiceRecordUsage_UsesRequestedModelAndUpstreamModelMetad
|
|||||||
require.Equal(t, 1, userRepo.deductCalls)
|
require.Equal(t, 1, userRepo.deductCalls)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpenAIGatewayServiceRecordUsage_BillsMappedRequestsUsingUpstreamModelFallback(t *testing.T) {
|
func TestOpenAIGatewayServiceRecordUsage_BillsMappedRequestsUsingRequestedModel(t *testing.T) {
|
||||||
usageRepo := &openAIRecordUsageLogRepoStub{inserted: true}
|
usageRepo := &openAIRecordUsageLogRepoStub{inserted: true}
|
||||||
userRepo := &openAIRecordUsageUserRepoStub{}
|
userRepo := &openAIRecordUsageUserRepoStub{}
|
||||||
subRepo := &openAIRecordUsageSubRepoStub{}
|
subRepo := &openAIRecordUsageSubRepoStub{}
|
||||||
svc := newOpenAIRecordUsageServiceForTest(usageRepo, userRepo, subRepo, nil)
|
svc := newOpenAIRecordUsageServiceForTest(usageRepo, userRepo, subRepo, nil)
|
||||||
usage := OpenAIUsage{InputTokens: 20, OutputTokens: 10}
|
usage := OpenAIUsage{InputTokens: 20, OutputTokens: 10}
|
||||||
|
|
||||||
expectedCost, err := svc.billingService.CalculateCost("gpt-5.1-codex", UsageTokens{
|
// Billing should use the requested model ("gpt-5.1"), not the upstream mapped model ("gpt-5.1-codex").
|
||||||
|
// This ensures pricing is always based on the model the user requested.
|
||||||
|
expectedCost, err := svc.billingService.CalculateCost("gpt-5.1", UsageTokens{
|
||||||
InputTokens: 20,
|
InputTokens: 20,
|
||||||
OutputTokens: 10,
|
OutputTokens: 10,
|
||||||
}, 1.1)
|
}, 1.1)
|
||||||
|
|||||||
@@ -4153,9 +4153,6 @@ func (s *OpenAIGatewayService) RecordUsage(ctx context.Context, input *OpenAIRec
|
|||||||
}
|
}
|
||||||
|
|
||||||
billingModel := forwardResultBillingModel(result.Model, result.UpstreamModel)
|
billingModel := forwardResultBillingModel(result.Model, result.UpstreamModel)
|
||||||
if result.BillingModel != "" {
|
|
||||||
billingModel = strings.TrimSpace(result.BillingModel)
|
|
||||||
}
|
|
||||||
serviceTier := ""
|
serviceTier := ""
|
||||||
if result.ServiceTier != nil {
|
if result.ServiceTier != nil {
|
||||||
serviceTier = strings.TrimSpace(*result.ServiceTier)
|
serviceTier = strings.TrimSpace(*result.ServiceTier)
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ func optionalNonEqualStringPtr(value, compare string) *string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func forwardResultBillingModel(requestedModel, upstreamModel string) string {
|
func forwardResultBillingModel(requestedModel, upstreamModel string) string {
|
||||||
if trimmedUpstream := strings.TrimSpace(upstreamModel); trimmedUpstream != "" {
|
if trimmed := strings.TrimSpace(requestedModel); trimmed != "" {
|
||||||
return trimmedUpstream
|
return trimmed
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(requestedModel)
|
return strings.TrimSpace(upstreamModel)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user