Alejandro Rioja.
AI Agents Operations

Patrones de Orquestación Multiagente: Colas, Estado y Traspasos

Alejandro Rioja
Alejandro Rioja
7 min de lectura
TL;DR

Los sistemas multiagente fiables no dependen de prompts ingeniosos — dependen de la aburrida disciplina de los sistemas distribuidos: colas durables entre agentes, estado mantenido fuera del modelo y traspasos idempotentes que sobreviven a los reintentos. El modelo es el trabajador; la cola es la columna vertebral.

Newsletter gratuita

Cada miércoles. 28.400+ operadores. Sin relleno.

Tabla de contenidos

Actualizado junio 2026.

TL;DR: Los sistemas multiagente fiables no se ganan con prompts ingeniosos — se ganan con la aburrida disciplina de los sistemas distribuidos. Pon una cola durable entre agentes, mantén el estado fuera del modelo y haz que cada traspaso sea idempotente para que un reintento no actúe dos veces. El modelo es el trabajador; la cola es la columna vertebral. Acierta en esos tres y la orquestación deja de dar miedo.

Lectura del operador: La mayoría de mis más de 100 agentes son de un solo paso. Los que no lo son — los pipelines que clasifican, luego enriquecen, luego actúan — solo se volvieron fiables cuando dejé de pensar en “cadena de prompts” y empecé a pensar en “cola de trabajos con trabajadores LLM”. Esto es arquitectura, no ingeniería de prompts.

“Multiagente” suena a que los agentes se hablan entre sí. En la práctica, la versión fiable es lo contrario: los agentes no se comunican directamente en absoluto. Dejan mensajes en una cola y recogen trabajo de una cola, y la orquestación vive en la fontanería entre ellos. Estos son los patrones que aguantan en producción.

Patrón 1: Pon una cola durable entre cada agente

El primer instinto es llamar al agente B directamente desde dentro del agente A. No lo hagas. Las llamadas directas acoplan a los dos: si B es lento, A se bloquea; si B falla, el trabajo de A se pierde; si necesitas escalar B, no puedes sin tocar A.

En su lugar, A termina su trabajo y encola un mensaje para B. B es un trabajador separado que vacía la cola a su propio ritmo.

typescript
// El agente A termina y traspasa vía la cola — sin llamada directa a B
await env.ENRICH_QUEUE.send({
  traceId,
  type: "enrich",
  payload: classifierResult,
});
// El trabajo de A está hecho. B lo recogerá de forma independiente.

En Cloudflare uso Workers Queues exactamente para esto — las mismas primitivas detrás de el stack de agentes que uso. La cola te da cuatro cosas gratis: buffering (B puede estar caído sin perder trabajo), reintentos (los mensajes fallidos se reentregan), contrapresión (un pico se encola en lugar de provocar una caída) y desacoplamiento (escala o redespliega B sin tocar A). Cada una de esas es algo que de otro modo tendrías que construir a mano y equivocarte.

Patrón 2: Mantén el estado fuera del modelo, siempre

El bug multiagente más común es asumir que el modelo recuerda algo entre pasos. No lo hace. Cada llamada al modelo es sin estado; la única memoria es lo que pones en el prompt. Así que la fuente de verdad para “dónde está este trabajo en el pipeline” debe vivir en una base de datos, no en una conversación.

Mantengo un único registro de trabajo que cada agente lee y actualiza:

typescript
interface JobState {
  traceId: string;
  stage: "classified" | "enriched" | "acted" | "done" | "failed";
  data: Record<string, unknown>;
  attempts: number;
  updatedAt: number;
}

Cada agente hace el mismo bucle: leer el estado del trabajo, hacer su trabajo, escribir el nuevo estado, encolar la siguiente etapa. El modelo nunca retiene el estado — recibe la porción relevante como entrada y devuelve un resultado. Esto es lo que hace al sistema reanudable: si un trabajador muere a mitad de un trabajo, el registro de estado todavía dice exactamente dónde estaban las cosas, y el mensaje de cola reentregado retoma desde ahí. También hace que la depuración sea manejable, porque la tabla de estado es un registro consultable del recorrido de cada trabajo — la misma mentalidad de instrumentación de cómo mido si un agente está funcionando.

Patrón 3: Haz que cada traspaso sea idempotente

Las colas garantizan la entrega al menos una vez, no exactamente una vez. Eso significa que un mensaje puede entregarse dos veces — cortes de red, reintentos, redespliegues. Si la acción de tu agente no es idempotente, una doble entrega actúa dos veces: dos correos de confirmación, dos reservas, dos cargos. Esta es la clase de bug de orquestación más desagradable, y es la que los equipos descubren en producción.

La solución es hacer que las acciones sean idempotentes con una clave:

typescript
async function handleEnrich(msg: QueueMessage, env: Env) {
  const job = await getJob(env, msg.traceId);
  if (job.stage !== "classified") {
    // Ya procesado más allá de esta etapa — es una entrega duplicada. Omitir.
    return;
  }
  const result = await enrich(job.data);
  await advanceJob(env, msg.traceId, "enriched", result);
  await env.ACT_QUEUE.send({ traceId: msg.traceId, type: "act" });
}

