La mayoría de las personas que intentan construir un agente multi-paso terminan con una línea recta. Paso uno, paso dos, paso tres - cada uno esperando cortésmente a que el anterior termine antes de empezar.
9 de cada 10 notan que la mitad de esos pasos nunca necesitaron esperar.
No enrutan. No ramifican. No paralelizan. Simplemente hacen cola - una cabeza, un contexto, una cosa a la vez, hasta que la ventana se llena y el agente olvida lo que estaba haciendo.
Sigue mi Substack para recibir novedades de IA:
Esta es la hoja de ruta de 14 pasos que convierte esa línea de un solo archivo en un grafo: uno que se despliega a través de una flota, verifica sus propios hallazgos y converge en un resultado que un agente solitario jamás podría retener.

Aquí está el cambio que nadie explica. Un prompt es una oración. Un bucle es un ciclo. Un harness es el suelo sobre el que se para el agente.
Pero la forma del trabajo en sí - qué se ejecuta antes de qué, qué puede ejecutarse al mismo tiempo, qué tiene que esperar a todo lo demás - esa forma es un grafo. Los nodos hacen el pensamiento. Las aristas transportan los resultados.
Claude Code incorporó las herramientas para construir estos grafos directamente: flujos de trabajo dinámicos.
Claude escribe un script de orquestación en JavaScript plano, luego genera una flota coordinada de subagentes para ejecutarlo - y la coordinación en sí misma cuesta cero tokens del modelo, porque es código, no una conversación.
01. Los nodos son trabajos. Las aristas son lo que fluye.
Un grafo tiene exactamente dos cosas, y entenderlas correctamente elimina la mayor parte de la confusión. Un nodo es una unidad de trabajo - un agente, un trabajo delimitado, una entrada y una salida.
Una arista es una dependencia: dice la salida de este nodo alimenta la entrada de ese nodo. Nada más.

El error es tratar "y luego" como una arista. "Resume el archivo y luego dime el clima" no tiene una arista entre los dos - el clima no consume el resumen.
Eso son dos nodos desconectados que un script lineal encadena innecesariamente. La arista solo existe cuando los datos realmente se mueven a través de ella.
Aprende a preguntar, por cada "y luego" en tu agente: ¿el siguiente paso lee la salida del paso anterior? Si no, no hay arista, y la espera es una pérdida de tiempo.
1Dibújalo como cajas y flechas. Una caja es una llamada agent().2Una flecha es una variable que pasa del retorno de una llamada al prompt3de otra. Si no puedes dibujar la flecha - si ninguna variable cruza - las dos4cajas son independientes, y la independencia es lo que explotarás5durante el resto de este curso.
02. Tu script lineal es un grafo degenerado
Cuando escribes un agente como "haz A, luego B, luego C, luego D", has dibujado un grafo - una única cadena sin ramificaciones. Cada nodo tiene exactamente una arista de entrada y una de salida.
Se ejecuta correctamente. También se ejecuta lentamente y es frágil, porque una cadena no tiene redundancia: si C se estanca, D nunca ocurre, y el trabajo de A queda atrapado río arriba sin lugar a dónde ir.

La primera habilidad real de la ingeniería de grafos es redibujar la cadena. Toma tu agente lineal y, para cada flecha, haz la pregunta del Paso 1.
La mayoría de las cadenas tienen dos o tres flechas que no transportan datos - son solo el orden en que escribiste las cosas.
Corta esas flechas y la cadena se colapsa en algo más amplio: unos pocos nodos independientes que podrían ejecutarse todos a la vez, alimentando un solo nodo que los necesita a todos.
03. Dale a cada nodo un contrato
Un nodo sobre el que no puedes razonar es un nodo que no puedes paralelizar. La solución es un contrato: entrada delimitada, salida delimitada, exactamente un trabajo.
La entrada es lo que sea que el nodo lea - pasado explícitamente, nunca asumido desde una ventana compartida. La salida tiene una forma definida, idealmente validada, para que el siguiente nodo pueda consumirla sin adivinar.

