Fallback de modelos en agentes: otro modelo, no el mismo 429
Resumen
Un fallback cambia de modelo o de proveedor cuando el primario no responde. Distinto de reintentos (misma llamada) y del circuit breaker (cortar la dependencia). Vercel AI Gateway models[] + Cloudflare Universal endpoint y cf-aig-step. Cero fallback en 401/403 ni en spend limit. El modelo que contestó va al log, no al prompt.

Qué resuelve
Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.
Un agente no “se cae el modelo”. Se cae una llamada: 503, 529, timeout al primer byte, o un 429. Si reintentas el mismo modelo, eso es reintentos. Si cortas la dependencia, eso es circuit breaker. El fallback cambia de modelo o proveedor cuando el primario no sirve esta petición.
Vercel AI Gateway (docs, 2026-07-28) lo dice en una línea: configure model failover to specify backups that are tried in order if the primary model fails or is unavailable. Cloudflare AI Gateway (docs, 2026-04-20) hace lo mismo en el Universal endpoint: un array de proveedores y el header cf-aig-step te dice quién contestó.
Contrato: cadena corta (2–3 modelos). Fallback solo en fallo transitorio o timeout. Cero fallback en 401/403 ni en spend/quota. El modelo efectivo se loguea; no se reescribe el system prompt. El backup tiene que poder hacer las tools de esa llamada.
La regla de oro: misma petición, otro cerebro
| Capa | Qué cambia | Qué no cambia |
|---|---|---|
| Retry | Espera + jitter. Mismo modelo, mismo request | El proveedor |
| Fallback | Modelo o proveedor siguiente de la lista | El turno, las tools, el tenant |
| Breaker | Deja de llamar esa dependencia | El resto del agente |
| Kill switch | Apaga el sistema | Nada: no hay turno |
El retry asume que el mismo endpoint va a despertar. El fallback asume que ese modelo no va a servir ahora. Mezclarlos sin tope es una factura: Cloudflare documenta retries con máximo 5 intentos y delay máximo 5 s (request handling, 2026-06-15). 3 modelos × 5 retries no es resiliencia: es un timeout del webhook.
Qué códigos sí caen al backup (y cuáles no)
OpenAI (error codes, 2026-09-06) y Claude (API errors, 2026-09-06) no son un interruptor único. Lee el código, no el meme de “cualquier 4xx”.
| Señal | ¿Fallback? | Por qué |
|---|---|---|
500 OpenAI / 500 Claude api_error | Sí, tras 1 retry corto | Fallo del servidor. El backup puede estar sano |
503 OpenAI server_is_overloaded / 529 Claude overloaded_error | Sí | El modelo pedido está saturado. Otro modelo (u otro proveedor) es el punto |
Timeout al primer byte (Cloudflare cf-aig-request-timeout) | Sí | El primario no arrancó. No esperes el stream eterno |
429 rate limit con Retry-After | Primero espera; fallback si el techo es del modelo | Pace + header. Si el techo es de org, el backup del mismo vendor también 429 |
429 OpenAI credit_balance_exhausted / spend / usage limit | No | Retrying billing, spend, or quota errors won't restore API access |
| 400 Claude por spend limit de org/workspace | No | No es un request mal formado: es techo. Sube el límite o degrada el producto |
| 401 / 403 | No | Auth rota. Rotar la clave, no el modelo |
| 400 schema / 413 request too large | No | El backup no arregla un JSON inválido ni un PDF de 40 MB |
Regla práctica: fallback = el primario no está disponible. No es “el primario contestó mal y quiero otro tono”. Eso es un eval, no un failover.
Cómo se declara la cadena (sin magia)
Vercel: model + providerOptions.gateway.models
El primario va en model. Los backups van en models[], en orden. Si un modelo tiene varios proveedores, order elige Azure antes que OpenAI para ese modelo; si todos fallan, pasa al siguiente de models.
const result = streamText({
model: "anthropic/claude-fable-5",
prompt,
providerOptions: {
gateway: {
models: ["anthropic/claude-opus-5", "google/gemini-3.1-pro-preview"],
},
},
});
La respuesta sale del primero que gana. El metadata modelAttempts lista cada intento con canonicalSlug (creator/model-name) y modelId del proveedor (provider:model). Loguea success, statusCode y responseTimeMs. No vuelques el array al LLM.
Cloudflare: array en el Universal endpoint + cf-aig-step
El body es un array. El primero es el primario; cada objeto extra es un fallback. Cloudflare dispara el siguiente ante error o timeout. El header cf-aig-step es el contrato:
cf-aig-step:0— ganó el primariocf-aig-step:1— ganó el segundocf-aig-step:2— ganó el tercero
Sin ese header (o sin modelAttempts en Vercel) no sabes si el backup está cargando el 40 % de los turnos. Eso no es “alta disponibilidad”: es un modelo caro que ya no corre.

