Tool Orchestration en AI Agents 2026: El Agent Loop No es una Lista de Tareas, es un Grafo de Dependencias

Tool Orchestration en AI Agents 2026: El Agent Loop No es una Lista de Tareas, es un Grafo de Dependencias

Programming· 7 min read

El 90% de los AI Agents de GitHub Ejecutan Tool Calls Como si Fuera 1999

Uno tras otro. Esperando a que el anterior termine aunque no tengan ninguna dependencia entre sí.

Eso desperdicia entre un 47% y un 62% de la latencia — y no se arregla con un mejor modelo. Se arregla con un scheduler.

Los modelos ya emiten múltiples tool calls en una sola pasada de generación. GPT‑5.6, Claude y todos los frontier models de 2026 despachan lotes completos de llamadas a herramientas cada iteración del loop. El problema es que los frameworks de orquestación más populares las ejecutan en el orden en que llegan, una a una, como quien recorre un array con un for y espera a cada elemento.

*El error de diseño raíz no es el modelo. Es tratar el agent loop como una lista de tareas cuando es un grafo de dependencias. *

La sabiduría convencional asume que la calidad de un agente depende del modelo o del prompt. El dato del 47-62% demuestra que el cuello de botella está en la capa de orquestación: cómo se programan y se despachan las llamadas a herramientas, no en qué modelo las genera.

El Problema: Creéis que un Agent Loop es una Lista de Tareas

Tomad un agente de research típico. El modelo emite en una sola pasada tres tool calls:

  1. web_search("precios SaaS 2026 en España")
  2. query_database("SELECT id, mrr FROM clientes WHERE churned = true")
  3. read_file("docs/comparativa_2025.md")

Ninguna depende de la otra. Son tres ramas independientes.

¿Qué hace un orquestador secuencial ingenuo? Espera a que web_search termine. Espera a que query_database termine. Espera a que read_file termine.

En secuencial tardas la suma de los tres. En paralelo tardas el máximo de los tres.

Para un agente con 5 ramas independientes que cada una tarda 2 segundos: 10 segundos en secuencial, 2 en paralelo. El ahorro crece con el número de ramas independientes — y casi ningún flujo real es 100% secuencial.

El anti-patrón (lo que generan el 90% de los frameworks por defecto):

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Ese for serializa incluso llamadas completamente independientes. Es la fuente del 47-62% de latencia extra.

El despacho paralelo con primitivas nativas:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

asyncio.gather en Python, Promise.all en TypeScript. La misma idea. El modelo ya emitió el lote; el scheduler decide quién espera y quién no.

La Evidencia: Lo que Pasa Cuando No Orquestas

No me creáis a mí. Medidlo vosotros.

Antes de tocar nada, instrumentad vuestro loop actual con un wrapper de timing que registre el wall-clock por tool_call y por iteración completa:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Responded a esta pregunta: ¿cuántas de vuestras tool calls por iteración son realmente dependientes? En casi cualquier flujo real — research, extracción, e-commerce, atención al cliente — el ratio de ramas independientes está por encima del 50%.

Una nota de honestidad: las cifras del 90% y del 47-62% provienen de un análisis observacional del ecosistema de GitHub, no de un benchmark externo publicado. Tratadlas como hipótesis medibles. El harness de medición de arriba es vuestra herramienta de validación — replicad la medición en vuestro propio stack y comprobad el delta vosotros mismos.

El Framework: El Orquestador de 3 Fases

La corrección no vive en el modelo ni en el prompt. Vive en una capa de scheduling entre la salida del LLM y la ejecución. Lo llamo El Orquestador de 3 Fases, y en el fondo es un DAG disfrazado.

Fase 1: Secuenciación Obligada

Inventariad vuestras tools y clasificad sus dependencias. Para cada par de herramientas, responded a una pregunta: ¿la salida de una es entrada de la otra?

Si web_search alimenta parse_results, son secuencia obligada. Se ejecutan en orden, sin discusión. Modelar esto explícitamente ya aporta valor aunque no haya ni una sola llamada paralela: fuerza a hacer visible qué depende de qué en vez de asumirlo.

Fase 2: Fan-Out de Ramas Independientes