En un flujo de trabajo, este contrato se aplica con un esquema. Cuando le pasas a Claude una llamada agent() con un esquema JSON, el subagente que Claude genera se ve forzado a devolver datos estructurados validados - la validación ocurre en la capa de llamada a la herramienta, así que Claude reintenta en caso de error en lugar de darte texto libre que tienes que parsear y rezar.
Esta es la diferencia entre un nodo que Claude puede conectar en un grafo y un nodo que solo funciona cuando un humano lee su salida.
1// Un nodo con un contrato real: entrada delimitada, salida validada, un trabajo.2const ITEM = {3 type: 'object', additionalProperties: false,4 properties: {5 title: { type: 'string' },6 url: { type: 'string' },7 impact: { type: 'string', enum: ['high', 'medium', 'low'] },8 },9 required: ['title', 'url', 'impact'],10};1112const result = await agent(source.prompt, {13 label: `research:${source.key}`,14 schema: ITEM, // fuerza una salida estructurada validada15 agentType: 'general-purpose',16});17// result ahora tiene una forma en la que el siguiente nodo puede confiar — no texto libre.
04. Trata la arista como un contrato de datos
Una arista no es solo "B viene después de A". Es una promesa sobre lo que cruza: A produce esta forma, y B está construido para consumir esta forma. Cuando nombras la arista por sus datos - no por su orden - dos cosas se vuelven más fáciles.

Puedes ver instantáneamente si la arista es real (¿los datos realmente se mueven?), y puedes intercambiar el nodo en cualquiera de los extremos sin romper el grafo, siempre que la forma se mantenga.
En la práctica, la arista vive en JavaScript plano. El paso de reducción entre la distribución y la síntesis - aplanar, deduplicar, filtrar - es solo código operando sobre las formas que tus nodos devolvieron.
No se necesita ningún agente. Una de las victorias silenciosas del pensamiento en grafos: una gran cantidad de lo que la gente gasta tokens del modelo es en realidad una arista, y las aristas son gratuitas.
1La tentación es generar un agente para "combinar los resultados". Resístela.2Si combinar significa aplanar y deduplicar, eso es results.flatMap(...)3y un Set — determinista, instantáneo, cero tokens. Guarda los agentes para4el juicio, no para la fontanería. Un grafo donde cada arista es un agente es un5grafo pagando alquiler por su propio cableado.
05. Distribuye con parallel()
Este es el movimiento que lo paga todo. Cuando tienes N nodos independientes - N fuentes que verificar, N archivos que revisar, N rutas que auditar - no los encadenas.
Le dices a Claude que los distribuya y los ejecute todos a la vez. En un flujo de trabajo, eso es parallel(): Claude toma un array de thunks y genera un subagente por cada thunk, todos ejecutándose concurrentemente, y luego te devuelve el array de resultados.

Dos detalles lo hacen robusto. Primero, parallel() es una barrera - espera a que cada thunk termine antes de devolver el control, así que la siguiente etapa ve el conjunto completo. Segundo, un thunk que lanza una excepción se resuelve como null en lugar de rechazar todo el lote, así que un agente defectuoso no puede hundir la ejecución.
Siempre haz .filter(Boolean) a los resultados. La concurrencia está limitada alrededor de tu número de núcleos y el exceso se encola, así que puedes pasar cien thunks y todos terminarán - solo unos pocos a la vez.
1phase('Research');23// Nueve fuentes, nueve agentes, todos a la vez.4const raw = await parallel(5 SOURCES.map((s) => () =>6 agent(s.prompt, {7 label: `research:${s.key}`,8 phase: 'Research',9 schema: ITEM_SCHEMA, // cada nodo devuelve JSON validado10 agentType: 'general-purpose',11 }),12 ),13);1415const collected = raw.filter(Boolean); // elimina los null de los agentes fallidos
La distribución vive en código que Claude escribió, no en una conversación del modelo. El propio contexto de Claude nunca contiene nueve fuentes a la vez - cada subagente lleva las suyas, y solo la respuesta final regresa.
Eso es lo que permite a Claude escalar un flujo de trabajo a docenas o cientos de subagentes sin ahogar la sesión. La capa de orquestación cuesta cero tokens porque no es otro turno de Claude pensando.
06. Convierge en una barrera
Una distribución solo es útil si algo la recolecta. La convergencia es el nodo donde las aristas convergen - donde un agente (o un fragmento de código) ve todos los resultados anteriores a la vez y hace algo que requiere el conjunto completo: deduplicar entre fuentes, clasificar por impacto, salida temprana si el total regresó vacío. Este es el único lugar donde una barrera justifica su costo en tiempo de reloj.

