Merge pull request #5018 from hongheshan-svg/fix/glm-5.2-fallback-pricing

fix(billing): 补上 glm-5.2 兜底价,避免被 glm-5 子串匹配抢走
This commit is contained in:
Wesley Liddick
2026-07-31 12:00:45 +08:00
committed by GitHub
2 changed files with 34 additions and 7 deletions
+12 -1
View File
@@ -403,6 +403,13 @@ func (s *BillingService) initFallbackPricing() {
// Source: https://docs.z.ai/guides/overview/pricing (USD per 1M tokens)
// 注意:CacheReadPricePerToken 即"缓存命中"价格,CacheCreationPricePerToken 留空(智谱未公开写入价,按 0 处理)。
// GLM-4.6 与 GLM-4.5 在 z.ai 国际版上定价一致;GLM-4.5 国内按 ¥0.8/¥2,汇率换算后约 $0.112/$0.28,与国际版 $0.6/$2.2 不同,本分支采用国际版 USD 口径与现有 Claude/GPT 一致。
// GLM-5.2 与 GLM-5.1 在 z.ai 上同价。
s.fallbackPrices["glm-5.2"] = &ModelPricing{
InputPricePerToken: 1.4e-6, // $1.40 per MTok
OutputPricePerToken: 4.4e-6, // $4.40 per MTok
CacheReadPricePerToken: 0.26e-6,
SupportsCacheBreakdown: false,
}
s.fallbackPrices["glm-5.1"] = &ModelPricing{
InputPricePerToken: 1.4e-6, // $1.40 per MTok
OutputPricePerToken: 4.4e-6, // $4.40 per MTok
@@ -670,8 +677,12 @@ func (s *BillingService) getFallbackPricing(model string) *ModelPricing {
// 匹配策略:长 key 优先(具体模型 → 系列 / 厂商),未知型号不回退以避免误计价。
// 与 DeepSeek 一样采用"白名单"语义:未在本表命中的国产模型 alias 一律不返回兜底价。
// 智谱 GLM(z.ai 公开 SKU:glm-5.1 / glm-5 / glm-5-turbo / glm-4.7 / glm-4.6 / glm-4.5 等)
// 智谱 GLM(z.ai 公开 SKU:glm-5.2 / glm-5.1 / glm-5 / glm-5-turbo / glm-4.7 / glm-4.6 / glm-4.5 等)
// 匹配顺序:先判别最高 tier,再依次降级。
// 注意:带小数点的型号必须排在裸 "glm-5" 之前,否则会被 strings.Contains 抢走。
if strings.Contains(modelLower, "glm-5.2") {
return s.fallbackPrices["glm-5.2"]
}
if strings.Contains(modelLower, "glm-5.1") {
return s.fallbackPrices["glm-5.1"]
}
@@ -158,17 +158,19 @@ func TestGetModelPricing_FallbackWarnPerModelNotGlobal(t *testing.T) {
require.Equal(t, 0, strings.Count(out, "model: GLM-5.2"), out) // 大写经 ToLower 归一,不应单独成行
}
// 回归:glm-5.2 仍解析到 glm-5 兜底价(计费金额不变,防止日志改动掩盖未来计费回归)。
func TestGetModelPricing_GLM52FallsBackToGLM5Price(t *testing.T) {
// 回归:glm-5.2 必须命中自己的兜底价,不能被 strings.Contains("glm-5") 抢成 glm-5 价。
// 历史 bug:兜底表缺 glm-5.2 条目,使用记录按 $1.00/$3.20 计费,比官方 $1.40/$4.40 少收约 27%。
func TestGetModelPricing_GLM52UsesOwnPrice(t *testing.T) {
svc := newTestBillingService()
got, err := svc.GetModelPricing("glm-5.2")
require.NoError(t, err)
require.NotNil(t, got)
// glm-5 base:Input 1e-6 / Output 3.2e-6(见 TestGetFallbackPricing_FamilyMatching)。
require.InDelta(t, 1e-6, got.InputPricePerToken, 1e-12)
require.InDelta(t, 3.2e-6, got.OutputPricePerToken, 1e-12)
// 官方 z.ai 口径:与 glm-5.1 同价(见 TestGetFallbackPricing_FamilyMatching)。
require.InDelta(t, 1.4e-6, got.InputPricePerToken, 1e-12)
require.InDelta(t, 4.4e-6, got.OutputPricePerToken, 1e-12)
require.InDelta(t, 0.26e-6, got.CacheReadPricePerToken, 1e-12)
}
func TestGetModelPricing_UnknownClaudeModelFallsBackToSonnet(t *testing.T) {
@@ -489,6 +491,13 @@ func TestGetFallbackPricing_FamilyMatching(t *testing.T) {
},
// ---- 智谱 GLM(z.ai USD 口径)----
{
name: "glm 5.2 flagship",
model: "glm-5.2",
expectedInput: 1.4e-6,
expectedOutput: floatPtr(4.4e-6),
expectedCacheRead: floatPtr(0.26e-6),
},
{
name: "glm 5.1 flagship",
model: "glm-5.1",
@@ -572,7 +581,7 @@ func TestGetFallbackPricing_FamilyMatching(t *testing.T) {
expectedInput: 0.1e-6,
expectedOutput: floatPtr(0.1e-6),
},
// 关键:5.1 必须先于 5 匹配(避免被 glm-5 抢走)
// 关键:5.1 / 5.2 必须先于 5 匹配(避免被 glm-5 抢走)
{
name: "glm 5.1 vs glm 5 ordering (verbatim 5.1)",
model: "glm-5.1",
@@ -580,6 +589,13 @@ func TestGetFallbackPricing_FamilyMatching(t *testing.T) {
expectedOutput: floatPtr(4.4e-6),
expectedCacheRead: floatPtr(0.26e-6),
},
{
name: "glm 5.2 vs glm 5 ordering (verbatim 5.2)",
model: "glm-5.2",
expectedInput: 1.4e-6, // = glm-5.2 价格(不是 glm-5 的 1e-6)
expectedOutput: floatPtr(4.4e-6),
expectedCacheRead: floatPtr(0.26e-6),
},
{
name: "glm 4.5-air vs glm 4.5 ordering",
model: "glm-4.5-air",