El backup no es un alias barato
Tres trampas que rompen agentes aunque el HTTP sea 200:
- Tools distintas. Si el primario tiene
create_invoicey el backup no hace function calling, el turno “tuvo éxito” y el efecto no ocurrió. El backup acepta las mismas tools, o degrada a solo lectura. - Contexto y límite. Un fallback a un modelo con ventana más chica recorta el historial a ciegas. Recorta tú, con presupuesto, o no lo pongas en la cadena.
- Costo y cuota. El backup “barato” que se dispara en cada 429 de rate limit puede agotar el techo del segundo proveedor. Eso vive en presupuestos por tenant, no en un
catchanónimo.
Cadena típica de un bot de soporte, no un ranking de blogs:
- Primario: el modelo con el que evaluaste (tools + tono).
- Backup mismo vendor: variante más pequeña o menos saturada.
- Backup otro vendor: solo si el contrato de tools cabe. Si no cabe, degrada a mensaje humano / cola, no a un modelo que inventa la tool.
Timeout del primario: AbortSignal en tools HTTP y el timeout del gateway. Cloudflare mide el timeout al primer byte: si el SSE abre y se queda mudo, corta el stream; no agregues el cuarto modelo.
Qué loguear (y qué no meter al prompt)
Mínimo por turno, fuera del contexto del modelo:
primary_model,effective_model,step(cf-aig-stepo índice demodelAttempts)statusCodedel fallo que disparó el salto- latencia por intento
tenant_id(para cruzar con cuotas)
Prohibido: pegar el token, el body completo, o un dump de modelAttempts en el system prompt. El modelo no necesita saber que es el plan B. El operador sí: si step>=1 sube de golpe, el primario está enfermo o mal tipado, no “el usuario pregunta difícil”.
Si el breaker del primario está Open, no dispares fallback en loop contra el mismo vendor: el backup 2 no arregla una outage de región. Ahí el fallback útil es otro proveedor o la degradación del producto.

Checklist
- Lista de 2 o 3 modelos, ordenada, en config — no en el prompt.
- Fallback solo ante 5xx, 503/529, timeout de primer byte, o 429 de modelo tras respetar
Retry-After. - Cero fallback en 401/403, spend/quota, 400 de schema, 413.
- El backup implementa las mismas tools o degrada el producto de forma explícita.
- Log de
effective_model+steppor turno; alerta sistep>=1supera tu umbral (empieza en 10 %). - Tope: 1 retry corto por modelo, luego salto. No 5×3.
- El humano mueve el kill switch; el fallback no apaga el bot.
FAQ
¿Fallback es lo mismo que routing barato→caro? No. Routing por costo elige modelo antes de fallar. Fallback elige después de un fallo. No los mezcles en el mismo array sin saber cuál regla ganó.
¿Puedo poner el mismo modelo en dos proveedores? Sí, y Vercel lo cubre con order (Azure luego OpenAI para el mismo slug). Eso es failover de proveedor, no de cerebro. Sigue siendo un fallback: cambia el host, no el contrato de tools.
¿El SDK de Claude ya reintenta solo? Sí: transitorios (conexión, rate limit, 5xx) con backoff, dos veces por defecto, honrando retry-after. Eso no es tu cadena de modelos. Si dejas el SDK en 2 retries y 3 modelos en el gateway, multiplica. Baja retries del SDK a 0 o 1 cuando el gateway ya hace failover.
¿Dónde vive esto? En el cliente HTTP (gateway o wrapper), no como texto en el hub de operación. El curso arranca el loop en /curso/instalar-agente; esta guía evita que un 503 mate el turno.
El fallback bueno es aburrido: lista corta, un header de quién ganó, backup que todavía llama tus tools. El malo es un catch que prueba “cualquier modelo” hasta el silencio.
Lecturas relacionadas
Sigue explorando AgentOps y otras piezas para builders.

Shadow, canary y feature flags en agentes: soltar sin redeploy

Dead-letter queue en agentes: el mensaje que no debe reintentarse

SLO y error budget en agentes: 4 SLIs, burn rápido/lento y política 50/100
