Agent Mentor Learn
Colaboración multiagente · Lección 6 de 6

Lección 6: Práctica: Construir un pipeline de revisión de dos agentes

Objetivos de aprendizaje:

  • Escribir un pipeline productor-revisor de dos agentes genuinamente ejecutable con la API de Claude
  • Lograr que el revisor devuelva un resultado de revisión estructurado y comprobable en lugar de un «se ve bien» generalizado
  • Poner una válvula de seguridad al bucle para que el productor y el revisor no puedan pulir de ida y vuelta para siempre

Requisitos: haber terminado las Lecciones 1-5, poder leer JavaScript/Node.js básico, y tener una clave de API de Claude que funcione | Anterior: Lección 5 <<

Primero, el resultado: una ejecución completa

Esto es lo que tendrás en marcha al final de la lección. Le entregas una tarea a la terminal, y dos agentes se turnan hasta que la revisión pasa o llegas al límite de rondas:

$ node review-pipeline.js "Escribe un anuncio de cambio de API para desarrolladores: el endpoint v2 cambia el campo user_id de número a cadena"
[Productor v1]¡Ya llegó el endpoint v2! Experiencia enormemente mejorada — por favor cámbiate pronto a la nueva versión.
[Revisor ronda 1] Rechazado. Problemas:- No detalla el campo específico que afecta este cambio (nunca menciona que user_id pasa de número a cadena)- No da ningún consejo de migración; los desarrolladores no saben cómo actualizar su código- «Experiencia enormemente mejorada» es una afirmación exagerada e inverificable, sin base concreta
[Productor v2]Aviso de cambio de la API v2: el tipo del campo user_id cambia de number a string.Revisa cada trozo de código que parsee este campo y cambia la lógica de lectura de numérica a cadena,para evitar fallos de parseo por el desajuste de tipo. Este cambio entra en vigor en la v2.1.0.
[Revisor ronda 2] Aprobado
Borrador final (aprobado en la ronda 2):Aviso de cambio de la API v2: el tipo del campo user_id cambia de number a string.Revisa cada trozo de código que parsee este campo y cambia la lógica de lectura de numérica a cadena,para evitar fallos de parseo por el desajuste de tipo. Este cambio entra en vigor en la v2.1.0.

La primera versión es rebotada por el revisor, con razones atadas a cada criterio específico; el productor la corrige hacia una segunda versión, el revisor mira de nuevo, y esta vez pasa. Este es el patrón productor-revisor de la Lección 4 convertido en código: "one LLM call generates a response while another provides evaluation and feedback in a loop."1

La forma general: el mismo esqueleto que un bucle de ejecución

Si tomaste el curso Llamada a herramientas por el agente: hacer que los agentes hagan cosas de verdad de esta serie, el esqueleto de este pipeline te resultará familiar: un bucle, un juicio por ronda, un resultado que decide si seguir, más una válvula de seguridad contra el bucle infinito. La única diferencia es qué juzga el juicio — el bucle de ejecución de herramientas de aquel curso juzga «¿el modelo todavía quiere llamar a una herramienta?» (la semántica del bucle está en la lección El viaje completo de ida y vuelta de una llamada a herramienta de aquel curso y sus fuentes oficiales), mientras que aquí juzga «¿el revisor dijo que pasó?». Mismo esqueleto, distinto contenido en el cuerpo del bucle.

Todo el pipeline son tres funciones cosidas juntas: runProducer genera o corrige el texto, runReviewer lo puntúa contra criterios y da notas específicas, y runPipeline enlaza las dos en un bucle con un techo de rondas como válvula de seguridad.

Paso 1: El productor — toma la tarea, produce el texto

En su primera ejecución el productor tiene solo la tarea en sí; en una segunda ejecución tras un rechazo, también lleva la versión anterior completa y las notas de revisión, para que el productor corrija sobre la última versión según las notas en lugar de improvisar desde cero:

