En una arquitectura multiagente típica, el Orchestrator delega tareas a agentes especializados y procesa sus respuestas. El problema aparece cuando un agente devuelve una salida mal formada: XML con etiquetas desbalanceadas, JSON inválido, campos obligatorios ausentes o tipos de datos incorrectos. En estos casos, el Orchestrator no siempre puede detectar el error de forma confiable, lo que provoca fallos silenciosos y aumenta la probabilidad de alucinaciones.
Plantillas de datos estructurados y Output Contracts para reducir alucinaciones
Los Output Contracts son una estrategia de validación estructurada para la comunicación entre agentes y el Orchestrator en arquitecturas multiagente. Consisten en encapsular la respuesta de cada agente dentro de un envelope XML que contiene un payload JSON validado mediante un JSON Schema específico para ese agente.
Un Output Contract define de forma explícita el formato que el agente debe producir. Mientras que los system prompts establecen reglas de comportamiento, los contratos de salida eliminan la ambigüedad sobre la estructura de la respuesta.
En un sistema multiagente, un output es el input del siguiente agente. Si ese output no respeta un formato conocido, el agente receptor puede interpretar la información de manera incorrecta, y es precisamente en esa interpretación donde suelen aparecer las alucinaciones de acción. Al establecer un contrato de formato entre subagentes, ese margen de interpretación desaparece, reduciendo errores sin necesidad de añadir lógica adicional de validación en cada paso.
Los tres bloques que componen un Output Contract son:
Arquitectura
El sistema está compuesto por:
- Un Contract Validator encargado de analizar y validar las respuestas.
- Un schema base con los campos comunes.
- Un schema específico por agente (Developer, Planner, Reviewer, Orchestrator, etc.).
- Un conjunto de pruebas automatizadas para verificar el comportamiento.
El flujo de validación consiste en:
- Extraer el envelope XML.
- Parsear el JSON.
- Validar los campos base.
- Validar el payload contra el schema del agente.
- Retornar un resultado indicando si el contrato es válido.
Implementación paso a paso
Paso 1: Crear el Schema base
El primer paso consiste en definir un Schema base con los campos obligatorios que debe incluir toda respuesta generada por un agente. Este esquema representa la estructura mínima del output y sirve como punto de partida para que todos los subagentes compartan un formato consistente antes de aplicar las validaciones específicas de cada rol.
Paso 2: Crear Schemas específicos por agente
Cada agente requiere reportar información distinta según las responsabilidades definidas en su system prompt. Por ello, cada uno cuenta con un Schema específico que amplía el Schema base, incorporando únicamente los campos necesarios para ese rol. De esta forma, se mantiene una estructura común para todos los agentes sin perder la flexibilidad de validar respuestas especializadas.
Paso 3: Modificar los system prompts de los agentes (formato del envelope)
En este paso se modifican los system prompts de los agentes que deberán responder utilizando el formato definido por el Output Contract. En este ejemplo, se actualizará el Developer, indicándole explícitamente que todas sus respuestas deben ajustarse al envelope establecido y referenciando la ubicación del Schema específico del agente para que pueda generar un output válido.
Paso 4: Crear el validador (contractValidator.js)
Una vez definidos los Schemas y configurados los system prompts, el siguiente paso es implementar el Contract Validator. Este componente será el encargado de recibir la respuesta del agente, extraer el envelope XML, parsear el payload JSON y validar tanto el Schema base como el Schema específico del agente. Si el contrato es válido, la respuesta podrá continuar con el flujo de ejecución; de lo contrario, se devolverán los errores de validación correspondientes.
Con esto validamos, en tiempo real, que la respuesta de cada agente cumpla con el contrato definido.
Esta implementación es solo un ejemplo. Si deseas ver el contenido completo del validador, puedes consultarlo en contractValidator.js
Paso 4.5: Invocar el validador
Existen dos formas de validar el output de cada agente utilizando contractValidator.js:
Usar el hook nativo tool.execute.after de OpenCode. Esta sería la solución más limpia y apropiada, ya que permitiría ejecutar automáticamente contractValidator.js después de cada respuesta del agente. Sin embargo, actualmente esta opción está bloqueada debido al *Blocked by OpenCode Issue #25918, por lo que, de momento, no es viable.
Realizar la validación desde el system prompt. Como alternativa temporal, el propio agente invoca contractValidator.js, enviando su output para ser validado. En la práctica, esta estrategia emula el comportamiento que tendría tool.execute.after y podrá reemplazarse por el hook nativo cuando este esté disponible.
Cuando el agente genera una respuesta, el proceso de validación sigue el siguiente flujo:
- Se extrae el contenido del bloque .
- Se parsea el payload JSON.
- Se carga el Schema correspondiente al agente.
- Se ejecuta validatePayload(payload, schema).
- Si la validación falla, la ejecución se detiene y se solicita al agente generar nuevamente la respuesta.
¿Por qué hacerlo? Porque permite detectar errores de formato antes de que la respuesta continúe en el flujo de trabajo, garantizando consistencia entre agentes y reduciendo la propagación de errores.
Paso 5: Validar la respuesta del agente
Todo comienza con una única cadena de texto (raw input): la respuesta que produce el agente. A partir de esta salida, el validador extrae el contrato, interpreta su contenido y verifica que cumpla con la estructura esperada.
A continuación veremos un ejemplo real de la respuesta generada por un Developer después de implementar un middleware de autenticación basado en JWT.
En este ejemplo pueden identificarse claramente las partes que conforman un Output Contract:
Etiqueta XML (): marca el inicio y el final del bloque estructurado. Corresponde al formatting prompt y permite localizar de forma confiable el contenido que debe validarse.
JSON interno: contiene el payload con la información estructurada que el resto del flujo puede consumir de manera fiable.
Campos fijos (agent, timestamp, version, etc.): pertenecen al Schema base y garantizan que el Orchestrator o cualquier otro agente disponga siempre de la misma información para continuar el flujo de trabajo.
¿Qué estamos ganando con esta estrategia?
Antes (solo texto libre)
Sin un Output Contract, cada agente responde en lenguaje natural y el Orchestrator debe interpretar qué quiso decir. Esto genera múltiples problemas:
- No existe un formato garantizado para las respuestas.
- Cada agente puede estructurar la información de forma diferente.
- Un JSON inválido o un XML mal formado puede romper todo el flujo.
- El Orchestrator debe asumir e interpretar datos, aumentando las probabilidades de alucinación.
- Los errores suelen detectarse tarde, cuando ya se propagaron al resto de agentes.
- Integrar nuevos subagentes requiere adaptar constantemente la lógica de interpretación.
Después (Markdown + Output Contract)
Con un Output Contract, el agente deja de responder con texto libre y entrega una estructura predecible y validable.
¿Qué cambia?
- El Orchestrator ya no necesita interpretar el texto para saber qué ocurrió.
- El estado de la ejecución, los errores y el resultado vienen en campos explícitos.
- Cada respuesta sigue exactamente el mismo formato.
- El contrato puede validarse automáticamente antes de continuar el flujo.
- Los agentes consumidores reciben datos consistentes, reduciendo las alucinaciones y los errores en cascada.
El Orchestrator deja de "adivinar" el significado de la respuesta y pasa a trabajar con datos estructurados y confiables. Esto hace que la comunicación entre agentes sea más robusta, predecible y fácil de mantener, especialmente a medida que la arquitectura crece en complejidad.
El resultado
La respuesta sigue siendo igual de legible para una persona; continúas leyendo el mismo texto generado por el agente. La diferencia es que, al final, se incluye un pequeño bloque estructurado (Output Contract) que el Orchestrator procesa internamente.
De esta forma, humanos y agentes consumen la misma respuesta, pero cada uno utiliza la parte que le corresponde: el desarrollador lee el contenido en lenguaje natural, mientras que el Orchestrator interpreta el contrato estructurado para continuar el flujo de trabajo de forma segura y consistente.
¿Qué mejora en la experiencia?
Si el Orchestrator puede leer esos datos estructurados, deja de depender de interpretar texto libre y puede ofrecer respuestas mucho más inteligentes y precisas. Por ejemplo, puede:
- Detectar automáticamente si una tarea finalizó con éxito o falló.
- Identificar el agente que produjo la respuesta y actuar en consecuencia.
- Mostrar errores claros y contextualizados sin analizar lenguaje natural.
- Reintentar únicamente la tarea que falló, en lugar de reiniciar todo el flujo.
- Encadenar agentes de forma más confiable al consumir datos validados.
- Generar métricas, auditorías y trazabilidad de cada ejecución.
En otras palabras, los Output Contracts no solo reducen las alucinaciones, sino que también mejoran la confiabilidad, la observabilidad y la experiencia general de trabajar con arquitecturas multiagente.
En resumen
No pierdes legibilidad; ganas automatización.
- Tú sigues leyendo un Markdown claro, estructurado y fácil de entender.
- El Orchestrator consume el JSON del Output Contract, lo valida y puede gestionar el flujo de trabajo de forma profesional, sin depender de interpretar texto libre ni de cometer errores de interpretación.
En definitiva, una misma respuesta satisface dos necesidades: una experiencia de lectura cómoda para las personas y un formato estructurado y confiable para los agentes.











Top comments (0)