auto-routing-batch-worker · ZH · 2026-10-09

批处理里的 model=auto:跑一条队列时模型会一直不变吗

解释在批量队列里反复使用 model=auto 时为什么可能发生模型漂移,给出检测与记录漂移的实操方法,并说明哪些场景应改为钉死具体模型以保证可复现。

问题从哪里来

聚合站通常把 model=auto 实现成一个路由别名:请求进来时由服务端决定这次交给哪家上游、哪个版本。对单次对话,这种“随便挑一个好用的”很省事。但把它放进一条批量队列里反复调用,就会冒出一个问题:同一个 auto,第一次和第五百次落到的可能是不同模型。

根本原因是 auto 不是模型名,而是一个路由策略。策略的输出取决于当时的可用性、配额、延迟、上游健康度等运行时状态。这些状态在一条跑几分钟甚至几小时的队列里是会变的。

为什么队列里更容易漂移

单次请求里,路由只做一次决策。批量队列里,你实际上是把同一个决策重复问了很多遍,而每次问的时候环境未必一样:

  • 某些上游在高峰期被限流或临时不可用,路由会把请求挪到备选。
  • 贡献 key 池是动态的,某个 key 被撤下或额度用尽,可用于承接该请求的上游集合就变了。
  • 上游可能上线新的模型版本,路由的候选列表随之更新。
  • 同一个请求的重试走的是新的一次路由,不一定回到原来那家。

所以答案很直接:同一条队列上反复调用 auto,不保证落在同一家。它甚至连“大概率同一家”都不该被当成前提。

怎么发现模型漂移

漂移本身不可怕,可怕的是你不知道它发生了。常见的检测手段:

  • 看响应里的模型字段。 大多数兼容 OpenAI 格式的接口会在返回体中带一个 model 字段,记下每次实际命中的模型名,而不是只记你请求时写的 auto。
  • 保留请求 ID / 上游标识。 如果响应头或元数据里有请求标识,一并落盘。事后排查时它是唯一的锚点。
  • 在日志里做分组统计。 跑完后按 model 字段分组,看一条队列是否被拆成了两三种模型。混在一起本身就是信号。
  • 抽样人工比对。 对同一批输入,挑几条用具体模型重跑,比较输出风格与格式是否一致。格式类任务(JSON、固定字段)对模型差异尤其敏感,往往最先暴露。

对批处理来说,最实用的做法是:每一行结果都带上实际命中的模型名。这样下游无论做什么分析,都能先按模型切片。

什么时候必须钉死具体模型

auto 适合探索、适合对一致性不敏感的杂活。但下面这些场景,应该改成明确写死某个模型:

  • 可复现性。 你要做评测、对比实验、或需要在几天后重跑同一批输入得到可比结果。
  • 输出结构强约束。 下游有严格解析逻辑,换个模型就可能字段缺失或格式跑偏。
  • 成本可预测性。 不同模型单价不同,队列规模大时,混用会让成本核算失去意义(本站按官方价 ×1.3 扣费,单价差异会直接体现在账单上)。
  • 回归对比。 你正在验证一次 prompt 改动是否有效,此时模型是必须控制的变量。

反过来,如果任务只是“把这段文本粗略归类”且你只关心大致结果,auto 反而能帮你在上游波动时继续把队列跑完。

一个可落地的队列写法

把模型选择从“隐式”变成“显式”,是避免漂移麻烦的关键。可以按这个顺序组织:

  1. 队列配置文件里为每个任务写明 model。需要弹性时再显式写 auto,而不是默认。
  2. 每行结果连同实际命中的模型名、请求标识一起写入输出。
  3. 队列结束后做一个汇总:按模型分组计数,和预期分布对比。
  4. 如果发现某条本该固定的队列出现了多种模型,检查是不是重试逻辑或中间环节偷偷用了 auto。

重试要注意的点

重试是最容易被忽略的漂移来源。你在外层包了一层“失败就重试”,但重试请求对服务端来说是新的一次路由,可能落到完全不同的上游。如果你的重试是为了拿到同一个模型的结果,那重试时也应该带上具体模型名,而不是继续用 auto。

小结

model=auto 是路由别名,不是模型身份。它在单次调用里很方便,但在批量队列里会随上游状态变化而漂移。想吃掉这个不确定性,做法很朴素:记录实际命中的模型、按模型切片分析、在需要可复现或结构稳定的场景里把模型钉死。把 auto 当成一个有意的选择,而不是默认值,队列的行为就会可控得多。