El prompt del productor es autocontenido. Como cubrió la Lección 3, un subagente no puede ver lo que pasó del lado del orquestador, y tampoco puede ver cómo fue revisado la última vez2. Así que cada llamada escribe «cuál es la tarea», «qué decía la versión anterior» y «(si lo hubo) cuáles fueron los problemas de la ronda pasada» de forma literal en el prompt de esta llamada. Fíjate en que hasta el propio borrador anterior del productor tiene que pasarse de forma explícita — esta es la mitad del principio de autocontención que más fácil se pasa por alto: la API de Messages es sin estado, cada petición debe llevar el historial completo que necesita, y el servidor no guarda nada entre peticiones3. «Corrige tu versión anterior» solo significa algo cuando la versión anterior fue realmente escrita en este prompt.

Paso 2: El revisor — puntúa contra criterios concretos, sin veredictos vagos

El revisor no se limita a preguntarle al modelo «¿esto está bien?». Como cubrió la Lección 5, la verificación tiene que aterrizar en criterios concretos y comprobables en lugar de una puntuación por impresión4. Aquí el revisor recibe una lista de comprobación explícita y se le exige responder en un formato JSON fijo:

Juntos, los campos approved e issues conforman un resultado de revisión estructurado: no un único «está bien», sino «pasa o falla» más «el problema específico detrás de cada criterio fallido». Una vez que el productor tiene issues, corrige esos problemas específicos en lugar de adivinar hacia dónde ir a partir de un veredicto vago.

Paso 3: No confíes ciegamente en el resultado de la revisión — trata un fallo de parseo como un rechazo

runReviewer devuelve una cadena, no un objeto JSON real, así que todavía hay que parsearla. Aunque al revisor se le diga que «responda estrictamente en JSON», sin una restricción de salida estructurada el modelo todavía puede producir JSON sintácticamente inválido, dejar caer campos, o envolver el JSON en un bloque de código con unas líneas de explicación alrededor5. La trampa aquí es: ¿qué pasa cuando el parseo falla? Tomar la ruta perezosa — dejarlo pasar por defecto ante un fallo de parseo — convierte en silencio un fallo de «el revisor no hizo su trabajo» en «revisión aprobada». Ese es justo el punto que planteó la Lección 5: una salida que «parece» terminada no es lo mismo que una salida que de verdad es correcta, y lo que no puedas verificar no deberías entregarlo6. Aquí hacemos lo contrario: un fallo de parseo siempre cuenta como un rechazo, nunca como un aprobado:

Las líneas typeof parsed.approved !== "boolean" y !Array.isArray(parsed.issues) extienden la misma idea — incluso cuando JSON.parse tiene éxito, todavía confirmas que los campos parseados tengan la forma correcta, y un tipo de campo incorrecto también cuenta como un rechazo. No bajes la guardia solo porque sea «al menos JSON válido».

Un apunte al margen: hay una función oficial de salidas estructuradas que garantiza, a nivel de muestreo, que la respuesta coincida estrictamente con un esquema5. Esta lección usa a propósito el estilo de «llamada pelada más tu propio parseo defensivo» para que sientas de primera mano que la salida del modelo no se puede confiar a ciegas; en producción puedes usar salidas estructuradas para eliminar este bache por completo.

Paso 4: Conéctalo en un bucle, agrega la válvula de seguridad

Con runProducer, runReviewer y parseReview en mano, runPipeline conecta las tres, y MAX_ROUNDS es la única válvula de seguridad aquí — el productor y el revisor podrían en teoría pulir para siempre, así que tiene que haber un techo:

Cuando llega a MAX_ROUNDS todavía sin pasar, runPipeline no fuerza un veredicto de «aprobado». Entrega honestamente el último borrador y los problemas aún sin resolver para revisión humana — esto también es el punto de la Lección 5 aplicado al paso de cierre: cuando la etapa de integración de resultados se topa con algo que no puede juzgar, no debería taparlo decidiendo por sí misma en código.