La verificación de etapa hace que la operación sea segura de ejecutar dos veces: la segunda entrega ve que el trabajo ya ha avanzado y no hace nada. Para efectos secundarios externos (enviar un correo, cobrar una tarjeta), pasa una clave de idempotencia a la API descendente para que ella también deduplique. Asume que cada mensaje se entregará dos veces y diseña de modo que eso sea inofensivo — porque eventualmente lo será.

Patrón 4: Orquestador vs coreografía — elige deliberadamente

Hay dos maneras de cablear el flujo, y la elección correcta depende de la complejidad.

Coreografía (lo que uso por defecto): cada agente conoce solo el siguiente paso y lo encola. El flujo emerge de la cadena. Simple, descentralizada, fácil de extender — añade una etapa insertando una cola. La desventaja es que ningún lugar único describe el flujo completo, así que un pipeline complejo puede volverse difícil de razonar.

Orquestación (un coordinador central): un orquestador es dueño del flujo, llama a cada agente por turno y decide qué sigue en función de los resultados. Todo el flujo vive en un lugar legible y la lógica de ramificación es explícita. El coste es un componente central que debe ser él mismo durable — si el propio estado del orquestador no está externalizado (Patrón 2), se convierte en el punto único de fallo.

Mi regla: coreografía hasta que la ramificación se vuelva compleja, luego un orquestador durable. Un pipeline lineal de tres etapas es coreografía. Un flujo con enrutamiento condicional, fan-out paralelo y uniones quiere un orquestador cuyo estado viva en la base de datos para que pueda reanudarse tras una caída.

Patrón 5: Fan-out, fan-in sin perder piezas

Cuando un trabajo genera N subtareas paralelas (enriquecer 50 registros, resumir 20 documentos) y necesitas esperar a todas antes de continuar, necesitas una unión (join). El truco es un contador en el estado del trabajo:

  1. El padre encola N mensajes hijos y escribe expected: N, completed: 0 en el registro del trabajo.
  2. Cada hijo hace su trabajo e incrementa atómicamente completed.
  3. El hijo que sube completed hasta igualar expected encola la siguiente etapa.

El incremento atómico es crítico — sin él, dos hijos que terminan simultáneamente pueden ambos creer que no son el último, y la unión nunca se dispara. Usa un contador que el datastore pueda incrementar atómicamente, o una transacción. Este patrón te permite paralelizar el medio costoso de un pipeline (a menudo trabajo barato para Haiku — ver las matemáticas de coste de Haiku vs Sonnet) manteniendo una unión limpia al final.

Lo que me saltaría

No necesitas un framework de agentes pesado para hacer nada de esto. Las colas, una tabla de estado y las claves de idempotencia son primitivas que toda plataforma ya tiene. He visto a equipos recurrir a frameworks multiagente elaborados para obtener funciones que una cola te da gratis, y heredar una caja negra más difícil de depurar que la fontanería que reemplazó. Empieza con las aburridas primitivas. Recurre a un framework solo cuando hayas sentido un dolor específico que él resuelva.

El resumen: los agentes son trabajadores sin estado, las colas son la columna vertebral durable, el estado vive en una base de datos y cada traspaso es seguro de ejecutar dos veces. Ese es todo el juego.

Preguntas frecuentes

¿Los agentes deben llamarse directamente entre sí o pasar por una cola?

Por una cola. Las llamadas directas acoplan a los agentes — el fallo o la lentitud de uno se propaga al otro, y no puedes escalar ni redesplegar de forma independiente. Una cola durable te da buffering, reintentos, contrapresión y desacoplamiento gratis.

¿Dónde debe vivir el estado multiagente?

Fuera del modelo, en una base de datos, como un registro de trabajo que cada agente lee y actualiza. Las llamadas al modelo son sin estado, así que la fuente de verdad para el progreso del pipeline debe ser externa — eso es lo que hace al sistema reanudable tras una caída.

¿Cómo evito que un agente actúe dos veces sobre el mismo trabajo?

Haz que los traspasos sean idempotentes. Verifica la etapa del trabajo antes de actuar y no hagas nada si ya ha avanzado, y pasa claves de idempotencia a las APIs externas. Las colas entregan al menos una vez, así que asume que cada mensaje puede llegar dos veces y diseña de modo que los duplicados sean inofensivos.

¿Necesito un framework multiagente?

Normalmente no. Las colas durables, una tabla de estado y las claves de idempotencia cubren la mayoría de las necesidades de producción con primitivas que tu plataforma ya proporciona. Adopta un framework solo cuando te encuentres con un problema concreto que él resuelva de forma única, no por defecto.

Seguir leyendo

Recibe el manual de IA en tu buzón

Cada miércoles. 28.400+ operadores. Sin relleno.

↵ para ver todos los resultados esc esc para cerrar