Módulo 6: Fallos a escala — backoff, circuit breakers y rate limits
Módulo 6: Fallos a escala — backoff, circuit breakers y rate limits
Descripción
El Módulo 5 te dio un gate: un harness de regresión que corre un set fijo de casos contra el agente de Reservo y falla el build cuando algo se rompió. Ese gate responde una pregunta puntual — "¿este agente, tal como está hoy, sigue comportándose como esperamos?" — pero da por sentado algo que este módulo pone en duda: que las herramientas del agente responden. En producción, no siempre responden. Una tool que hoy funciona perfecto puede, mañana, empezar a fallar — una dependencia externa caída, una red saturada, un servicio que devuelve error tras error durante quince minutos seguidos. Y por encima de eso, hay un tipo de fallo que ninguna tool del agente puede causar ni resolver: el propio proveedor del modelo, la API de Claude, puede responder con un 429 cuando tu organización excede su cuota de peticiones por minuto.
Este módulo construye la disciplina que le falta al agente de Reservo para sobrevivir a esos dos tipos de fallo sin desperdiciar dinero, sin colgarse, y sin mentirle al usuario. Tres piezas, en orden creciente de alcance: reintentos con backoff acotado (cuando una tool falla, reintentarla con una espera que crece exponencialmente, hasta un tope duro); un circuit breaker por tool (cuando una tool lleva fallando de forma sostenida — no un hipo, una caída real — dejar de llamarla durante un rato, y probar de nuevo más tarde); y el 429 de la propia API de Claude (un caso que ninguna guía genérica de resiliencia cubre, porque no es una dependencia HTTP cualquiera — es el proveedor del LLM que sostiene todo el sistema). Vas a construir las tres, ejecutarlas contra fallos simulados de forma determinista, y cerrar con un agente de Reservo que sigue funcionando — con criterio, no a ciegas — cuando book_room se cae en medio de un día real de tráfico.
Conexión con el módulo
Este módulo se apoya directamente en dos piezas que ya construiste, sin tocar ninguna: el runner run_reservo_agent de agent-fundamentals Módulo 8, y el manejo básico de errores de tool de esa misma guía, Módulo 7. Ese Módulo 7 ya resolvió una pregunta — "¿qué hace el agente cuando ESTA llamada a ESTA tool falla, ahora mismo, dentro de este run?" — con un reintento simple, sin backoff, capturado en call_with_retries. Este módulo hace una pregunta distinta, posterior: "¿qué hace el SISTEMA cuando esa tool lleva fallando, run tras run, durante un buen rato?" La respuesta no vive dentro de una sola llamada — vive en un estado que persiste entre runs, algo que el call_with_retries de esa lección, acotado a una única invocación, no puede tener por diseño.
Dónde estamos en el ecosistema
Agentes en producción — operar el agente de Reservo
├── Módulo 1: Por qué operar es distinto de construir
├── Módulo 2: Logging estructurado y trazado de un run
├── Módulo 3: Medir costo y tokens por run
├── Módulo 4: Medir latencia con honestidad
├── Módulo 5: Evals de regresión como gate de producción
├── Módulo 6: Fallos a escala — backoff, circuit breakers y rate limits ← ESTÁS AQUÍ
│ → Reintentos con backoff acotado (modelado, sin reloj real);
│ un circuit breaker por tool con estado ENTRE runs;
│ el 429 de la propia API de Claude; degradación elegante
├── Módulo 7: Versionado y rollout seguro
└── Módulo 8: Proyecto — el agente de Reservo en producción
Los cinco módulos anteriores construyeron, en orden, cuatro capacidades: observar un run completo con logging estructurado y un trace_id (Módulo 2); medir cuánto costó y cuánto tardó (Módulos 3 y 4); y gatear — decidir, con un criterio determinista, si el agente sigue comportándose como se espera (Módulo 5). Las cuatro capacidades comparten una premisa silenciosa: que cuando el agente llama a una tool, la tool responde. Este módulo es el primero que rompe esa premisa a propósito, y construye la tercera disciplina completa de esta guía — endurecer — antes de que el Módulo 7 cierre el ciclo con versionar.
El problema, en una frase
Un agente que reintenta ciegamente cada vez que una tool falla no es resiliente — es ruidoso. Sigue metiendo el mismo pedido en un servicio que ya sabemos que está caído, gasta tokens y tiempo en cada intento fallido, y —lo peor— no aprende nada entre un run y el siguiente. Cada usuario que llega mientras la tool está caída paga, de su bolsillo, el costo completo de descubrir esa caída desde cero. Este módulo resuelve eso con tres capas, cada una construida sobre la anterior:
1. BACKOFF ACOTADO -> dentro de un intento, espera cada vez mas antes
(Leccion 3) de reintentar, con un tope duro de intentos.
2. CIRCUIT BREAKER -> entre runs, recuerda que una tool esta muerta y
(Lecciones 4-5) deja de llamarla -- hasta que un chequeo
periodico confirma que revivio.
3. DEGRADACION -> mientras el breaker esta abierto, el agente NO
ELEGANTE se cae ni miente -- responde con claridad,
(Leccion 7) rapido, sin tocar la tool muerta.
Y una cuarta pieza que corre en paralelo a las tres, porque es un tipo de fallo completamente distinto: el 429 de la propia API de Claude (Lección 6) — el proveedor del modelo, no una tool del agente, pidiéndote que esperes.
La analogía que sostiene todo el módulo: el interruptor térmico de tu casa
Imagina el tablero eléctrico de tu casa. Cada circuito tiene un interruptor térmico — ese que "salta" cuando algo va mal. Si conectas un secador de pelo con un cortocircuito y el interruptor no existiera, cada vez que lo enchufas la corriente sigue fluyendo hacia un aparato roto, y en algún momento algo se quema de verdad — el cable, el tomacorriente, la instalación completa. El interruptor existe exactamente para evitar eso: en cuanto detecta que algo no anda bien en ESE circuito — no en toda la casa, en ESE circuito puntual — salta (se abre) y corta la corriente ahí. El resto de la casa sigue funcionando con normalidad. Después de un rato, alguien revisa, y si el problema se resolvió, vuelve a bajar la palanca — el circuito vuelve a conducir.
Reintentar sin un interruptor es seguir metiendo el secador roto al enchufe, una y otra vez, esperando que esta vez no salte chispa. El circuit breaker de este módulo es, literalmente, ese interruptor aplicado a una tool del agente: si book_room hace corto —falla una y otra vez—, el breaker salta (se abre, OPEN) y corta las llamadas a ESA tool, sin afectar a get_quote ni a list_rooms. Después de un rato prudente, deja pasar una llamada de prueba (HALF_OPEN) — como alguien que va a revisar el tablero—. Si esa prueba sale bien, el circuito vuelve a la normalidad (CLOSED); si sigue fallando, vuelve a saltar y espera otro rato. Guarda esta analogía — la vas a usar, con el vocabulario exacto CLOSED/OPEN/HALF_OPEN, en las lecciones 4 y 5.
🛑 Frontera doble — léela antes de escribir una línea de código
Este módulo tiene el solape más denso de toda la guía, y hay que trazarlo con precisión antes de empezar, porque se repite en cada lección.
Frontera 1 — hacia agent-fundamentals Módulo 7 (dentro-del-run vs. entre-runs)
agent-fundamentals Módulo 7 ya construyó call_with_retries(fn, *args, max_retries=3, **kwargs): un reintento simple, sin espera entre intentos, acotado por un tope duro, que distingue un fallo transitorio (ConnectionError, vale la pena reintentar) de un error de validación (nunca cambia, no vale la pena). Ese mecanismo sigue existiendo, sigue siendo correcto, y este módulo no lo reconstruye. La frontera exacta:
agent-fundamentalsM7 resuelve: "esta llamada a esta tool, ahora mismo, dentro de este run — ¿reintento?" Su alcance es un solo run; su memoria dura lo que dura esa llamada.- Este módulo (M6) resuelve: "esta tool lleva fallando run tras run — ¿sigo llamándola?" Su alcance cruza runs; su memoria —el estado del circuit breaker— vive en un objeto que persiste mientras el proceso está vivo, más allá de cualquier run individual.
La Lección 3 de este módulo escala el reintento de M7 —le agrega la pieza que esa misma lección dejó pendiente a propósito ("esta lección no la implementa en detalle")—: el backoff exponencial entre intentos. La Lección 4 en adelante construye algo que M7, por diseño, no podía construir: memoria entre runs.
Frontera 2 — hacia resilience-and-reliability-patterns-guide (vocabulario reusado, alcance angosto)
El vocabulario completo de circuit breakers —los estados CLOSED/OPEN/HALF_OPEN, backoff con jitter aleatorio real, bulkheads, degradación elegante y load shedding medidos a fondo con exhaustion de threads y retry storms— es el contenido completo de resilience-and-reliability-patterns-guide (ecosistema de arquitectura de software, caso Mercado — microservicios HTTP genéricos, sin relación con LLMs). Esa guía es la fuente canónica de ese vocabulario, y este módulo lo reusa, citándola explícitamente, sin repetir su desarrollo. La diferencia de alcance es angosta y precisa:
- Esa guía construye un circuit breaker para cualquier dependencia HTTP de un sistema distribuido genérico, con backoff+jitter aleatorio real (con semilla fija para reproducibilidad de sus propios experimentos) y lo mide con exhaustion de pool de threads, retry storms, bulkheads.
- Este módulo construye un circuit breaker por tool de un agente, aplicado únicamente a la capa de tool-calls (Lecciones 4-5) y al
429del proveedor del LLM (Lección 6, un caso que esa guía nunca cubre porque no es HTTP genérico — es el rate limit de la API de Claude). El backoff de este módulo es modelado y determinista — nuncarandom, nuncatime.sleep()real — porque el resto de esta guía completa exige reproducibilidad byte a byte en cada bloque "Qué esperar".
Este módulo nunca construye bulkheads, degradación elegante a fondo ni load shedding — esos temas quedan íntegros en la guía hermana, nombrada explícitamente donde corresponde (Lección 7). Cuando necesites la versión completa y medida de estos patrones —o resiliencia para un sistema que no involucra un LLM—, esa es la guía a la que ir.
🛑 Regla dura de esta lección (y de todo el módulo)
Toda la ingeniería de resiliencia de este módulo —el reintento con backoff, la máquina de estados del circuit breaker, la simulación del 429— se ejecuta de verdad, con Python 3.14.0, y cada bloque "Qué esperar" muestra la salida real de haber corrido ese código. Tres restricciones duras, heredadas del resto de esta guía y aplicadas aquí con especial cuidado:
- El backoff es modelado, nunca real. Vas a ver una función que calcula
delay = base * 2**intentoy la muestra por pantalla — nunca vas a vertime.sleep(delay). Si esta guía durmiera de verdad en cada reintento, cada ejemplo tardaría segundos reales en correr y el resultado dejaría de ser reproducible byte a byte de una máquina a otra. La lección que importa —cuánto crece la espera, y por qué eso protege a una tool caída— se entiende igual de bien viendo el número calculado que esperándolo de verdad. - Sin
random. Si en algún punto se menciona jitter —la técnica de sumarle una variación aleatoria al backoff para que muchos clientes no reintenten todos en el mismo instante—, se nombra y se explica, pero nunca se implementa conrandomen esta guía. La razón es la misma de siempre: un número aleatorio en un bloque "Qué esperar" rompe la reproducibilidad. La versión real, con jitter aleatorio de verdad, está enresilience-and-reliability-patterns-guide— se cita, no se repite. - El
429se simula, nunca se llama a la API real. No hay ninguna llamada de red en todo este módulo. El429 rate_limit_errorde Claude se simula con un cliente de prueba que devuelve el error un número determinado de veces y después responde con normalidad — determinista, citado, sin ninguna dependencia de si tu cuota real está o no excedida en este momento.
El caso que sigue acompañando la guía: book_room se cae, en medio de un día real
El sistema es el mismo de siempre — Reservo, reservas de salas de coworking —, con las mismas cuatro tools canónicas de agent-fundamentals. Este módulo no declara ninguna tool de negocio nueva; lo que hace es ponerle una falla realista a una tool que ya conoces —book_room, la de escritura, la que de verdad le importa al usuario que funcione— y construir, alrededor de ella, la capa de resiliencia que le falta.
list_rooms() -- solo lectura, no se toca en este módulo
get_quote(room, tier, hours) -- solo lectura, no se toca en este módulo
book_room(room, tier, hours, member) -- ESCRITURA: la tool que este módulo endurece
cancel_booking(id) -- destructiva, no se toca en este módulo
A lo largo de las ocho lecciones, book_room va a fallar de tres formas distintas y siempre deterministas: un bache breve (dos o tres llamadas seguidas, después se recupera solo — Lección 3); una caída sostenida, a través de varios runs de usuarios distintos —Ana, Luis, Sofía, y varios más— que llegan uno detrás de otro mientras el servicio sigue caído (Lecciones 4, 5, 7 y 8); y, en paralelo, un 429 del propio Claude que no tiene nada que ver con book_room — es la capa del modelo, no la capa de las tools (Lección 6).
Lo genuinamente nuevo de este módulo es un artefacto de operación más, siempre en inglés:
resilience/tool_circuit_breaker.py—retry_with_backoff,compute_backoff_ms, la claseCircuitBreaker(CLOSED/OPEN/HALF_OPEN),CircuitOpenError, ycall_with_breaker, que compone las dos piezas.resilience/claude_rate_limit.py—RateLimitErrory un cliente de prueba determinista para simular el429de Claude.
Identificadores y código, siempre en inglés (CircuitBreaker, retry_with_backoff, RateLimitError); prosa y comentarios, en español; dinero, en centavos int, como en el resto de la guía. Modelos actuales (claude-sonnet-5) donde el módulo necesite mencionar el modelo — la llamada al LLM sigue siendo concepto en toda esta guía.
Prerequisitos
Conocimiento requerido
- ✅ Haber completado (o conocer bien) los Módulos 1 y 2 de esta guía: el runner
run_reservo_agent, el logger estructurado, y la técnica de "envolver sin tocar" (monkeypatching de un atributo de módulo) que el Módulo 2 desarrolló a fondo. Este módulo la reusa una vez más, ahora para inyectar resiliencia en vez de observabilidad. - ✅ Haber completado
agent-fundamentals-and-tool-calling-guideMódulo 7, en especialcall_with_retries(Lección 6) — este módulo lo escala, no lo repite. - ✅ Python: excepciones (
try/except, jerarquías de excepciones propias), closures, funciones que reciben otra función como argumento (fn(*args, **kwargs)).
Recomendado
- ✅ Haber sentido, alguna vez, la frustración de un sistema que sigue insistiendo con un servicio que —cualquiera con dos minutos de logs podría ver— lleva caído un buen rato. Ese instinto es exactamente lo que este módulo convierte en código.
NO requerido
- ❌ No necesitas conocer
resilience-and-reliability-patterns-guidede antemano — este módulo cita lo que hace falta, con precisión, en el momento que corresponde. - ❌ No necesitas una API key ni conexión a internet: el
429es siempre simulado, y toda la ingeniería de este módulo corre 100% local. - ❌ No necesitas saber de bulkheads, load shedding, ni de exhaustion de pools de threads — eso es, íntegramente, terreno de la guía hermana.
Entorno
- ✅ Python 3.14.0 con su librería estándar (
enumno es obligatorio — este módulo usa strings simples para los estados, tal como hace la guía hermana). Nada que instalar.
Roadmap del módulo
Lección 01 — Introducción al módulo (esta)
La analogía del interruptor térmico, la doble frontera (agent-fundamentals M7 y resilience-and-reliability-patterns-guide), la regla dura de determinismo, y el caso: book_room se cae en medio de un día real.
Lección 02 — Una tool que falla repetidamente
El problema planteado con código real: tres usuarios distintos, tres runs independientes, la misma tool caída — y ninguna memoria entre ellos. El costo de no recordar.
Lección 03 — Reintentos con backoff acotado
retry_with_backoff: la escalada directa de call_with_retries de agent-fundamentals M7, con la pieza que esa lección dejó pendiente — el backoff exponencial, modelado, con un tope duro. Y sus límites: qué pasa cuando la caída dura más que el tope.
Lección 04 — El patrón circuit breaker
La máquina de tres estados, construida desde cero: CircuitBreaker, CircuitOpenError. La primera ejecución completa: CLOSED → tres fallos → OPEN → dos rechazos rápidos → HALF_OPEN → la sonda tiene éxito → CLOSED.
Lección 05 — CLOSED, OPEN, HALF_OPEN
Zoom en las transiciones: qué pasa cuando la sonda de HALF_OPEN también falla (vuelve a OPEN, nuevo cooldown), el costo real en llamadas ahorradas, y por qué el "sondeo" de este breaker opera a nivel de run completo, no de intento individual.
Lección 06 — El 429 de Claude
El rate limit de la propia API de Claude: RateLimitError, un cliente simulado y determinista, y el mismo retry_with_backoff de la Lección 3 aplicado a un tipo de fallo completamente distinto. Por qué esta capa nunca lleva un circuit breaker propio.
Lección 07 — Degradación elegante
Qué le dice el agente al usuario cuando el breaker de book_room está OPEN — sin construir bulkheads ni load shedding, reusando el protocolo is_error que agent-fundamentals ya construyó. Rápido, honesto, sin tocar la tool muerta.
Lección 08 — Mini-proyecto: un agente de Reservo resiliente
Un lote de ocho usuarios, un book_room que se cae y se recupera, backoff + circuit breaker + degradación elegante trabajando juntos — y el trade-off real de ajustar el cooldown, medido con números reales.
Mapa de progresión
Lección 01 (esta) → La analogía, la doble frontera, el caso
Lección 02 → El problema: fallos sin memoria entre runs
Lección 03 → retry_with_backoff (escala M7)
Lección 04 → CircuitBreaker: la máquina de tres estados
Lección 05 → Las transiciones, a fondo
Lección 06 → El 429 de Claude
Lección 07 → Degradación elegante
Lección 08 → Mini-proyecto: todo junto
Dificultad: ⭐⭐ ──────────────────▶ ⭐⭐⭐
Qué lograrás en este módulo
Al completar las 8 lecciones, podrás:
- Distinguir con precisión el reintento dentro-de-un-run (
agent-fundamentalsM7) del circuit breaker entre-runs (este módulo) — y explicar, con un ejemplo, por qué uno no reemplaza al otro. - Construir y ejecutar
retry_with_backoff: un reintento acotado con backoff exponencial modelado, aplicado tanto a una tool que falla como al429de la propia API de Claude. - Construir y ejecutar una máquina de estados
CircuitBreakercompleta (CLOSED/OPEN/HALF_OPEN) por tool, con estado que persiste entre runs, citando con precisión el vocabulario deresilience-and-reliability-patterns-guide. - Explicar y demostrar por qué el
429de Claude es un caso distinto al de una tool caída, y por qué nunca lleva un circuit breaker propio. - Integrar backoff, circuit breaker y degradación elegante en un solo agente de Reservo, y medir —con números reales, no de memoria— el trade-off de ajustar el cooldown del breaker.
El antes y después
ANTES del módulo:
→ "Si una tool falla, reintentarla de nuevo alcanza"
→ "Un circuit breaker es lo mismo que un reintento, con otro nombre"
→ "El 429 de Claude se maneja igual que cualquier tool caída"
→ "Cuando algo falla, hay que decírselo al usuario tal cual salió,
con el stacktrace si hace falta"
DESPUÉS del módulo:
→ Reintentar sin backoff ni memoria entre runs es ruido, no resiliencia
→ Un circuit breaker resuelve un problema que un reintento,
por diseño, no puede resolver: recordar entre runs
→ El 429 de Claude es la capa del proveedor del modelo, no una tool
del agente -- se retentan, nunca se cortan con un breaker
→ Degradar con elegancia es responder rápido y con claridad cuando
el breaker está abierto -- no ocultar el fallo, no reintentar a ciegas
Trampas a evitar al cursar este módulo
1. "Ya usé call_with_retries en agent-fundamentals — este módulo repite lo mismo"
No. call_with_retries resuelve el reintento dentro de un run, sin memoria entre uno y el siguiente. Este módulo construye backoff (una mejora sobre ESE mismo mecanismo) y, sobre todo, un circuit breaker — algo que call_with_retries, acotado a una sola invocación, nunca podría hacer por diseño: recordar que una tool lleva fallando a través de varios runs.
2. "Un circuit breaker es solo un reintento con otro nombre"
Un reintento decide "¿cuántas veces le doy otra oportunidad a ESTA llamada?". Un circuit breaker decide algo distinto y previo: "¿vale la pena intentar esta llamada, o ya sé —por lo que pasó en runs anteriores— que la tool está muerta?" Un reintento nunca deja de intentar por sí solo; un breaker sí, y esa es exactamente la protección que aporta.
3. "Voy a implementar el backoff con random para que el jitter sea realista"
No en esta guía. El jitter aleatorio real es una técnica legítima y útil —está desarrollada a fondo en resilience-and-reliability-patterns-guide—, pero rompe la reproducibilidad byte a byte que exige cada bloque "Qué esperar" de esta guía completa. Aquí el backoff se calcula y se muestra, nunca se ejecuta con time.sleep(), y si se menciona jitter, se hace con honestidad explícita sobre esa simplificación.
4. "El 429 de Claude se resuelve igual que una tool caída, con el mismo circuit breaker"
No. Una tool caída es un problema local —ESA dependencia, ESE servicio, dejó de responder— y el circuit breaker existe para dejar de insistirle. El 429 es la propia API de Claude diciéndote "estás pidiendo más de lo que tu cuota permite ahora mismo" — no está caída, sigue funcionando perfectamente para todos los demás. Cortarle el paso a las llamadas al modelo con un breaker no tiene sentido: el modelo ES el producto. La respuesta correcta a un 429 es reintentar con backoff, nunca dejar de llamarlo.
5. "Cuando el breaker está abierto, mejor que el agente falle con un error técnico — así el usuario sabe que algo anda mal"
Al revés. Fallar con un error técnico (CircuitOpenError: ...) es exactamente lo que la Lección 7 corrige: el agente sabe, con certeza, por qué book_room no está disponible — esa información no debería perderse en un stacktrace. Degradar con elegancia es traducir esa certeza en una respuesta clara y útil, sin fingir que todo salió bien.
Cómo trabajar este módulo
- Corre cada ejemplo tú mismo. Cada lección trae código ejecutable con salida real. Ver el breaker saltar de
CLOSEDaOPENen tu propia terminal —con el número exacto de fallos que hicieron falta— vale más que leerlo en una tabla. - Sigue el hilo de
book_room. Es la misma tool, la misma caída simulada, reutilizada y ampliada de lección en lección — no reinicies el ejemplo cada vez que abras un archivo nuevo. - El mini-proyecto (Lección 08) es la síntesis con trade-offs reales. No es solo "todo junto" — mide, con números, qué se gana y qué se pierde al ajustar el cooldown del breaker.
Tiempo estimado
Lección 01 (esta) → 20 min lectura
Lección 02 → 20 min + correr el ejemplo
Lección 03 → 30 min + correr el ejemplo
Lección 04 → 30 min + correr el ejemplo
Lección 05 → 30 min + correr el ejemplo
Lección 06 → 25 min + correr el ejemplo
Lección 07 → 25 min + correr el ejemplo
Lección 08 → 40 min + armar el mini-proyecto
Total: ~3.5 horas
Evidencia de éxito
Antes de avanzar al Módulo 7 (Versionado y rollout seguro), deberías poder:
- ✅ Explicar, con el ejemplo de
book_room, por qué reintentar sin memoria entre runs desperdicia costo cada vez que llega un usuario nuevo mientras la tool sigue caída. - ✅ Ejecutar
retry_with_backoffsobre una tool flaky y leer, en la salida real, cómo crece el backoff con cada intento. - ✅ Ejecutar un
CircuitBreakercompleto y narrar, con el vocabulario exacto, cada transición:CLOSED → OPENpor umbral,OPEN → HALF_OPENpor cooldown,HALF_OPEN → CLOSEDoHALF_OPEN → OPENsegún el resultado de la sonda. - ✅ Distinguir, sin dudar, un
429de Claude de una tool caída, y explicar por qué el primero nunca lleva breaker. - ✅ Trazar las dos fronteras de este módulo: hacia
agent-fundamentalsM7 (dentro-del-run) y haciaresilience-and-reliability-patterns-guide(vocabulario reusado, alcance angosto).
Resumen
- Este módulo endurece al agente de Reservo contra dos tipos de fallo: una tool que falla de forma sostenida (
book_room) y el429de la propia API de Claude — con tres piezas: backoff acotado, un circuit breaker por tool, y degradación elegante. - La frontera hacia
agent-fundamentalsM7 es de alcance temporal: esa guía resuelve el reintento dentro de un run; este módulo construye memoria que persiste entre runs. - La frontera hacia
resilience-and-reliability-patterns-guidees de profundidad y alcance: esa guía es la fuente canónica del vocabularioCLOSED/OPEN/HALF_OPENy de backoff+jitter medido a fondo con datos aleatorios reales; este módulo lo reusa, citándola, aplicado únicamente a la capa de tool-calls del agente y al429del proveedor del LLM — nunca construye bulkheads ni load shedding. - Regla dura: el backoff se calcula y se muestra, nunca se duerme de verdad (
time.sleep()); nunca hayrandom; el429se simula con un cliente determinista, nunca una llamada real a la API. - La analogía que sostiene todo el módulo: el circuit breaker es el interruptor térmico de tu casa — salta para proteger, no para castigar, y vuelve a la normalidad apenas puede confirmar que el problema pasó.
Siguiente lección: 02 — Una tool que falla repetidamente. Vemos, con código ejecutado, el problema exacto que el resto del módulo resuelve: tres usuarios distintos, tres runs independientes, la misma tool caída — y el costo de no recordar nada entre uno y el siguiente.
Recursos adicionales
- Anthropic — Errors — La referencia completa de códigos de error de la API de Claude, incluido el
429 rate_limit_errorque la Lección 6 simula. - Anthropic — Rate limits — Cómo funcionan los límites de la API de Claude por nivel de cuenta, la base real detrás del
429simulado de este módulo. - Anthropic — Building effective agents — Sobre por qué la confiabilidad de un agente en producción depende de anticipar fallos, no solo de manejarlos cuando ya ocurrieron.
resilience-and-reliability-patterns-guide— La guía hermana, fuente canónica del vocabulario de circuit breakers, backoff+jitter y degradación elegante que este módulo reusa con precisión y cita en cada lección que corresponde.- Python 3.14 — What's New — La versión exacta con la que se ejecuta toda la ingeniería de este módulo.