Resumen

  • El esqueleto del pipeline productor-revisor es la misma cosa que un bucle de ejecución: un bucle, un juicio por ronda, un resultado que decide si seguir, más una válvula de seguridad contra el bucle infinito. La definición oficial de este patrón es exactamente "one LLM call generates a response while another provides evaluation and feedback in a loop"1 — aquí el juicio cambia de «¿debería llamarse a una herramienta?» a «¿el revisor dijo que pasó?».
  • El prompt del productor es autocontenido: cada llamada escribe la tarea, la versión anterior completa, y (si los hubo) los problemas específicos de la ronda pasada de forma literal en el prompt — la API de Messages es sin estado, cada petición debe llevar el historial completo, y nada se guarda entre peticiones3, así que no puedes contar con que el modelo recuerde por su cuenta lo que pasó la ronda pasada2.
  • El revisor puntúa contra criterios concretos y comprobables, ítem por ítem, y devuelve un {approved, issues} estructurado en lugar de un veredicto generalizado4.
  • Lo que el revisor devuelve tampoco se puede confiar a ciegas — un fallo de parseo o una forma de campo incorrecta debería contar como un rechazo, no como un aprobado silencioso6; este principio aplica no solo a «confiar en lo que dice un subagente» sino también a «confiar en el formato de datos que devuelve un subagente».
  • Cuando llega al máximo de rondas todavía sin pasar, el pipeline debería entregar honestamente el último borrador y los problemas sin resolver para revisión humana, en lugar de decidir un aprobado por sí mismo en código.

Eso es todo lo de las seis lecciones de este curso: desde «por qué varios agentes», pasando por cómo el orquestador y los subagentes reparten el trabajo, cómo escribir prompts de delegación, qué patrón de colaboración encaja con qué escenario, y cómo manejar los fallos, terminando con construir a mano un pipeline productor-revisor que funciona. Lo más valioso que puedes hacer a continuación no es releer las explicaciones — es tomar una tarea pequeña y real que tengas a mano, dejarla caer en este esqueleto de pipeline, ajustar los criterios de revisión, y ejecutarlo para ver si rebota el borrador y cuántas veces. Ajustar tú mismo los criterios de revisión una vez vale más que releer la teoría diez veces.

Footnotes

  1. Building effective agents (Anthropic Engineering) — https://www.anthropic.com/engineering/building-effective-agents 2

  2. Create custom subagents (Claude Code Docs) — https://code.claude.com/docs/en/sub-agents 2

  3. Using the Messages API (Claude API) — https://platform.claude.com/docs/en/build-with-claude/working-with-messages 2

  4. How we built our multi-agent research system (Anthropic Engineering) — https://www.anthropic.com/engineering/multi-agent-research-system 2

  5. Structured outputs (Claude API) — https://platform.claude.com/docs/en/build-with-claude/structured-outputs 2

  6. Best practices for Claude Code (Claude Code Docs) — https://code.claude.com/docs/en/best-practices 2

Ejercicios

01

Ensambla el código de esta lección en un review-pipeline.js, ejecuta npm install @anthropic-ai/sdk, npm pkg set type=module, define ANTHROPIC_API_KEY, y ejecuta una vez la tarea de ejemplo de esta lección. Confirma que ves al menos una ronda «Rechazado» antes de ver «Aprobado». (Si la primera versión del productor pasa de largo, cambia por una tarea más fácil de tropezar — por ejemplo, pide a propósito «un anuncio muy corto» sin decir qué tan corto.)

Nivel 1: Ponlo a correr, luego agrega un criterio de revisión

Una vez que funcione, agrega un nuevo criterio a REVIEW_CRITERIA: «¿Menciona el texto el número de versión específico donde el cambio entra en vigor?». Córrelo de nuevo y confirma que los issues del revisor ahora incluyen una nota atada a este nuevo criterio.

Criterios de finalización · marcado local
02

La versión de parseReview de abajo tiene un problema. Primero explica la situación en la que dejaría pasar como «aprobado» un borrador que nunca fue realmente revisado, luego da el código arreglado.

Nivel 2: Rompe algo a propósito, luego arréglalo
Criterios de finalización · marcado local