针对 DeepSeek、Qwen、GLM、Kimi 等中国AI API,构建生产级监控以捕获模型版本变化、缓存计费字段、上下文窗口扩展、输出限制调整等 Catalog Drift,避免线上事故。
中国 AI API 的迭代速度快到令人窒息——一个静态的 SDK 配置可能在下次 Sprint 规划会之前就已经过时了。模型名称会变,缓存计费字段会出现,上下文窗口会扩展,输出限制会移动,而价格变更通知往往在财务更新表格之前就悄悄到来。
这并不意味着每个应用都需要一套复杂的 Provider 抽象层。它意味着生产团队需要一个小型控制循环,把模型目录当作实时的运维数据来对待。如果你的 SaaS 产品调用了 DeepSeek、Qwen、GLM、Kimi,或者 AIWave 这类聚合服务,问题不仅仅是"请求是否成功?"更好的问题是:"我们今天交付的模型契约,是否仍然与我们今天检查的 Provider 事实一致?"
本文将带你构建一个实用的模型目录漂移监控器,专门面向 OpenAI 兼容的中国 AI API。目标是趁变化变成故障之前就把它们揪出来:模型版本变了、缓存价格移动了、输出限制比你的摘要器预期的更小了、或者 Provider 增加了一条你的成本估算忽略的高峰时段规则。
我于 2026 年 8 月 13 日检查了各官方源页面。DeepSeek 的价格页面目前列出了 deepseek-v4-flash 和 deepseek-v4-pro,上下文为 1M,并包含了一条将于 2026 年 8 月 16 日生效的高峰/非高峰价格更新公告。Kimi 的 K3 页面列出了 1,048,576 token 的上下文窗口,以及独立的缓存命中、缓存未命中和输出费率。Z.AI 发布了 GLM-5.2 和 GLM-5.1 的 USD 价格,包含缓存输入。QwenCloud 的模型市场列出了 Qwen3.7 Max、Qwen3.7 Flash 和 Qwen3 开源快照的逐模型详情。AIWave 为想在一处发现可用中国模型的应用暴露了一个 OpenAI 兼容的模型列表端点。
下面的监控器不爬取凭证、不存储 Prompt、也不需要真实用户流量。它只存储 Provider 元数据。
大多数 AI 事故都不是戏剧性的 Provider 服务中断。它们是平淡无奇的错配。
一个编码 Agent 向一个模型发送了 90K token,那个模型曾经支持这种请求形状,但配置的别名现在指向了别处。成本预测假设了一个输出费率,而 Provider 已经按缓存命中和缓存未命中拆分定价。一场采购评审比较了上个月的列表价格,漏掉了一条带日期的价格通知。一个工程团队部署了 fallback 链,但从未检查 fallback 是否支持 Function Calling、结构化输出或足够的上下文。
这些问题是可以预防的——只要你把模型元数据提升为头等制品。
上面这张表是有意面向运维的。它不是落地页的市场对比。它是 CI、发布评审和财务对账的输入。
每个 Provider 对目录的描述都不一样。有的发布一张价格表,有的暴露模型页面,而聚合服务通常暴露一个 API 端点。在做任何比较之前,先把这些来源标准化成一个小 Schema。
from dataclasses import dataclass, asdict
from decimal import Decimal
from typing import Optional
@dataclass(frozen=True)
class ModelCatalogRow:
provider: str
model: str
source_url: str
checked_date: str
input_per_mtok: Optional[Decimal] = None
cached_input_per_mtok: Optional[Decimal] = None
cache_write_per_mtok: Optional[Decimal] = None
output_per_mtok: Optional[Decimal] = None
context_tokens: Optional[int] = None
max_output_tokens: Optional[int] = None
rpm: Optional[int] = None
tpm: Optional[int] = None
pricing_note: str = ""
def serialize(row: ModelCatalogRow) -> dict:
data = asdict(row)
for key, value in data.items():
if isinstance(value, Decimal):
data[key] = str(value)
return data
价格用 Decimal。Float 运算做仪表盘勉强可以,但作为计费控制的默认值就很糟糕。同时要存储 Source URL 和检查日期。没有日期的价格不是运维事实;它只是一个即将变成过时假设的谣言。
以下是基于今天检查的官方页面手动维护的种子文件。在生产环境中,你可以把收集步骤放到浏览器自动化、Provider API 或人工审批队列后面。漂移逻辑保持不变。
from decimal import Decimal
CHECKED_DATE = "2026-08-13"
CATALOG = [
ModelCatalogRow(
provider="DeepSeek",
model="deepseek-v4-flash",
source_url="https://api-docs.deepseek.com/quick_start/pricing/",
checked_date=CHECKED_DATE,
input_per_mtok=Decimal("0.14"),
cached_input_per_mtok=Decimal("0.0028"),
output_per_mtok=Decimal("0.28"),
context_tokens=1_000_000,
max_output_tokens=384_000,
pricing_note="Provider page announces new peak/off-peak rates effective 2026-08-16 16:00 UTC.",
),
ModelCatalogRow(
provider="DeepSeek",
model="deepseek-v4-pro",
source_url="https://api-docs.deepseek.com/quick_start/pricing/",
checked_date=CHECKED_DATE,
input_per_mtok=Decimal("0.435"),
cached_input_per_mtok=Decimal("0.003625"),
output_per_mtok=Decimal("0.87"),
context_tokens=1_000_000,
max_output_tokens=384_000,
pricing_note="Provider page announces new peak/off-peak rates effective 2026-08-16 16:00 UTC.",
),
ModelCatalogRow(
provider="Kimi",
model="kimi-k3",
source_url="https://www.kimi.com/resources/kimi-k3-pricing",
checked_date=CHECKED_DATE,
input_per_mtok=Decimal("3.00"),
cached_input_per_mtok=Decimal("0.30"),
output_per_mtok=Decimal("15.00"),
context_tokens=1_048_576,
),
ModelCatalogRow(
provider="Z.AI",
model="glm-5.2",
source_url="https://docs.z.ai/guides/overview/pricing",
checked_date=CHECKED_DATE,
input_per_mtok=Decimal("1.40"),
cached_input_per_mtok=Decimal("0.26"),
output_per_mtok=Decimal("4.40"),
),
ModelCatalogRow(
provider="QwenCloud",
model="qwen3.7-max",
source_url="https://www.qwencloud.com/models/qwen3.7-max",
checked_date=CHECKED_DATE,
input_per_mtok=Decimal("1.25"),
cached_input_per_mtok=Decimal("0.25"),
cache_write_per_mtok=Decimal("1.5625"),
output_per_mtok=Decimal("3.75"),
context_tokens=1_000_000,
max_output_tokens=131_000,
rpm=600,
tpm=1_000_000,
),
ModelCatalogRow(
provider="QwenCloud",
model="qwen3.7-flash",
source_url="https://www.qwencloud.com/models/qwen3.7-flash",
checked_date=CHECKED_DATE,
input_per_mtok=Decimal("0.03"),
cached_input_per_mtok=Decimal("0.006"),
cache_write_per_mtok=Decimal("0.038"),
output_per_mtok=Decimal("0.13"),
context_tokens=1_000_000,
max_output_tokens=131_000,
rpm=15_000,
tpm=5_000_000,
),
]
注意,监控器同时捕获了 Provider 特定的细节和标准化后的值。QwenCloud 区分了隐式缓存读取和显式缓存创建。DeepSeek 有一条带日期的未来定价通知。Kimi K3 的输出价格相对于其缓存命中输入费率来说偏高。Z.AI 为 GLM 发布了缓存输入费率。这些细节不应该被扁平化为单一的"价格"列。
一旦你有了昨天的快照和今天的快照,漂移检测就很直接了。按 Provider 和模型进行比较,然后发出对工程、财务和产品有影响的变化通知。
import json
from pathlib import Path
WATCH_FIELDS = [
"input_per_mtok",
"cached_input_per_mtok",
"cache_write_per_mtok",
"output_per_mtok",
"context_tokens",
"max_output_tokens",
"rpm",
"tpm",
"pricing_note",
]
def load_snapshot(path: Path) -> dict[tuple[str, str], dict]:
if not path.exists():
return {}
rows = json.loads(path.read_text(encoding="utf-8"))
return {(row["provider"], row["model"]): row for row in rows}
def diff_snapshots(previous: dict, current: dict) -> list[dict]:
events = []
all_keys = sorted(set(previous) | set(current))
for key in all_keys:
before = previous.get(key)
after = current.get(key)
provider, model = key
if before is None:
events.append({"severity": "info", "provider": provider, "model": model, "change": "model_added"})
continue
if after is None:
events.append({"severity": "warning", "provider": provider, "model": model, "change": "model_removed"})
continue
for field in WATCH_FIELDS:
if before.get(field) != after.get(field):
severity = "warning" if field.endswith("_per_mtok") or field in {"context_tokens", "max_output_tokens"} else "info"
events.append({
"severity": severity,
"provider": provider,
"model": model,
"change": field,
"before": before.get(field),
"after": after.get(field),
"source_url": after.get("source_url"),
"checked_date": after.get("checked_date"),
})
return events
def write_snapshot(path: Path, rows: list[ModelCatalogRow]) -> None:
payload = [serialize(row) for row in rows]
path.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
关键的设计选择是 Severity 级别。模型被添加到市场是有用的信息。模型从已配置的路由中被移除是发布阻断器。上下文窗口缩减可能破坏用户工作流。缓存价格变化可能扭曲毛利率。一条带日期的定价通知应该在数字变化之前就创建财务和路由评审任务。
快照 Diff 告诉你什么变了。策略检查告诉你你的应用是否仍然能在自己的需求范围内运行。
例如,假设一个 Tier 1 SaaS 团队使用长上下文编码 Agent,并要求:
把它写成代码。保持足够小,让值班工程师在凌晨 2 点也能读懂。
import datetime as dt
def validate_policy(rows: list[ModelCatalogRow], today: str) -> list[str]:
issues = []
today_date = dt.date.fromisoformat(today)
for row in rows:
age = (today_date - dt.date.fromisoformat(row.checked_date)).days
if age > 7:
issues.append(f"{row.provider}/{row.model}: source check is {age} days old")
if not row.source_url.startswith("https://"):
issues.append(f"{row.provider}/{row.model}: source URL is missing or not HTTPS")
if row.context_tokens is not None and row.context_tokens < 128_000:
issues.append(f"{row.provider}/{row.model}: context below 128K")
if row.output_per_mtok is None:
issues.append(f"{row.provider}/{row.model}: output price missing")
if row.cached_input_per_mtok is None and row.context_tokens and row.context_tokens >= 500_000:
issues.append(f"{row.provider}/{row.model}: long-context model has no cached input field")
return issues
把它作为每日任务的一部分运行,在变更模型路由之前再次运行。如果失败了,不要默默更新 SDK。发起一次评审。目的不是阻断每一次变更;而是把不可见的漂移变得可见。
如果你使用直接 Provider 集成,你的监控器应该读取每个 Provider 的公开文档或市场页面。如果你使用 AIWave,你也可以检查 AIWave 的 OpenAI 兼容模型列表端点,并与你关心的 Provider 事实进行比较。
有用的模式是两层:
Provider 事实层:官方模型 ID、定价、上下文、输出限制、缓存字段和通知。
应用路由层:你的产品实际暴露的模型、它们的别名、fallback 顺序和使用策略。
AIWave 可以简化路由层,因为你的应用可以保持一个 OpenAI 兼容客户端、一套 USD 计费关系和一组运维策略,同时仍能在 25+ 个中国模型之间切换。但这不会消除验证的需要。它只是让验证更容易集中化。
以下是对 OpenAI 兼容模型列表的最小路由检查。使用你自己的 base URL,并把密钥放在环境变量中。
import os
import requests
def fetch_openai_compatible_models(base_url: str) -> set[str]:
api_key = os.environ.get("AIWAVE_API_KEY")
if not api_key:
raise RuntimeError("AIWAVE_API_KEY is required")
response = requests.get(
f"{base_url.rstrip('/')}/v1/models",
headers={"Authorization": f"Bearer {api_key}"},
timeout=20,
)
response.raise_for_status()
payload = response.json()
return {item["id"] for item in payload.get("data", []) if "id" in item}
def check_required_routes(available: set[str], required: set[str]) -> list[str]:
return sorted(required - available)
这有意与价格收集分开。生产网关可以在价格页面已变更时暴露一个模型;或者 Provider 页面可以在你的网关使其可用之前添加一个模型。你需要两个事实。
一个好的漂移监控器产生无聊但具体的工单:
"发现 DeepSeek V4 定价通知;请在 2026-08-16 16:00 UTC 之前更新预测。"
"Qwen3.7 Flash 输出费率已变更;请重新运行编码 Agent 成本测试。"
"Kimi K3 输出成本已变更;请审查长上下文报告生成预算。"
"GLM-5.2 缓存输入字段已变更;请更新缓存命中假设。"
"所需的 AIWave 路由缺失;阻断发布直到 fallback 配置被审查。"
工单应该包含 Source URL、检查日期、旧值、新值、受影响的内部路由和负责人。避免"AI 价格已变更"这类通用告警。它们制造了工作,但没有制造清晰度。
对于财务,保持一个紧凑的 CSV 导出。对于工程,在版本控制或对象存储中保持一个 JSON 快照。对于产品,在影响用户面向能力的变更时,在发布评审中总结变更。
在信任这个监控器之前,用与任何运维工具相同的纪律来运行它:
工程工作量很小。养成习惯才是困难的。模型目录现在是生产配置的一部分。显式追踪它们的团队会走得更快,因为每条路由、fallback 和成本估算都从当前事实出发,而不是从过时的笔记出发。
中国 AI 模型 API 有价值,正是因为这个生态系统非常活跃。新版本、更大上下文、缓存规则和定价更新都是正常的。模型目录漂移监控器让你从这个速度中受益,而不会让它给你的 SDK、你的用户或你的账单审查带来意外。