model-auto-fallback-chain · ZH · 2026-11-03

把 model=auto 当兜底层:首选后端失败之后发生了什么

解释 model=auto 作为兜底层的工作方式:当首选后端失败或不可用时,auto 如何重试与降级到其他模型后端,以及如何从响应字段中判断请求是否已被路由到备选后端。

auto 不是一个模型,而是一条路由规则

把 model 设成 auto 时,你并没有选中某个具体模型,而是把“选哪个后端、失败之后怎么办”交给了聚合网关。理解这一点,后面所有行为都顺理成章:网关先按自己的能力选出首选后端,把请求发出去;只有当首选这条路走不通时,才会启动兜底逻辑。

一次请求的典型路径

  1. 网关根据请求内容与当前可用性,选出首选后端。
  2. 向该后端发起请求。
  3. 成功则原样返回;对调用方而言,整个兜底过程是不存在的。
  4. 失败则进入错误分类与重试/降级流程。

关键在于第 4 步:并不是所有失败都值得兜底。

哪些失败会触发兜底

网关通常会区分两类错误:

  • 可重试类:上游临时不可用、连接中断、超时、限流(429)、上游 5xx。这类错误换一个后端或稍等重试就可能成功,属于兜底的适用场景。
  • 不可重试类:请求本身有问题,比如参数非法、上下文超长、鉴权失败、内容被上游策略拒绝。这类错误换任何后端都会以类似方式失败,重试只是浪费时间和额度,因此应直接把错误返回给调用方。

所以看到一次 auto 请求返回错误,先判断错误属于哪一类:如果是不可重试类,说明兜底还没来得及(也不应该)生效。

重试与降级的区别

这两个动作经常被混为一谈,但语义不同:

  • 重试:还是同一个后端,再试一次。适合瞬时抖动、连接层失败。
  • 降级:换一个后端继续。适合当前后端持续不可用,或者明确返回了不可用信号。

实践中两者往往组合使用:同后端短暂重试若干次仍失败,再切到备选后端;切过去之后如果备选也失败,可能继续在备选上重试,或再换下一个。整个过程的次数是有上限的,否则一次请求会无限拖长。

兜底之后,你拿到的可能不是你以为的模型

这是 auto 最需要留意的副作用:请求成功了,但答案是另一个后端给的。不同模型在风格、格式遵循度、工具调用能力上存在差异,如果你的业务对输出格式有强依赖,就需要知道自己有没有被降级。

可以从几个地方判断:

  • 响应中的模型标识字段:多数兼容 OpenAI 协议的实现会在响应体里回填实际使用的模型名。如果这个字段显示的不是你预期的那个,说明已经发生了路由或降级。
  • 响应头:部分网关会在头里附上重试次数、最终后端之类的信息。有就优先读它,比解析正文更稳。
  • usage 字段:如果某次请求的 token 计数与你平时同 prompt 的结果明显不同,可能是换后端了——不同模型的分词方式不同。这只是线索,不是证据。
  • 日志与用量明细:在控制台按请求查看时,通常能看到该次请求最终落在哪个后端,适合事后排查。

建议的工程做法

  • 不要在关键链路上默认用 auto。需要稳定输出格式、严格工具调用、可复现评测的场景,显式指定具体模型,把不确定性挡在外面。
  • 把 auto 用在容错优先的地方:批量离线任务、草稿生成、非结构化摘要这类“成功即可、是谁答的不重要”的负载。
  • 记录实际后端。把响应里的模型标识和重试信息写入自己的日志,出问题时能快速判断是模型能力问题还是路由问题。
  • 区分错误类型再重试。自己在客户端再加一层重试时,只对可重试类错误重试;对参数错误做盲目重试只会加倍消耗额度。
  • 注意超时预算。兜底意味着一次逻辑请求可能包含多次上游尝试,客户端超时要留出余量,否则网关还在降级,你这边已经断了。

关于计费

兜底不改变计费口径:调用方仍按所用模型的官方价 ×1.3 扣费。如果发生了降级,实际计费会跟随最终承接该请求的后端,而不是你最初以为的那个。这也是建议记录实际后端的原因之一——便于对账。

一句话总结

auto 的兜底只在“换条路还有希望”的错误上生效;判断是否被降级,看响应里的模型标识和响应头,而不是靠猜。对输出一致性有要求的场景,显式指定模型比依赖兜底更可靠。