Los nodos sin aristas entre sí se lanzan en paralelo con asyncio.gather o Promise.all. Con timeouts por rama, para que una herramienta lenta no bloquee todo el bucle.

El paralelismo no es ilimitado. Es fan-out controlado: límites de concurrencia configurables y capas de espera si alguna rama toca el mismo rate limit.

Fase 3: Agregación y Orden Canónico

Aquí es donde el 90% de las implementaciones naive de paralelismo se rompen. Paralelizar cambia la semántica de error.

En secuencial, un fallo aborta el flujo limpiamente. En paralelo tienes fallos parciales, retries por rama y el problema crítico: inyectar resultados desordenados en el contexto del LLM.

La solución es un orden canónico determinista basado en el orden de aparición de las tool calls en el lote original. Ese es el orden que el modelo espera cuando le devolvéis el contexto — romperlo degrada la coherencia aunque todos los resultados sean correctos.

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

El manejo de fallos en ramas paralelas

Con return_exceptions=True en Python o Promise.allSettled en TypeScript, una rama que reviente no aborta las demás:

  • Retry por rama, no por lote completo.
  • Resultados parciales tolerados: si tres de cinco ramas responden, se devuelven las tres con una nota de fallo.
  • Orden canónico de inyección para no romper la coherencia que el LLM espera.

La Analogía que lo Explica Todo

En scraping aprendí una lección que aplica a agents: el código es commodity; la capa operativa es el producto.

Cualquiera escribe una función con un decorador y llama a MCP.add_tool() — las definiciones de tools son commodity. Pero el bucle que decide qué se ejecuta en paralelo, qué se secuencia y cómo se agregan los resultados es la capa operativa que distingue un demo de un sistema en producción.

Los modelos no planifican ejecución eficiente. Emiten llamadas. Sin una capa de scheduling que clasifique dependencias, el modelo no tiene forma de forzar paralelismo — y el dato del 47-62% sugiere que tampoco los frameworks actuales lo hacen por defecto. El scheduling es responsabilidad del orquestador, no del modelo.

Esto conecta con lo que OpenAI ya empuja en 2026 con su Programmatic Tool Calling: escribir JavaScript para orquestar tools, ejecutar llamadas independientes en paralelo y procesar los outputs fuera del context window. El modelo se queda con lo que requiere inteligencia — aplicar juicio — y la capa operativa hace el scheduling.

Cómo Implementarlo Hoy en tu Stack

Paso 1 — Inventaría tus tools. Lista cada una y escribe sus dependencias explícitas. No las dejes implícitas en el prompt.

Paso 2 — Divide tu flujo en las 3 fases. Fase 1 con dependencias reales, Fase 2 con el fan-out, Fase 3 con la agregación determinista.

Paso 3 — Implementa el despacho paralelo con asyncio.gather o Promise.all. Timeouts por rama.

Paso 4 — Mide antes y después. Wall-clock por tool_call y por iteración completa. El delta frente a tu medición base es tu ahorro real — no el 47-62% teórico, sino el tuyo.

Paso 5 — Añade semántica de fallos. allSettled, retry por rama, resultados parciales y orden canónico de inyección.

Si trabajáis con SDKs como Claude Agent SDK, LangGraph o CrewAI, el patrón se integra igual: interceptad el lote de tool calls que emite el modelo y sustituid el dispatch por defecto por vuestro orquestador de 3 fases. No necesitáis cambiar de framework — necesitáis una capa de scheduling encima del que ya usáis.

La Conclusión Directa

El 90% de los agents de GitHub pierden entre 47% y 62% de su latencia en un error de diseño que no necesita un modelo mejor: necesita un scheduler.

Tratad el agent loop como lo que es: un grafo de dependencias, no un array. Orquestad en fases. Medid el delta en vuestro stack.

El modelo emite. El orquestador decide. Y esa capa de decisión es el producto real que os separa de un demo — la capa operativa que el resto del ecosistema sigue tratando como commodity.

Artículos relacionados

---

¿Quieres recibir contenido como este cada semana? Suscríbete a mi newsletter

Brian Mena

Brian Mena

Software engineer building profitable digital products: SaaS, directories and AI agents. All from scratch, all in production.

LinkedIn