La regla que mantiene los grafos rápidos: usa una barrera solo cuando una etapa genuinamente necesita todos los resultados anteriores juntos. ¿Deduplicar entre todas las fuentes? Barrera - correcto.
1// La arista: JS plano, sin agente, cero tokens.2const flat = collected.flatMap((c) => c.items);3log(`Collected ${flat.length} items`);45phase('Curate');6// El nodo barrera: necesita el conjunto COMPLETO para deduplicar + clasificar.7const curated = await agent(8 `Deduplica y clasifica estos por impacto:\n${JSON.stringify(flat)}`,9 { phase: 'Curate', schema: CURATED_SCHEMA },10);
¿Solo aplanar una lista? Eso es una arista, hazlo en línea. La prueba de olfato es brutal y simple: si escribiste parallel → transformación → parallel, y esa transformación intermedia no tiene dependencia entre elementos, deberías haber usado un pipeline y omitido la barrera por completo.
07. El diamante: dividir → trabajar → fusionar
Junta la distribución y la convergencia y obtienes la topología de trabajo de todo grafo de agente serio: el diamante.
Un nodo divide el trabajo, muchos nodos hacen el trabajo en paralelo, un nodo fusiona. Es la forma detrás de un análisis de mercado, una auditoría de dependencias, una revisión de código, un informe de investigación - intercambia las fuentes y los prompts y el mismo esqueleto se adapta.

La forma canónica tiene un nombre que vale la pena memorizar: distribuir → reducir → sintetizar. Distribuye para obtener amplitud, reduce con código plano para comprimirla, sintetiza con un agente final para escribir la respuesta.
Una vez que ves el diamante, dejas de preguntar "cómo hago que mi agente haga más pasos" y empiezas a preguntar "dónde está la división, dónde está la fusión" - que es la pregunta que realmente escala.
08. Enruta la arista en tiempo de ejecución con un condicional
No todos los grafos son fijos. A veces, la arista a tomar depende de lo que un nodo encontró. Un nodo enrutador inspecciona un resultado y decide qué camino descendente se activa - clasifica el ticket, luego bifurca al manejador correcto; verifica el tamaño del diff, luego haz una revisión rápida o inicia una auditoría completa.
En un flujo de trabajo, esto es solo un if o switch de JavaScript sobre la salida validada de un nodo, porque el flujo de control vive en el código.

Aquí es donde el determinismo se convierte en una característica, no en una limitación. La decisión del enrutador puede ser impulsada por Claude (un subagente clasifica), pero el enrutamiento es código que Claude escribió - así que se ejecuta de la misma manera cada vez para la misma clasificación.
Obtienes el juicio de Claude en el nodo y la confiabilidad del script en la arista. Sin sorpresas de "Claude decidió saltarse la auditoría" - porque el salto tendría que estar escrito en el grafo, y no lo está.
1// Nodo enrutador: un agente clasifica, el código elige la arista.2const { severity } = await agent(3 `Clasifica el riesgo de este diff:\n${diff}`,4 { schema: { type: 'object',5 properties: { severity: { enum: ['low', 'high'] } },6 required: ['severity'] } },7);89let review;10if (severity === 'high') {11 // ruta pesada: auditoría paralela completa12 review = await parallel(FILES.map((f) => () => agent(`Audita ${f}`)));13} else {14 // ruta ligera: una pasada rápida15 review = await agent(`Revisión rápida de ${diff}`);16}
09. Pon un verificador en la arista
El verdadero apalancamiento de un grafo no son más agentes - es la estructura que puedes envolver alrededor de ellos para producir confianza.
Un nodo verificador se sitúa en la arista antes de que un resultado pueda pasar al siguiente, y su único trabajo es intentar matar el hallazgo. Si sobrevive, pasa. Si no, nunca llega a la respuesta.

Tres patrones vale la pena tener en tu arsenal.
- Verificación adversarial: para cada hallazgo, genera N escépticos independientes con el prompt de refutarlo; consérvalo solo si una mayoría sobrevive.
- Verificación con perspectivas diversas: dale a cada verificador una lente distinta - corrección, seguridad, se-reproduce - porque la diversidad atrapa modos de fallo que N verificaciones idénticas nunca detectarán.
- Panel de jueces: genera N intentos desde diferentes ángulos, puntúalos con jueces en paralelo, sintetiza a partir del ganador mientras injertas lo mejor de los subcampeones.
Este es exactamente el patrón que permitió a un equipo real portar el runtime de Bun con revisión de código adversarial integrada en el bucle.
10. Aísla los nodos para que un fallo no pueda envenenar el grafo
En una cadena, un fallo se propaga en cascada - C muere, D nunca se ejecuta, todo se detiene. En un grafo, el fallo debe estar contenido en su nodo.
Eso ya es parcialmente cierto: un thunk que lanza una excepción dentro de parallel() se resuelve como null, así que ocho agentes buenos aún devuelven resultados mientras uno malo se cae. Tu .filter(Boolean) es la contención.
Diseña cada convergencia para tolerar entradas faltantes en lugar de asumir un conjunto completo.

