fix: 千问3.5-plus计费不正确修复

This commit is contained in:
npc0-hue
2026-03-12 11:11:47 +08:00
parent 8df2e46658
commit 9591795b10
2 changed files with 73 additions and 15 deletions
@@ -49,3 +49,34 @@ var DefaultAPIBase = map[string]string{
// CredentialKeyFallback 未知提供商时依次尝试的配置 key
var CredentialKeyFallback = []string{ConfigKeyOpenaiAPIKey, ConfigKeyAPIKey, ConfigKeyDashScopeAPIKey}
// BuiltinModelPricing 内置兜底定价表(当 Dify Console API 未返回该模型定价时使用)。
// 价格单位:每千 token(与 ModelPricing.Unit=0.001 对应),货币为各模型实际结算货币。
// 通义/百炼模型官方定价(人民币,参考 https://help.aliyun.com/document_detail/2586379.html):
// - 输入/输出价格均为「每百万 token」,换算为每千 token 时除以 1000。
var BuiltinModelPricing = map[string]ModelPricing{
// ──── 通义千问 Qwen3 系列(RMB / 百万 token128K 档) ────
"qwen3-235b-a22b": {Input: 0.4 / 1000, Output: 1.6 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen3-30b-a3b": {Input: 0.11 / 1000, Output: 0.44 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen3-32b": {Input: 0.8 / 1000, Output: 3.2 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen3-14b": {Input: 0.3 / 1000, Output: 1.2 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen3-8b": {Input: 0.1 / 1000, Output: 0.4 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen3-4b": {Input: 0.04 / 1000, Output: 0.16 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen3-1.7b": {Input: 0.02 / 1000, Output: 0.08 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen3-0.6b": {Input: 0.01 / 1000, Output: 0.04 / 1000, Unit: 0.001, Currency: "RMB"},
// ──── 通义千问 Qwen3.5 系列(RMB / 百万 token128K 档) ────
"qwen3.5-plus": {Input: 0.8 / 1000, Output: 4.8 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen3.5-turbo": {Input: 0.3 / 1000, Output: 1.2 / 1000, Unit: 0.001, Currency: "RMB"},
// ──── 通义千问 Qwen2.5 系列(RMB / 百万 token ────
"qwen2.5-72b-instruct": {Input: 4.0 / 1000, Output: 12.0 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen2.5-32b-instruct": {Input: 3.5 / 1000, Output: 7.0 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen2.5-14b-instruct": {Input: 2.0 / 1000, Output: 6.0 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen2.5-7b-instruct": {Input: 1.0 / 1000, Output: 2.0 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen2.5-3b-instruct": {Input: 0.3 / 1000, Output: 0.6 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen-plus": {Input: 0.8 / 1000, Output: 2.0 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen-turbo": {Input: 0.3 / 1000, Output: 0.6 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen-max": {Input: 40.0 / 1000, Output: 120.0 / 1000, Unit: 0.001, Currency: "RMB"},
"qwen-long": {Input: 0.5 / 1000, Output: 2.0 / 1000, Unit: 0.001, Currency: "RMB"},
}
+42 -15
View File
@@ -152,27 +152,54 @@ func rmbToUSD(rmb float64) float64 {
return rmb / rmbToUSDRate
}
// resolvePricing 返回模型定价:优先用从 Dify 拉取的 pricing
// 其次查内置兜底定价表(BuiltinModelPricing),最后返回 nil。
func resolvePricing(pricing *gaia.ModelPricing, modelName string) *gaia.ModelPricing {
if pricing != nil && pricing.Unit > 0 {
return pricing
}
// 内置定价表精确匹配
if p, ok := gaia.BuiltinModelPricing[modelName]; ok {
return &p
}
// 前缀模糊匹配(如 "qwen3.5-plus-xxx" 匹配 "qwen3.5-plus"
lower := strings.ToLower(modelName)
for k, p := range gaia.BuiltinModelPricing {
if strings.HasPrefix(lower, strings.ToLower(k)) {
cp := p
return &cp
}
}
return nil
}
// calcQuotaDelta 根据定价和 token 用量计算本次消耗的配额金额(统一以 USD 计)。
// Dify pricing 字段语义:input/output 为每「unit」个 token 的价格,unit 通常为 0.001(千分之一),
// 即 input=0.0014, unit=0.001 表示每千 token 收 $0.0014 × (tokens/1000)。
// 即 input=0.0014, unit=0.001 表示每千 token ¥0.0014 × (tokens/1000)。
// 公式:cost = tokens × input × unit(因为 unit=1/1000,等价于 tokens/1000 × input)。
// 若货币为 RMB,则除以汇率 7.26 换算为 USD,与 account_money_extend.used_quota 存储单位保持一致。
// 若未找到定价则回退到合理默认值:$0.001/1000 tokens(即每 token $0.000001
func calcQuotaDelta(pricing *gaia.ModelPricing, promptTokens, completionTokens int) float64 {
if pricing == nil || pricing.Unit == 0 {
// 回退:按 $0.001 / 千token 计费(约 GPT-3.5 量级),避免按每 token 计费导致超额扣费
// 若货币为 RMB/CNY,则除以汇率 7.26 换算为 USD,与 account_money_extend.used_quota 存储单位保持一致。
// 若 Dify 未返回定价则查内置兜底表;均未命中时按极小默认值记账,避免多扣
func calcQuotaDelta(pricing *gaia.ModelPricing, modelName string, promptTokens, completionTokens int) float64 {
p := resolvePricing(pricing, modelName)
if p == nil {
// 兜底:$0.001/千token,仅做记账占位,不应大量触发
global.GVA_LOG.Warn("calcQuotaDelta 未找到模型定价,使用兜底值",
zap.String("model", modelName),
zap.Int("prompt_tokens", promptTokens),
zap.Int("completion_tokens", completionTokens),
)
return float64(promptTokens+completionTokens) * 0.001 * 0.001
}
inputCost := float64(promptTokens) * pricing.Input * pricing.Unit
outputPrice := pricing.Output
inputCost := float64(promptTokens) * p.Input * p.Unit
outputPrice := p.Output
if outputPrice == 0 {
outputPrice = pricing.Input
outputPrice = p.Input
}
outputCost := float64(completionTokens) * outputPrice * pricing.Unit
outputCost := float64(completionTokens) * outputPrice * p.Unit
total := inputCost + outputCost
// RMB 定价统一换算为 USD 后再扣费,与 used_quota 存储单位保持一致
if strings.EqualFold(pricing.Currency, "RMB") || strings.EqualFold(pricing.Currency, "CNY") {
// RMB/CNY 定价统一换算为 USD 后再扣费,与 used_quota 存储单位保持一致
if strings.EqualFold(p.Currency, "RMB") || strings.EqualFold(p.Currency, "CNY") {
total = rmbToUSD(total)
}
return total
@@ -1239,9 +1266,9 @@ func (s *ModelProviderService) ProxyRequest(
// 计费:仅成功时扣费
if logStatus == "success" {
if promptTokens > 0 || completionTokens > 0 {
// LLM 类型:按 token 计费
pricing, _ := s.fetchModelPricingFromDify(modelOrPath)
delta := calcQuotaDelta(pricing, promptTokens, completionTokens)
// LLM 类型:按 token 计费
pricing, _ := s.fetchModelPricingFromDify(modelOrPath)
delta := calcQuotaDelta(pricing, modelOrPath, promptTokens, completionTokens)
deductAccountQuota(userID, delta)
} else if isImageOrPerRequestPath(path) {
// 图片生成等无 usage 的接口:按请求次数计费(固定 0.04 USD/次,约 1 张图片单价)