别名本身不会「坏」,它会静默指向新版本:请求成功返回 200,但模型能力、格式习惯、token 费用均已改变,三周后才可能被发现。
响亮的失败是 404,响应体带着类似 model_not_found 的错误码,提示模型不存在或你无权访问。在 Azure 上,对等的 404 报的是部署名称而非模型名称,这是另一个诊断陷阱:部署名称是你自己指定的字符串,所以错误信息里没有任何证据能说明是哪个底层模型版本过期了。对这个响应的通用处理方式就是"模型未找到"错误;本文要探讨的是:为什么一个 alias 会产生这个错误。
另一种安静的失败才是烧钱的那个。Alias 没有坏掉——它搬家了。你的请求依然成功,依然返回 200,但现在跑在另一个模型版本上了,有不同的格式化习惯、不同的拒绝面和不同的 token 账单。没有人收到告警。三周后有人发现摘要变长了。这和静默模型更新的机制一样,区别在于这里是你自己选择了这层间接映射。
Alias 是一个在请求时由服务器解析的名称。每个部署环境里都有两种 alias。
供应商维护的浮动指针。 一个裸的模型族名称,解析到供应商当前认为是默认版本的那个带日期的快照。用起来方便,而且是设计好的——它会在你脚下发生变化。
你自己创建的部署名称。 在 Azure 及类似平台上,你代码里的字符串是你自己为部署配置中某个(模型,版本) pair 起的别名。你的代码现在完全与模型名称隔离了,这正是它的意义所在,同时也意味着你代码里根本看不到实际跑的是哪个模型。
第三种情况藏在微调里:经过微调的模型标识符是 base model 的 alias。当 base 模型退役时,衍生品也跟着一起退役,而按名称列出你所有模型的清单不会告诉你这件事,因为微调后的标识符看起来仍然完全合法。
响应已经告诉了你实际跑的是哪个模型。Chat 风格的响应带有模型标识符,对于 alias 而言,那个标识符是解析后的快照而非你发送的字符串。所以要把两者都记录下来,作为两个独立字段,每条请求都记。
# 在调用 site 记录,而不是在某个可以被绕过的包装器里
resp = client.chat.completions.create(model=REQUESTED, messages=msgs)
log.info("llm_call",
model_requested=REQUESTED, # 代码请求了什么
model_resolved=resp.model, # 实际跑的是什么
request_id=resp.id)
先做一个合理性检查:如果你认为某个名称是 alias,但 model_resolved 总是恰好等于 model_requested,那你很可能是在包装器里回显了自己的输入而不是读取响应。在一个你确定是 aliased 的调用上验证这一点,然后再信任这个审计逻辑。
然后审计就是一条定时查询:按 pair 对昨天的流量分组,与前一天做 diff。
SELECT model_requested, model_resolved, count(*)
FROM llm_calls
WHERE ts >= current_date - 1
GROUP BY 1, 2;
-- 当某个 model_requested 昨天只有唯一一个 model_resolved,
-- 今天变成了不同的或额外的 model_resolved 时报警。
这个告警在指针移动的当天就会触发。对比一下另一种情况——等到有人抱怨输出质量才开始察觉——到那时你已经有好几周的混合流量了,没有干净的前后对比可供分析。如果你维护着评测套件,这个告警也是触发它的正确时机:这正是捕获静默模型更新后回归的标准场景。
上面的审计需要这一个字段——解析后的模型标识符——在所有调用中一致记录,包括每月运行的批处理任务和有人调度过的 notebook。网关是实现这一点最便宜的地方,因为每条请求都会经过网关,无论哪个服务发起了调用或用了哪个 SDK。给十二个服务分别做埋点,最终得到的是十一个服务埋了点。
在部署可配置的地方,你选择的策略决定了你会遇到两种失败中的哪一种。Microsoft 的 Foundry Models 文档将选项描述为:部署设置为退出自动模型版本升级,这需要手动升级且在模型退役时停止工作;部署设置为在新默认版本可用时升级,这会自动转到新的默认版本;以及部署设置为在当前版本过期时升级,这会在其当前版本退役时更新。参见 Microsoft Learn 上的模型版本控制。
把这个理解为对失败模式的选择,而不是一个配置细节。选择不自动升级获得了可重现性,但给自己埋下了一个必须自己追踪的宕机日期。选择自动升级获得了连续性,但得到了静默的行为改变。没有第三种"什么都不发生"的选项,而常见的错误是每个部署稀里糊涂选了不同的策略,然后在故障时才发现这个大杂烩。
合理的做法是:固定版本,然后把退役日期和解析标识符告警配对成一条日历项。单纯固定版本只是把一个慢性问题变成了一个你没写下来的硬截止日期。
对环境中的每个模型字符串做盘点。应用代码、配置文件、环境变量、基础设施模板、prompt 注册表、notebook,以及任何跑在 cron 上的东西。总是那个季度任务出问题。
将每个字符串分别对着供应商的模型列表解析一下,看它是不是 alias,再对着供应商发布的退役表解析一下,看它还有多久退役。
加上请求/解析的日志,让它跑一周再做任何改动,这样你就有了一个每个 alias 当前解析到哪里的基线。
逐个服务地将每个 alias 固定到一个带日期的快照上,并把固定位置记到退役日历会读的地方——一个单独的 constants 模块是常见答案,而且文档也应该从同一个模块生成。
安排好解除固定的时机。一个没有计划审查的固定版本,就是让你在退役日期到来时毫无准备;用 feature flag 标记模型版本(就像通过弃用标记一个模型版本一样),让最终的迁移变成一个配置变更而不是一次部署。
策略选项名称、错误码和退役计划是由供应商设定的,会变动。上面的措辞是链接文档在编写时使用的;在把它们写进操作手册之前,先在你自己的供应商控制台里确认当前的名称。