El fallo más sutil son los nodos pisándose unos a otros. Cuando los agentes escriben archivos en paralelo, pueden colisionar.
La solución es el aislamiento: "worktree" - cada agente se ejecuta en su propio worktree de git, hace su trabajo en un sandbox y se fusiona limpiamente.
Recurre a ello solo cuando los nodos realmente escriban en paralelo. Es el cinturón de seguridad para la única topología que lo necesita, no un impuesto predeterminado en cada ejecución.
11. Añade un ciclo - pero haz que converja
A veces no sabes lo grande que es el trabajo hasta que estás dentro: descubrimiento de tamaño desconocido, una barrida de bugs donde encontrar un bug revela tres más. Eso necesita un ciclo - una arista controlada de vuelta a un nodo anterior.
El peligro es obvio: un ciclo que no converge es un bucle infinito que genera agentes hasta que tu presupuesto se agota.

El patrón que converge es bucle-hasta-agotar: sigue generando buscadores hasta que K rondas consecutivas no produzcan nada nuevo, luego detente. El único detalle que lo hace funcionar o lo rompe - y el error que casi todos cometen la primera vez - es contra qué deduplicas.
Deduplica contra todo lo visto, no solo contra los resultados confirmados. De lo contrario, los hallazgos rechazados reaparecen cada ronda, el bucle nunca se agota, y has construido una máquina que paga por redescubrir los mismos callejones sin salida para siempre.
1const seen = new Set(); const confirmed = []; let dry = 0;23while (dry < 2) { // detente después de 2 rondas vacías4 const found = (await parallel(5 FINDERS.map((f) => () => agent(f.prompt, { schema: BUGS }))6 )).filter(Boolean).flatMap((r) => r.bugs);78 const fresh = found.filter((b) => !seen.has(key(b)));9 if (!fresh.length) { dry++; continue; } // nada nuevo → hacia la sequía10 dry = 0;11 fresh.forEach((b) => seen.add(key(b))); // deduplica contra VISTO, no confirmado1213 // verifica con lentes diversos cada hallazgo nuevo antes de que cuente14 const judged = await parallel(fresh.map((b) => () =>15 parallel(['correctness', 'security', 'repro'].map((lens) => () =>16 agent(`Juzga "${b.desc}" vía ${lens} — ¿real?`, { schema: VERDICT })))17 .then((v) => ({ b, real: v.filter(Boolean).filter((x) => x.real).length >= 2 }))));1819 confirmed.push(...judged.filter((v) => v.real).map((v) => v.b));20}
12. Escalona los modelos a través de los nodos
No todos los nodos necesitan tu mejor modelo. Un grafo hace esto obvio de una manera que un agente único nunca lo hace: algunos nodos son delimitados y repetitivos (extrae este campo, clasifica este ticket), y otros llevan el verdadero juicio (sintetiza el informe, adjudica el hallazgo).
Ejecuta los nodos aburridos en un modelo más barato y gasta tus tokens caros donde realmente vive el juicio.

En un flujo de trabajo, cada subagente que Claude genera hereda el modelo de tu sesión a menos que el script lo sobrescriba - así que por defecto, una ejecución grande factura enteramente al nivel de tu sesión. La opción model en una llamada agent() individual le dice a Claude que enrute solo ese nodo a otro lugar.
Verifica /model antes de una ejecución grande, luego haz que Claude enrute los nodos repetitivos de la distribución a un modelo más barato y mantenga el nodo de fusión arriba. Esta es la palanca que convierte un grafo hambriento de tokens de caro a económico sin tocar su forma.
13. La topología es tu costo y latencia
La forma del grafo no es cosmética - es la palanca más grande en el tiempo de reloj. La elección que tropieza a todos: parallel() versus pipeline(). Una barrera parallel() hace que todo espere al nodo más lento antes de que la siguiente etapa comience.
Un pipeline() transmite cada elemento a través de todas las etapas independientemente, sin barrera - el elemento A puede estar en la etapa 3 mientras el elemento B todavía está en la etapa 1. Los elementos rápidos terminan temprano en lugar de estar inactivos detrás de los lentos.

Por defecto, usa pipeline(). Recurre a una barrera solo cuando una etapa genuinamente necesita todos los resultados anteriores a la vez - una deduplicación entre conjuntos, una salida temprana sobre el total, un prompt que compara contra "los otros hallazgos." "Es código más limpio" y "las etapas se sienten separadas" no son razones; la latencia de la barrera es tiempo real, medible y desperdiciado. Separado no es lo mismo que sincronizado.
14. Deja que Claude dibuje el grafo - auto-enrutamiento
El movimiento final es dejar de dibujar el grafo a mano para trabajos que no puedes planificar de antemano.
Con los flujos de trabajo dinámicos, describes el objetivo y Claude escribe el script de orquestación él mismo - descomponiendo la tarea, eligiendo la distribución, generando una flota coordinada de subagentes y sintetizando el resultado. Obtienes un grafo adaptado a esta ejecución en lugar de uno fijo que esperabas que funcionara.

Hay tres formas de entrar. Di la palabra "workflow" en tu prompt y Claude escribe uno para la tarea. Ejecuta uno guardado o empaquetado - /deep-research es un grafo real en producción: alcance → búsqueda paralela → obtener → verificación adversarial → sintetizar, el esqueleto exacto de este curso.
O activa ultracode y Claude planifica un flujo de trabajo para cada tarea sustancial en la sesión. Cuando una ejecución es buena, presiona s para guardar su script en .claude/workflows/ - con control de versiones, re-ejecutable por nombre, un grafo que cualquiera que clone el repositorio puede lanzar.
1› Ejecuta un flujo de trabajo para auditar cada ruta en src/routes/ en busca2de autenticación faltante. Genera un agente por archivo de ruta, luego verifica cada hallazgo antes3de reportar. ● Claude escribió un script de orquestación · lanzando en segundo plano…4/workflows — auth-audit · ejecutándose ✓ Alcance 1/1 2.1k tok ·54s ✓ Distribución 18/18 un agente por archivo de ruta ◯ Verificar 11/18 3-voto6escépticos por hallazgo… ○ Sintetizar 0/1 esperando verificación la sesión se mantiene7responsiva — sigue trabajando mientras la flota se ejecuta
Seis grafos para construir con Claude esta semana

- Barrido de seguridad en cada ruta. Claude genera un subagente por archivo de ruta, cada uno buscando verificaciones de autenticación faltantes, luego una pasada de verificación confirma cada hallazgo antes de que llegue al informe. Amplitud que ningún contexto único podría retener.
- Informe citado con /deep-research. Un grafo que ya viene incluido en Claude Code. Claude descompone tu pregunta en ángulos distintos, ejecuta búsquedas paralelas, deduplica fuentes, luego verifica adversarialmente cada afirmación con escépticos de tres votos antes de escribir.
- Porta un módulo, archivo por archivo. El techo de Bun, escalado a tu repositorio. Claude distribuye la traducción entre archivos, ejecuta la suite de pruebas como una compuerta en cada uno, y repite los fallos de vuelta - revisión adversarial atrapando lo que una sola pasada enviaría roto.
- Revisión adversarial de un diff. Claude enruta según el tamaño del diff: un cambio pequeño recibe una pasada rápida, uno grande desencadena una auditoría paralela completa con revisores en lentes distintas - corrección, seguridad, rendimiento - luego un panel de jueces sintetiza.
- Escaneo de ecosistema programado. Guárdalo una vez, ejecútalo para siempre. Claude verifica muchas fuentes en paralelo - lanzamientos, blogs, discusiones - clasifica por impacto en una barrera, y escribe el resumen. Con control de versiones en .claude/workflows/, lanzable por nombre.
- Descubrimiento de tamaño desconocido. No sabes cuántos bugs hay. Claude ejecuta buscadores en paralelo, deduplica cada nuevo hallazgo contra todo lo visto, verifica los sobrevivientes, y sigue en bucle hasta que dos rondas no produzcan nada nuevo - entonces se detiene.
Conclusión:
Un promptista hace una pregunta. Un arquitecto dibuja un grafo.
El agente lineal nunca fue el techo - era solo la primera forma, la que todos usan porque coincide con cómo escribimos. Una línea, una cabeza, una cosa a la vez.
Una vez que puedes ver los nodos y las aristas, dejas de pedirle al agente que haga más y empiezas a pedirle al grafo que lo haga más amplio: distribuye donde el trabajo es independiente, pon compuertas en las aristas donde la confianza importa, escalona los modelos donde el juicio no está.
La mayoría seguirá poniendo pasos en cola en una línea. Los que aprendan a dibujar el grafo ejecutarán una flota - y nunca notarán el techo bajo el que el resto está atrapado.





