轮换要带健康状态记忆

**多 key / 多模型轮换不能盲目串行遍历:要记住哪些组合刚坏过、按错误性质设冷却、并给每次尝试设超时,否则一轮请求会把函数执行预算烧光,用户等满超时后仍然失败。**

一、盲目串行的算术

4 key × 3 模型 = 12 组,上游单次约 8 秒 → 全试一遍 96 秒,直接撞上 Vercel maxDuration: 60。表现是:

连续 3 次:60.003s 超时 → 429

比不轮换更糟 —— 用户等 60 秒然后失败。

二、健康状态记忆

进程级内存表:health: Map<"key::model", {until, status}>。

冷却时长按错误性质区分(这是关键,不能一律 30 秒):

错误冷却理由
429 配额耗尽10 分钟额度按天重置,几秒内不可能恢复
503 模型过载60 秒通常几十秒恢复
403 / 4045 分钟凭据或模型名问题,短期不自愈
500 / 502 / 504、网络抛错30 秒网关抖动

排序:健康组合优先,冷却组合排后而不是删除 —— 健康表是临时的,全部冷却时仍要有兜底可试。

const ordered = [...combos.filter(c => !c.cooling), ...combos.filter(c => c.cooling)];

单次尝试超时 8 秒,防止一个慢组合拖死整轮;最后一组不加超时(反正没有下一组,不如多等一会)。成功即 markSuccess 清除冷却,稳定态下第一组就命中,只需一次上游往返。

三、边界:无状态部署让健康表打折

Vercel 是无状态的,每次请求可能落在不同实例,健康表不共享。所以冷却只是「本实例的经验」,效果是概率性的 —— 实测同样逻辑耗时在 1.7s ~ 31s 之间波动。

结论:健康记忆能显著降低最坏耗时,但不能替代跨实例的共享状态(真要稳定就得放 Redis / KV 之类)。

相关

  • 账号冷却不要按错误码一刀切(把网络级抖动误当账号级故障的反例)
  • Agent模型接入与额度机制(额度池、轮换为何"一下子满了")
  • 多账号模型路由机制(上游自带账号冷却的做法)
  • 口径先于数值(429 与 503 不能混为一类)