ADR-0019: Respuesta estructurada del agente
- Estado: Accepted
- Fecha: 2026-05-27
- Responsables de la decisión: Waldemar Szemat
Contexto y planteamiento del problema
Section titled “Contexto y planteamiento del problema”Los evaluadores de corrección de la negativa y de la escalamiento deciden “¿se rehusó el agente?” / “¿escaló el agente?”. Decidir eso coincidiendo subcadenas de prosa libre contra tablas de marcadores solo en inglés es frágil de tres formas concretas:
- Las tablas de marcadores están solo en inglés. El arnés incluye los idiomas es-419 y pt-BR (ADR-0001), pero los evaluadores no pueden ver una negativa en esos idiomas a menos que la prosa contenga por casualidad las subcadenas en inglés. Una expresión regular multilingüe distinta existía en paralelo en la capa de barreras de seguridad - dos capas de marcadores paralelas que derivan de forma independiente.
- Añadir una nueva subplantilla de negativa (hay seis:
input-malformed,out-of-scope-dosing,out-of-scope-diagnosis,out-of-scope-interpretation,out-of-scope-pii,out-of-scope-meta) requiere ampliar la tabla de marcadores; una subcadena omitida califica silenciosamente una negativa como una respuesta. - La señal de la puerta de evaluación es, estructuralmente, una coincidencia de subcadenas n-de-N sobre prosa que el modelo puede parafrasear legítimamente. Dos negativas semánticamente idénticas pueden obtener una calificación de 1.0 y 0.0 según la elección de palabras.
La mejora hacia un dominio de agente estructurado necesitaba que el contrato fuera robusto antes de apilar encima la recuperación con RAG y un evaluador centrado solo en la recuperación. ¿Cómo hacemos que el discriminador sea estructural en lugar de basado en prosa, manteniendo sin cambios el renderizado del texto del asistente existente en la SPA?
Factores de decisión
Section titled “Factores de decisión”- Corrección estructural: el discriminador no debe depender de la elección de palabras de la prosa ni del idioma.
- Portabilidad entre proveedores: el contrato debe funcionar en Groq, OpenAI, Anthropic y el stub en proceso. La cobertura del modo JSON varía marcadamente entre proveedores.
- Compatibilidad hacia atrás: las pruebas existentes, la puerta de evaluación y la SPA deben seguir funcionando durante la migración. Sin una reescritura de “big bang”.
- Señal de evaluación: el tipo estructurado se mapea directamente a las expectativas must_refuse / must_escalate que los casos de evaluación ya llevan, de modo que el evaluador se convierte en una comprobación de discriminador de una sola línea.
- Presupuesto de spans: los atributos de traza para la respuesta estructurada deben caber en el presupuesto de observabilidad existente (política de spans con solo metadatos de ADR-0006).
Opciones consideradas
Section titled “Opciones consideradas”- Opción A: Mantener la prosa + ampliar las tablas de marcadores de subcadenas por idioma + añadir capas de expresiones regulares por idioma.
- Opción B: Migrar cada adaptador al uso de herramientas nativo con una
única herramienta
agent_replycuyo esquema imponga la envoltura. - Opción C: Añadir un esquema de Pydantic
AgentReply, solicitar el modo JSON por proveedor (cada adaptador degrada con cortesía a la mejor superficie de JSON disponible), validar en la capa del agente, consumir el discriminador en la capa del evaluador y dejar obsoleta la coincidencia de subcadenas en tres etapas.
Resultado de la decisión
Section titled “Resultado de la decisión”Opción elegida: Opción C - esquema de Pydantic + modo JSON por proveedor + obsolescencia escalonada de la capa de subcadenas.
La única razón determinante es la asimetría entre proveedores del
soporte de uso de herramientas: Anthropic ofrece uso de herramientas de forma
nativa, los proveedores compatibles con OpenAI (Groq, OpenAI) ofrecen
response_format={"type":"json_schema",...} directamente, y la ruta del
cliente stub no necesita ninguno de los dos. La opción B forzaría a los
adaptadores compatibles con OpenAI a tomar un desvío innecesario hacia el uso de
herramientas solo para igualar a Anthropic. La opción C deja que cada adaptador
use su idioma nativo y la capa del agente valida una forma agnóstica del
proveedor a la salida.
La respuesta estructurada es una pequeña envoltura validada con cuatro campos:
kind- uno derefusal,answeroescalation(el discriminador que leen los evaluadores).text- el mensaje del asistente renderizado en el idioma (no vacío).citations- la lista de identificadores de fragmentos de la KB que respaldan la respuesta.rationale- una breve explicación interna (con longitud acotada).
La capa del agente valida la envoltura y fija la respuesta estructurada en
el estado del agente desde el nodo de generación de respuesta y los ayudantes
de emisión de negativa / respuesta / escalamiento; la solicitud de completado y
los tipos de resultado llevan los campos de modo JSON, encauzados a través del
transporte compartido. Los evaluadores leen el discriminador kind
estructurado directamente; las tablas de marcadores de subcadenas, los
ayudantes de coincidencia de prosa y sus ramas de respaldo no existen en la
capa de evaluación, y el sitio de llamada posterior a las barreras de seguridad
consume la respuesta estructurada.
La postura del modo JSON por proveedor:
- Groq / OpenAI: nativo
response_format={"type":"json_schema","json_schema":{...,"strict":true}}mediante el constructor de cargas útiles compartido compatible con OpenAI. - Anthropic: sin bandera nativa; inyectar un preámbulo de modo JSON en el mensaje del sistema y analizar la respuesta con tolerancia. La migración al uso de herramientas se difiere (las cascadas hacia Anthropic son poco frecuentes; el enfoque del preámbulo mantiene ese proveedor utilizable sin una reescritura más profunda del adaptador).
- Stub: emite una envoltura de respuesta predefinida reutilizando las heurísticas existentes que tienen en cuenta el idioma.
- Respaldo: relevo transparente; el campo de solicitud de modo JSON sobrevive sin cambios a lo largo de primario → respaldo → último recurso.
Confirmación
Section titled “Confirmación”- Una prueba dedicada fija la forma del esquema y el viaje de ida y vuelta.
- Cada prueba de adaptador comprueba la forma de la carga útil de modo JSON en la solicitud y el campo estructurado en la respuesta.
- Cada prueba de integración del grafo comprueba que el
kindde la respuesta estructurada coincide con la ruta esperada. - La capa de evaluación no tiene referencias a tablas de marcadores de subcadenas (no queda ningún respaldo de coincidencia de prosa).
Consecuencias
Section titled “Consecuencias”Positivas
Section titled “Positivas”- El discriminador es invariante al idioma y sobrevive a cualquier paráfrasis que emita el modelo.
- Añadir una nueva subplantilla de negativa es una rama de tipo de respuesta de una sola línea, no una ampliación de la tabla de marcadores.
- Los evaluadores se vuelven triviales: una única comprobación de igualdad del discriminador por caso.
- La envoltura estructurada es el portador natural para la posterior mejora de spans de citación y el evaluador de recuperación-recall.
- La señal de evaluación se vuelve estructural; las paráfrasis con la misma semántica obtienen una calificación idéntica.
Negativas
Section titled “Negativas”- Las respuestas de Anthropic bajo el modo JSON pagan ~50 tokens de entrada por turno por el preámbulo del esquema. Las cascadas hacia Anthropic son poco frecuentes en una configuración con OpenAI como primario, de modo que el costo acumulado es pequeño, pero distinto de cero.
- Se añade una nueva superficie de abstracción (la envoltura de respuesta y su enumeración de tipos) a la API pública del paquete del agente.
- La capa de transporte gana dos campos de solicitud opcionales y un campo de resultado opcional; los adaptadores de proveedor deben respetarlos o documentar por qué no lo hacen.
Neutrales
Section titled “Neutrales”- El contrato de renderizado de la SPA no cambia: el contenido del último mensaje
sigue recibiendo el
textrenderizado en el idioma. La envoltura estructurada es observable en el estado del agente y en los spans de traza, pero no en el flujo SSE (los tipos de evento de SSE se amplían por separado en el streaming de tokens). - Las llamadas en modo JSON se ejecutan a una temperatura determinista; las rutas de forma libre mantienen un valor por defecto bajo.
Pros y contras de las opciones
Section titled “Pros y contras de las opciones”Opción A: ampliar las tablas de marcadores por idioma
Section titled “Opción A: ampliar las tablas de marcadores por idioma”- Buena, porque no requiere cambios en los adaptadores.
- Mala, porque las tablas de marcadores crecen con cada nuevo idioma y cada nueva subplantilla; la deriva entre los marcadores de la capa de evaluación y la expresión regular de la capa de barreras de seguridad empeora.
- Mala, porque la señal de evaluación sigue acoplada a la prosa; las paráfrasis aún se califican mal.
Opción B: uso de herramientas nativo en todos los proveedores
Section titled “Opción B: uso de herramientas nativo en todos los proveedores”- Buena, porque el esquema se impone en el límite del proveedor.
- Mala, porque Groq / OpenAI adquieren un desvío de uso de herramientas que no necesitan (ya ofrecen json_schema directamente).
- Mala, porque la tasa de activación del uso de herramientas (el modelo decidiendo
cuándo llamar a la herramienta) es un modo de fallo adicional que no existe con un
response_formatforzado.
Opción C (elegida): esquema de Pydantic + modo JSON por proveedor + obsolescencia escalonada
Section titled “Opción C (elegida): esquema de Pydantic + modo JSON por proveedor + obsolescencia escalonada”- Buena, porque cada adaptador usa su idioma nativo.
- Buena, porque la migración es escalonada y reversible en cada punto de control.
- Buena, porque la envoltura estructurada es el portador natural para los posteriores spans de citación y el evaluador centrado solo en la recuperación.
- Mala, porque la falta de una bandera nativa en Anthropic obliga a una postura de preámbulo de prompt + análisis tolerante que otros adaptadores no necesitan.