Phase 16 - Lesson 22
Escalado en Producción — Colas, Checkpoints, Durabilidad
Escalar sistemas multiagente a miles de ejecuciones simultáneas requiere ejecución durable. El runtime de LangGraph escribe un checkpoint después de cada super-step claveado por
thread_id(Postgres por defecto); las caídas de los workers liberan una concesión (lease) y otro worker se reanuda. Los agentes pueden dormir indefinidamente esperando la entrada de un humano. MegaAgent (arXiv:2408.09955) ejecutó una cola de productor-consumidor por agente con tres estados (Idle / Processing / Response) y coordinación de dos capas (chat intra-grupo + chat de administración inter-grupo). Fiber/async supera a thread-per-job para el streaming de LLM: los hilos están inactivos el 99% del tiempo esperando tokens, las fibras ceden cooperativamente en I/O. Contrapunto: "Scaling Agentic Software" de Ashpreet Bedi aboga por FastAPI + Postgres + nada más hasta que la carga demuestre lo contrario — las arquitecturas simples llegan más lejos de lo esperado. Esta lección construye un registro de checkpoints durable, una cola de trabajo por agente con transiciones de estado, una demostración de async-vs-thread, y establece la regla pragmática de "empezar simple".
Tipo: Aprender + Construir
Idiomas: Python (stdlib, asyncio, sqlite3)
Prerrequisitos: Fase 16 · 09 (Redes de Enjambre Paralelas), Fase 16 · 13 (Memoria Comparthibla)
Tiempo: ~75 minutos
Problema
Un prototipo de sistema multiagente funciona en una laptop con tres agentes en un bucle de eventos en memoria. Te mudas a producción:
- Los agentes a veces se ejecutan durante horas (investigación larga, esperas de interacción humana).
- Los procesos de los workers se caen. Reiniciar pierde el estado.
- La carga pico es 10 veces el promedio; necesitas escalado horizontal.
- Los usuarios pagan por ejecución de agente; necesitas semántica de ejecución única (exactly-once) para el cobro.
El bucle de eventos en memoria no hace nada de esto. Necesitas una capa de ejecución durable por debajo. Las opciones canónicas de 2026 son:
- Un motor de flujo de trabajo con checkpoints (Temporal, runtime de LangGraph).
- Una cola de mensajes con un almacén de estado (Postgres + SQS/RabbitMQ).
- Frameworks de modelo de actores (cola de productor-consumidor por agente de MegaAgent).
- FastAPI + Postgres a medida (el argumento de Bedi).
Esta lección construye una miniatura de cada uno.
Concepto
Ejecución durable, el patrón
Un motor de ejecución durable persiste el estado completo del programa después de cada "paso" (super-step, en la terminología de LangGraph). En caso de caída:
worker crashes mid-step
-> lease timeout
-> another worker picks up the thread_id
-> resumes from last checkpoint
-> no duplicate side effects
Requisitos para que esto funcione:
- Estado serializable. Todo el estado del agente debe ser persistible. Las clausuras de funciones (closures) con conexiones de base de datos activas no sobreviven.
- Reanudación determinista. Dado el mismo estado y las mismas entradas, el agente produce las mismas acciones (oráculo determinista externo para llamadas a LLM).
- Efectos secundarios idempotentes. Las llamadas externas (llamadas a herramientas, pagos) deben ser idempotentes o usar una clave de deduplicación.
LangGraph escribe un checkpoint después de cada super-step; Temporal escribe después de cada actividad; Restate utiliza diarios basados en origen de eventos (event-sourced). Los tres implementan el mismo patrón.
Runtime de LangGraph
Cada agente tiene un thread_id; el estado es un diccionario tipado; cada super-step escribe una fila en la tabla de checkpoints. Al reanudar, el runtime reproduce desde el último checkpoint, no desde cero. Los agentes pueden interrumpir la ejecución con interrupt() esperando la entrada humana; el runtime persiste y libera al worker. Cuando llega la entrada, cualquier worker puede reanudar.
Este es el diseño de producción de referencia en abril de 2026.
Cola por agente de MegaAgent
arXiv:2408.09955 describe un experimento de escala: miles de agentes concurrentes en un clúster. Arquitectura:
agent i:
state ∈ {Idle, Processing, Response}
in_queue <- messages addressed to agent i
out_queue -> replies + side effects
coordinators:
intra-group chat (agents in the same group)
inter-group admin chat (high-level routing)
La coordinación de dos capas permite que la conversación intra-grupo ocurra densamente mientras que la inter-grupo permanece dispersa — el patrón utilizado para mantener el costo lineal en miles de agentes.
Async vs thread-per-job
Las llamadas a LLM están limitadas por I/O (I/O-bound). Un hilo que espera el siguiente token está inactivo el 99% del tiempo. Los hilos cuestan ~1MB de RAM cada uno; a 10,000 llamadas concurrentes, eso representa 10GB solo para pilas de ejecución (stacks).
Las fibras (Python asyncio, goroutines de Go, tokio de Rust) ceden cooperativamente en I/O. Las mismas 10,000 llamadas caben cómodamente en el proceso. A escala de agentes de LLM, async no es una optimización — es la arquitectura.
Excepción: El post-procesamiento limitado por CPU (embedding, trucos de tokenizador) aún requiere hilos o procesos. Separa tu capa de I/O de tu capa de CPU.
Contrapunto de Bedi
"Scaling Agentic Software" (Ashpreet Bedi, 2026) argumenta que la mayoría de los equipos sobre-diseñan antes de medir la carga. El predeterminado pragmático:
- FastAPI + Postgres.
- Cada ejecución de agente es una fila; el estado se actualiza in-place con concurrencia optimista.
- Trabajos en segundo plano a través de
pg_notifyo un worker Celery simple. - Política de reintentos en el código de la aplicación.
Para cargas inferiores a ~100 ejecuciones de agentes simultáneas en tareas manejables, esto suele ser todo lo que necesitas. Actualiza cuando midas fallas.
La regla: adopta frameworks de ejecución durable cuando te enfrentes a un problema concreto que las arquitecturas simples no puedan resolver. La adopción prematura consume tiempo en ceremonias que no dan frutos.
Semántica de ejecución única (exactly-once)
Para ejecuciones pagadas de agentes, necesitas "ejecución única efectiva" (entrega de al menos una vez + consumidor idempotente). Las técnicas de ingeniería:
- Clave de deduplicación por ejecución. Incorpórala en cada llamada de efecto secundario.
- Patrón Outbox. Los efectos secundarios escriben primero en una tabla, luego un proceso independiente los ejecuta. Ambos pasos son idempotentes.
- Transacciones de compensación. Cuando un efecto secundario tiene éxito pero su escritura de seguimiento falla, programa una compensación.
Estos son patrones de ingeniería de bases de datos, no específicos de LLM. El único impuesto de LLM es que las llamadas a LLM son lentas; todo lo demás son sistemas distribuídos estándar.
Despliegue arcoíris (rainbow deployment)
El sistema de investigación multiagente de Anthropic utiliza "despliegues arcoíris": múltiples versiones del runtime del agente se ejecutan concurrentemente para que los agentes de larga duración no tengan que ser eliminados en cada despliegue de código. Prueba las nuevas versiones en una fracción del tráfico (canary); retira las versiones antiguas cuando sus agentes terminen.
Esto es estándar para sistemas de larga duración con estado; la adaptación de 2026 es que los agentes pueden vivir durante horas, por lo que los ciclos de despliegue deben adaptarse.
La lista de verificación de producción canónica
- Estado durable (checkpoints, snapshots o log reproducible con outbox).
- Efectos secundarios idempotentes.
- Capa de I/O asíncrona para llamadas a LLM.
- Entrega de al menos una vez con deduplicación.
- Despliegue arcoíris/canary para cargas de trabajo con estado.
- Observabilidad: trazas por agente, auditoría de super-step, contador de reintentos.
Build It
code/main.py implementa:
CheckpointStore— registro de checkpoints respaldado por SQLite con claves de ID de hilo. Cada super-step añade una fila.run_with_checkpoint(agent, thread_id)— simula una caída en medio de la ejecución; un segundo worker se reanuda desde el último checkpoint.AgentQueue— máquina de estados Idle / Processing / Response por agente con una pequeña cola de trabajo.demo_async_vs_threads()— ejecuta 500 llamadas a LLM simuladas concurrentemente a través de asyncio y a través de hilos; informa el tiempo de reloj y el pico de memoria (aproximado).
Ejecuta:
python3 code/main.py
Resultado esperado: la reanudación del checkpoint tiene éxito después de la caída simulada; la versión asíncrona maneja 500 llamadas concurrentes en < 1s; la versión de hilos tarda varios segundos y consume órdenes de magnitud más memoria por unidad concurrente.
Use It
outputs/skill-scaling-advisor.md asesora sobre la elección de ejecución durable: FastAPI + Postgres, runtime de LangGraph, Temporal o personalizado. Calibrado por carga, necesidades de retención de estado y frecuencia de despliegue.
Ship It
Endurecimiento canónico de producción:
- Empieza simple (regla de Bedi). FastAPI + Postgres hasta que midas fallas.
- Instrumenta todo antes de optimizar. Histograma de latencia por ejecución, tiempo por paso (step), conteo de reintentos, categorización de fallas.
- Patrón Outbox para efectos secundarios. Especialmente pagos y llamadas a API externas.
- Despliegues arcoíris. Nunca elimines ejecuciones de agentes en curso durante los despliegues.
- Adopta motores de ejecución durable (Temporal / LangGraph / Restate) cuando te enfrentes a problemas específicos: esperas de horas para entrada humana, coordinación entre regiones, políticas complejas de reintentos/compensación.
- Async para la capa de I/O. Hilos solo para el post-procesamiento limitado por CPU.
Ejercicios
- Ejecuta
code/main.py. Confirma que la reanudación del checkpoint funciona; mide la diferencia de concurrencia entre async e hilos. - Implementa una tabla outbox: cada llamada a herramienta escribe primero en el outbox, luego una tarea/goroutine independiente la ejecuta. Verifica la idempotencia ejecutando la llamada a herramienta dos veces.
- Simula un despliegue arcoíris: dos versiones concurrentes del runtime; ruta la mitad de los nuevos thread_ids a cada una; confirma que los hilos en curso en la versión antigua no se interrumpan.
- Lee la documentación de runtime de LangGraph (enlace abajo). Identifica qué características del runtime tomaría más tiempo replicar en una versión a medida con FastAPI + Postgres. ¿Es esa una razón para adoptarlo o puedes posponerlo?
- Lee la Sección 3 de MegaAgent (arXiv:2408.09955). La coordinación de dos capas (chat intra-grupo + chat de administración inter-grupo) es explícita. Diseña cómo mapearías esto a una cola de mensajes con dos familias de colas.
Términos Clave
| Término | Lo que la gente dice | Lo que realmente significa |
|---|---|---|
| Ejecución durable | "Persistir el estado del programa" | El motor escribe el estado después de cada super-step; la recuperación ante caídas es determinista. |
| Super-step | "Límite transaccional" | Unidad de trabajo entre checkpoints. Término de LangGraph. |
| thread_id | "Identificador de ejecución del agente" | Clave que vincula checkpoints y lógica de reanudación. |
| Idempotencia | "Seguro para reintentar" | Repetir un efecto secundario produce el mismo resultado que un solo intento. |
| Patrón Outbox | "Desacoplar efectos secundarios" | Escribe la intención en una tabla; un ejecutor independiente la realiza y la marca como terminada. |
| Entrega de al menos una vez | "Posibles duplicatos" | Semántica de cola de mensajes; la clave de deduplicación hace que el consumo sea efectivo una sola vez. |
| Despliegue arcoíris | "Versiones superpuestas" | Múltiples versiones del runtime concurrentes durante cargas de trabajo de larga duración. |
| Fibra asíncrona | "Cesión cooperativa" | Concurrencia en modo usuario; barata en comparación con hilos para cargas de trabajo limitadas por I/O. |
| Checkpoint | "Instantánea del estado" | Estado serializado en el límite de un super-step; clave para la reanudación. |
Lectura Adicional
- LangChain — The runtime behind production deep agents — Diseño del runtime de LangGraph
- MegaAgent — Cola de productor-consumidor por agente; coordinación de dos capas con miles de agentes concurrentes
- Matrix — Framework descentralizado con colas de mensajes como sustrato de coordinación
- Temporal docs — El motor de flujo de trabajo de referencia para ejecución durable
- Anthropic — Multi-agent research system — Lecciones de producción incluyendo despliegues arcoíris