====== Patrones agénticos ====== Un patrón agéntico es una forma conocida de **conectar varias llamadas al modelo** para resolver algo que una sola llamada no resuelve bien. En el tema anterior vimos que el grafo es el mapa y el bucle es el camino; los patrones de aquí son los mapas que ya se sabe que funcionan. Cada patrón de esta página se le pide al agente **con texto**, y ese texto se deja escrito como una //skill// del proyecto (tema 2) para no reescribirlo cada vez. Los ejemplos de cada sección son eso: lo que hay que poner. El primero lleva la cabecera completa del ''SKILL.md''; en el resto va solo el cuerpo, que es lo que cambia. **Empieza por lo más simple que pueda funcionar.** Una llamada bien planteada con buen contexto resuelve la mayoría de las tareas. Cada patrón añade latencia, coste y sitios donde fallar, así que solo se sube de patrón cuando el anterior se queda corto de verdad, no porque quede mejor en el diagrama. ^ Patrón ^ Cuándo se usa ^ | [[#pipeline_prompt_chain|Pipeline]] | La tarea se parte en pasos fijos, conocidos de antemano | | [[#enrutador|Enrutador]] | Entradas de tipos distintos que se atienden mejor por separado | | [[#planificador-ejecutor|Planificador-Ejecutor]] | Conviene revisar el plan antes de que se toque nada | | [[#orquestador|Orquestador]] | Las subtareas no se conocen hasta ver el problema | | [[#ejecutor-revisor|Ejecutor-Revisor]] | Hay criterios claros y la crítica mejora el resultado | | [[#adversarios|Adversarios]] | Interesa encontrar el fallo, no pulir el acabado | | [[#razonador-refutador|Razonador-Refutador]] | La causa de un fallo no está clara y conviene acertar antes de arreglar | | [[#best-of-n|Best-of-N]] | Los intentos salen muy distintos y verificar es barato | | [[#human-in-the-loop_hitl|Human-in-the-loop]] | Hay acciones irreversibles o responsabilidad de por medio | | [[#memoria_persistente|Memoria persistente]] | El trabajo dura más que una sesión | ---- ===== 1. Pipeline (prompt chain) ===== La tarea se parte en **pasos fijos** y la salida de cada uno es la entrada del siguiente. Entre paso y paso se pone una puerta que comprueba que lo producido sirve antes de seguir. start :paso 1; if (pasa la puerta) then (si) :paso 2; if (pasa la puerta) then (si) :paso 3; else (no) :corregir el paso 2; endif else (no) :corregir el paso 1; endif stop Es el patrón del //spec-driven development//: requisitos → diseño → tareas → código, con una aprobación en cada salto (tema 10). Cada paso ve un problema más pequeño y mejor acotado que el original, y por eso lo hace mejor. * **A favor**: cada paso es simple, verificable y depurable por separado. * **En contra**: latencia, y un error del paso 1 se arrastra hasta el final. De ahí que la puerta entre pasos sea obligatoria, no decorativa. * **Condición**: los pasos tienen que ser siempre los mismos. Si cambian según el problema, lo que hace falta es un orquestador. **Ejemplo.** Una funcionalidad nueva, de la petición al código. Como //skill// del proyecto, con su cabecera: --- name: pipeline-funcionalidad description: Implementa una funcionalidad nueva por fases. Usar cuando se pida añadir algo que no existe todavía. --- Implementa la funcionalidad en cuatro pasos. No empieces uno hasta cerrar el anterior. 1. REQUISITOS: escribe en docs/specs//requirements.md qué tiene que pasar y cómo se comprueba. Para y espera el visto bueno. 2. DISEÑO: a partir de ese fichero, escribe design.md: ficheros que se tocan, contratos, modelo de datos. Para y espera el visto bueno. 3. TAREAS: parte el diseño en tareas de menos de una hora en tasks.md, cada una con su criterio de hecho. 4. CÓDIGO: implementa las tareas en orden. Después de cada una lanza los tests; si fallan, arregla antes de pasar a la siguiente. Si en el paso 3 o en el 4 descubres que el diseño estaba mal, vuelve al paso 2 y corrígelo antes de seguir. ---- ===== 2. Enrutador ===== Una primera llamada **clasifica** la entrada y la manda a la ruta adecuada: otro prompt, otro modelo u otra herramienta. start :clasificar la peticion; if (tipo) then (bug) :flujo de depuracion; elseif (tipo) then (funcionalidad nueva) :flujo completo de spec; else (otro) :ruta por defecto; endif stop Los dos usos que de verdad aparecen: * **Por especialidad**: un //bug// va al flujo de depuración; una funcionalidad nueva, al flujo de especificación completo. * **Por coste**: lo fácil al modelo barato, lo difícil al caro. El ahorro es grande y la calidad no baja, porque lo que se enruta mal es lo que estaba en la frontera. **Siempre tiene que haber ruta por defecto.** El fallo típico del enrutador no es equivocarse de ruta, es no tener ninguna para lo que no encaja en ninguna categoría. **Ejemplo.** Clasificar lo que llega antes de ponerse a trabajar: Antes de tocar nada, clasifica la petición en una de estas rutas y di en una línea cuál has elegido: - BUG: algo que ya debería funcionar y no funciona. -> Reproduce el fallo con un test que falle, arregla, comprueba que el test pasa. No refactorices nada más por el camino. - FUNCIONALIDAD: algo que no existe todavía. -> Flujo completo: requisitos, diseño, tareas, código. - CAMBIO MECÁNICO: renombrar, mover, subir una dependencia. -> Hazlo y enseña el diff. Sin especificación. - NO ENCAJA: si dudas entre dos rutas, o no es ninguna, pregunta. No elijas por tu cuenta. ---- ===== 3. Planificador-Ejecutor ===== Se separa **decidir qué hacer** de **hacerlo**. El planificador produce un plan escrito; el ejecutor lo cumple paso a paso. La ventaja es que el plan es un artefacto **revisable antes de que se toque una sola línea**, que es justo cuando corregir sale barato. Es también el patrón que explota el modo //Plan// de las herramientas del tema 3: el modelo caro planifica, uno más barato ejecuta lo ya decidido. * **Cuándo**: cambios que tocan varios ficheros, o donde el enfoque importa más que el teclear. * **Riesgo**: un plan malo contamina todo lo que viene detrás, y el ejecutor no suele darse cuenta porque su trabajo es obedecer. Por eso el plan se lee. * **Detalle práctico**: si el plan queda escrito en un fichero del repositorio, el ejecutor puede ir marcando lo hecho y una sesión nueva retoma por donde iba. **Ejemplo.** Un cambio que toca varios ficheros: FASE 1, PLAN. No escribas código todavía. Lee el código afectado y escribe un plan con: - los ficheros que vas a tocar y qué cambia en cada uno - el orden de los cambios - lo que has descartado, y por qué - lo que no tienes claro, en forma de preguntas Para y espera a que apruebe el plan. FASE 2, EJECUCIÓN. Cumple el plan aprobado, y nada más que el plan. Si a mitad descubres que no se sostiene, para y dilo en lugar de improvisar otra solución por tu cuenta. ---- ===== 4. Orquestador ===== Un agente central mira el problema, **decide sobre la marcha en qué subtareas se parte**, se las reparte a trabajadores especializados y funde los resultados. start :orquestador: partir el trabajo; fork :trabajador A; fork again :trabajador B; fork again :trabajador C; end fork :orquestador: fundir resultados; stop La diferencia con el pipeline es **quién decide los pasos**: en el pipeline están escritos de antemano; aquí los decide el orquestador en tiempo de ejecución, al ver el caso concreto. En desarrollo con IA la ventaja que más se nota no es el paralelismo, es el **contexto**: cada trabajador arranca con su propia ventana limpia y solo con lo suyo, así que el orquestador puede abarcar un problema que no cabría en una sola conversación. * **A favor**: control centralizado, trazable y reproducible; subtareas en paralelo. * **En contra**: el orquestador es un punto único de fallo —si parte mal el trabajo al principio, todo lo de debajo sobra— y el coste se multiplica por el número de trabajadores. * **Lo difícil está en la fusión**: juntar resultados parciales que se contradicen es más trabajo del que parece al dibujarlo. **Ejemplo.** Diseño, implementación y calidad, cada uno en su agente. Un subagente **empieza de cero y no sabe nada de esta conversación**, así que el encargo lleva dentro quién es y qué tiene que devolver: Eres el orquestador: no escribes código, repartes el trabajo y unes el resultado. Cada subagente que lances arranca en blanco, así que dile en el propio encargo quién es, qué le das, qué tiene que devolver y qué no puede tocar. 1. Lanza un subagente con este encargo: "Eres el diseñador. Tienes el repositorio en solo lectura: no escribes ni modificas nada. Dado este enunciado , devuelve el enfoque, la lista de ficheros que hay que tocar y los contratos entre las partes. No implementes." 2. Parte el diseño en trozos independientes y lanza un subagente por cada trozo: "Eres quien implementa . Este es el trozo de diseño que te toca: , y estos los contratos que tienes que respetar: . Implementa solo eso. No toques ficheros fuera de esta lista: . Devuelve el diff y los tests que añadas." 3. Junta los resultados. Si dos se contradicen, resuélvelo tú y di cómo. 4. Sobre el resultado ya unido, lanza un subagente que no haya escrito nada de esto: "Eres el revisor de calidad de un código que no has escrito. Aquí tienes el diff completo y los requisitos . Busca requisitos sin cumplir, casos límite sin tratar y errores que se tragan. Devuelve cada hallazgo como BLOQUEANTE o MENOR." 5. Si vuelve algún BLOQUEANTE, repite el punto 2 solo con la parte afectada, añadiendo el hallazgo al encargo. A cada subagente pásale el texto que necesita, nunca la conversación entera: repartir el contexto es justamente para lo que sirve esto. ---- ===== 5. Ejecutor-Revisor ===== Un agente produce, **otro distinto** lo critica contra unos criterios, y se repite hasta que pase o hasta agotar las vueltas. start repeat :ejecutor: producir o corregir; :revisor: evaluar contra los criterios; backward:devolver con los comentarios; repeat while (aprobado) is (no) not (si) :entregar; stop Es la capa 5 del harnés (tema 4) convertida en patrón. Funciona cuando se cumplen las dos condiciones: - **Hay criterios claros** contra los que evaluar. Sin eso el revisor opina, y opinar no converge. - **La crítica mejora el resultado**, igual que a una persona le sirve que le revisen el código. El revisor tiene que ser **otro agente con el encargo explícito de buscar problemas**, y con límite de vueltas. Un modelo revisando su propia salida tiende a aprobarla; y sin tope de iteraciones, dos agentes se pueden pasar la tarde puliendo un detalle. **Ejemplo.** Uno programa y otro revisa. El revisor **se lanza en ese momento** y recibe en el encargo su papel y el material, porque no ha visto nada de lo anterior: Implementa la tarea. Al terminar, di qué has hecho y qué has dejado fuera a propósito. Después, sin revisarlo tú, lanza un subagente con este encargo: "Eres el revisor de este cambio, que no has escrito. Aquí tienes el diff y el requisito que dice lo que tenía que hacer . Revisa en este orden: 1. ¿Hace lo que pide el requisito? Cítalo. 2. ¿Casos límite sin tratar: nulos, lista vacía, concurrencia? 3. ¿Errores que se tragan sin registrar? 4. ¿Los tests comprueban el comportamiento o la implementación? Marca cada hallazgo como BLOQUEANTE o MENOR. No comentes estilo: de eso se encarga el formateador. Si no encuentras nada, dilo; no inventes hallazgos para justificar la revisión." Arregla los BLOQUEANTES y lanza un revisor **nuevo** con el diff ya corregido. Tres vueltas como máximo; a la tercera, para y resume lo que queda abierto. ---- ===== 6. Adversarios ===== La vuelta de tuerca del anterior: el segundo agente no pule, **ataca**. Su encargo no es «¿está bien?» sino «encuentra el caso en el que esto se rompe». ^ ^ Revisor ^ Adversario ^ | Pregunta | ¿Cumple los criterios? | ¿Por dónde falla? | | Produce | Una lista de mejoras | Un contraejemplo concreto | | Termina cuando | Aprueba | No encuentra por dónde entrar | Dónde se usa de verdad: * **Contra la especificación**: buscar el requisito ambiguo, el caso que no se contempló, la contradicción entre dos apartados. Sale mucho más barato aquí que en producción. * **Contra la implementación**: generar los tests que la rompen, no los que la confirman. Emparejado con el //mutation testing// del tema 7, que mide exactamente eso. * **Contra la seguridad**: el papel de //red team//. El valor está en que el criterio de éxito de los dos agentes es **opuesto**, y eso impide el acuerdo cómodo al que llegan dos modelos con el mismo objetivo. **Ejemplo.** Dos agentes defienden decisiones de arquitectura distintas. Cada uno recibe su papel al lanzarlo, y el papel es precisamente lo que los hace adversarios: Hay que decidir si el envío de correos va dentro de la petición o a una cola. No lo decidas tú: monta el debate. Lanza un subagente: "Defiende que el envío vaya dentro de la petición. Explica cómo se implementa, qué cuesta y qué se rompe el día que haya diez veces más tráfico. Este es el código de hoy: . No te cures en salud reconociendo las ventajas de la otra opción: tu trabajo es la mejor versión de esta." Lanza otro con el mismo encargo, cambiando la opción por la cola. Con las dos propuestas encima de la mesa, lanza un subagente por cada una: "Aquí tienes una propuesta de arquitectura . Tu único trabajo es encontrar el escenario concreto en el que falla: carga, fallo parcial, reintentos, despliegue, operación. No vale opinar ni pedir mejoras: hace falta el caso, con números si los hay." Y con todo eso, un último subagente que no haya participado: "Aquí tienes dos propuestas de arquitectura y los ataques que ha recibido cada una . Decide una y escribe en docs/adr/ la decisión, el motivo y la opción descartada con su razón. Si las dos aguantan igual, dilo: entonces se elige la más fácil de deshacer." ---- ===== 7. Razonador-Refutador ===== Antes de arreglar nada, un agente **escribe su razonamiento paso a paso** —qué ha visto, qué deduce de ello y qué piensa hacer— y otro distinto **busca el paso que no se sostiene**. Solo cuando el razonamiento aguanta se toca el código. start repeat :razonador: explicacion con hechos, deducciones y plan; :refutador: buscar el paso que no se sostiene; backward:la prueba en contra pasa a ser un hecho; repeat while (razonamiento solido) is (no) not (si) :implementar el plan; stop Se parece a los dos anteriores, pero mira otra cosa y en otro momento: ^ ^ Revisor ^ Adversario ^ Refutador ^ | Pregunta | ¿Cumple los criterios? | ¿Por dónde falla? | ¿Se deduce esto de lo que hemos visto? | | Mira | El resultado terminado | Una propuesta o una implementación | La explicación del problema | | Cuándo | Después de hacerlo | Antes o después | Antes de tocar nada | El fallo que evita es muy común: **una solución impecable para un problema que no era el problema**. El modelo ve un síntoma, se convence de una causa y la arregla con todo detalle. El Refutador hace las preguntas incómodas: ¿eso lo has comprobado o lo supones?, ¿de verdad se sigue de lo anterior?, ¿hay otra explicación para lo mismo? **Por qué gana el Refutador aunque tenga menos pruebas.** Para que una explicación sea cierta tiene que cumplirse **todo** lo que exige; para que sea falsa basta con que falle **una sola cosa**. Por eso mil pistas a favor no pesan nada frente a un hecho que la hace imposible. Por ejemplo, fallan 30 tests con ''NullPointerException'' dentro de ''PedidoService.calcularTotal()'', y el Razonador concluye que el pedido llega sin cliente. El Refutador lee el código: el constructor de ''Pedido'' lanza una excepción si no recibe cliente, así que un pedido sin cliente nunca llega hasta ahí. La explicación es falsa, da igual cuántos tests fallen. **Qué pasa cuando gana.** El trabajo no termina ahí: vuelve al Razonador, y **lo que ha tumbado la explicación pasa a ser un hecho comprobado**. Con esa pista nueva, el Razonador propone otra explicación —«el cliente nunca es nulo, así que el nulo sale de otro campo que usa ''calcularTotal()'': el descuento, que solo se rellena cuando hay cupón»— y el Refutador intenta tumbarla también. Esta vez no puede: los 30 tests que fallan crean pedidos sin cupón y los que pasan, con cupón. Se repite hasta que una explicación aguanta, y solo entonces se arregla. Cada vuelta descarta una causa y deja un hecho más, así que el círculo se va cerrando. * **Cuándo**: tests que unas veces pasan y otras no, código lento sin causa clara, errores cuyo origen no se ve a simple vista. * **En contra**: más tiempo y más coste. Si la causa era obvia desde el principio, sobra. * **Regla del Refutador**: puede comprobar hechos —leer el código, lanzar un test—, pero no propone soluciones ni escribe código. Solo señala qué paso no se sostiene y con qué prueba. **Ejemplo.** Encontrar la causa de un fallo antes de arreglarlo. El auditor **se lanza en ese momento** y no sabe nada del problema, así que el encargo lleva el contexto y el razonamiento: Hay un fallo y no está claro de dónde viene. No toques código todavía. FASE 1, RAZONAMIENTO. Escribe tres listas: - HECHOS: lo que has visto de verdad: errores, trazas, qué tests fallan y cuáles no. Solo lo comprobado. - DEDUCCIONES: qué concluyes, un paso por línea, diciendo de qué hecho sale cada uno. - PLAN: qué cambiarías y qué esperas que pase después. FASE 2, REFUTACIÓN. Sin revisarlo tú, lanza un subagente con este encargo: "Eres un auditor de lógica. Aquí tienes el contexto del problema y un razonamiento sobre su causa . Comprueba solo esto: 1. ¿Se da algo por cierto sin haberlo comprobado? 2. ¿Hay algún paso que no se deduce del anterior? 3. ¿Hay otra causa que explique los mismos hechos y se ha pasado por alto? Puedes comprobar lo que haga falta sin modificar nada. No propongas soluciones ni escribas código. Devuelve cada paso que no se sostiene con la prueba que lo tumba, o 'RAZONAMIENTO SÓLIDO'." FASE 3. Si vuelve algún fallo, añade sus pruebas a HECHOS, formula otra explicación que las respete y lanza un auditor nuevo. Tres vueltas como máximo; a la tercera, para y resume lo descartado y lo que queda abierto. Con 'RAZONAMIENTO SÓLIDO', implementa el plan. Más informnación: * [[https://dzone.com/articles/multi-agent-infrastructure-observability|What Actually Makes AI Infrastructure Agents More Reliable (It's Not More Agents)]] ===== 8. Best-of-N ===== Se lanza **el mismo encargo N veces en paralelo** —con temperatura alta o con modelos distintos— y se elige el mejor resultado. Sirve porque los intentos salen genuinamente distintos entre sí. Lo difícil no es generar: es **elegir**. Y de eso depende que el patrón valga o no valga nada: ^ Cómo se elige ^ Fiabilidad ^ | Verificador objetivo: compila, pasa los tests, mide mejor en el //benchmark// | Alta. Es el caso que interesa | | Un modelo juez compara las N salidas | Regular: hereda los sesgos del juez | | Una persona mira las N | Alta, pero no escala | * **Cuándo**: verificar es mucho más barato que generar, y un intento suelto falla a menudo. El caso claro en código es tener N implementaciones y quedarse con la que pasa la batería de tests. * **En contra**: cuesta N veces. Se reserva para el trozo difícil, no para todo el trabajo. **Ejemplo.** Tres diseños, y solo uno se implementa: Diseña TRES soluciones distintas para esta tarea. Distintas de verdad: si las tres son la misma con otros nombres, vuelve a empezar. De cada una: el enfoque en cinco líneas, los ficheros que toca, qué se gana, qué se paga, y qué pasa el día que haya que añadir un proveedor más. Compáralas en una tabla contra estos criterios, por orden: 1. cumple el requisito 2. esfuerzo de implementación 3. lo que cuesta cambiarla dentro de un año 4. cuánto código nuevo mete en el proyecto Recomienda una, y di en qué caso cambiaría la recomendación. No implementes ninguna hasta que te diga cuál. ---- ===== 9. Human-in-the-loop (HITL) ===== No es «que alguien lo mire»: es **decidir en qué puntos concretos se para y se espera a una persona**. Los tres sitios donde tiene sentido poner la puerta: * **Aprobar el plan**, antes de que se escriba nada. El punto más rentable de todos: corregir aquí cuesta un párrafo. * **Aprobar la acción irreversible**, justo antes de ejecutarla. * **Aprobar la entrega**, antes de que salga de cara al cliente. Lo que pasa por una persona **siempre**: borrar datos, desplegar, mandar correos, gastar dinero, tocar producción. Todo lo que el historial no deshace. **La persona va en la puerta, no en cada paso.** Un flujo que pide confirmación de todo acaba aprobándose a ciegas, y eso es peor que no tener puerta: da la sensación de control sin el control. Las capas de abajo —límites, comprobaciones, revisión automática— están para reducir lo que llega al humano a lo que de verdad necesita criterio. **Ejemplo.** La persona aprueba la especificación antes de que empiece el diseño: Escribe la especificación en requirements.md y PARA. No empieces el diseño, no escribas código, no propongas el paso siguiente. Termina el documento con dos listas: - las decisiones que has tomado por tu cuenta porque el enunciado no las decía (esta es la parte importante: es donde se cuela lo que yo no quería) - las preguntas que necesitas que conteste una persona Sigo yo. Cuando te diga "aprobado", pasas al diseño. Cualquier otra respuesta es una corrección de los requisitos. ---- ===== 10. Memoria persistente ===== Un agente empieza de cero cada sesión. La memoria persistente es lo que le permite retomar el trabajo y acumular lo aprendido. Tres tipos, con papeles distintos: ^ Memoria ^ Qué guarda ^ Dónde vive ^ | **De trabajo** | El contexto de la tarea actual | La ventana de contexto. Se pierde al cerrar | | **Episódica** | Qué se hizo, qué se intentó y qué falló | El plan con lo hecho marcado, el historial de decisiones | | **Semántica** | Hechos estables del proyecto: convenciones, arquitectura, reglas | ''CLAUDE.md'', ''AGENTS.md'', ''.kiro/steering/'', los ADR | En desarrollo, la memoria que funciona son **ficheros dentro del repositorio**, no una base vectorial. Son legibles por una persona, van versionados, se revisan en el //pull request// y se corrigen a mano cuando dicen una tontería. Una base vectorial aporta cuando el volumen no cabe en ficheros; antes de eso es complejidad que solo estorba. Lo que hay que decidir explícitamente es la **política de actualización**: qué se escribe, cuándo y quién lo borra. Una memoria a la que solo se añade se pudre: acumula decisiones viejas que ya no valen, y el agente las sigue a rajatabla porque no sabe que caducaron. **Ejemplo.** Los ficheros que el agente lee al empezar y mantiene al terminar: La memoria de este proyecto son ficheros. Antes de nada, lee: .kiro/steering/ reglas que valen para todo el proyecto docs/specs// requisitos, diseño y tareas de lo que hacemos docs/adr/ decisiones ya tomadas, y por qué Reglas: - Si algo de lo que te digo contradice lo que hay escrito, gana lo escrito y me avisas. - Toda decisión que afecte a tareas futuras va a docs/adr/ el mismo día. - Al terminar una tarea, márcala en tasks.md. La sesión siguiente empieza leyendo ese fichero, no preguntándome por dónde ibas. - Si un documento ha dejado de ser verdad, corrígelo en el mismo cambio que lo desmiente. Nunca escribas encima dejando debajo la versión vieja. ---- ===== 11. Cómo elegir ===== ^ Patrón ^ Fuerte en ^ Su límite ^ Coste ^ | Pipeline | Pasos simples y verificables uno a uno | Los pasos son rígidos | Bajo | | Enrutador | Ahorro y especialización | Se equivoca al clasificar | Bajo | | Planificador-Ejecutor | Corregir cuando aún es barato | Un plan malo contamina todo | Medio | | Orquestador | Problemas grandes, contexto repartido | Punto único de fallo; la fusión | Alto | | Ejecutor-Revisor | Calidad con criterios claros | Sin criterios, no converge | Medio-alto | | Adversarios | Encontrar lo que falla | No mejora el acabado | Medio | | Razonador-Refutador | Acertar con la causa antes de arreglar | Sobra si la causa era obvia | Medio | | Best-of-N | Calidad cuando verificar es barato | Se paga N veces | Alto | | HITL | Responsabilidad y lo irreversible | El humano es el cuello de botella | Bajo, pero lento | | Memoria persistente | Trabajo que dura semanas | Se pudre sin mantenimiento | Bajo | Los patrones **se combinan**, y casi siempre se usan combinados. Las dos combinaciones que aparecen una y otra vez en desarrollo con IA: * **Planificador → HITL → Pipeline → Ejecutor-Revisor**: se planifica, una persona aprueba el plan, se ejecuta por fases y cada fase pasa por revisión. Es, punto por punto, lo que hacen los frameworks SDD del tema 11. * **Orquestador → trabajadores → Adversario**: se reparte el trabajo grande y al final un agente intenta romper el resultado unificado. ===== Fuentes ===== * [[https://dzone.com/articles/ai-agent-architectures-patterns-applications-guide|AI Agent Architectures: Patterns, Applications, and Implementation Guide]]