Generación de casos de prueba para agentes de IA: entradas estructuradas a partir de esquemas JSON

Los generadores de Galtea ahora leen su JSON Schema y producen una entrada completa para cada caso de prueba, basada en la historia del caso y en la especificación bajo prueba. No solo un mensaje de usuario.

>Loading the Elevenlabs Text to Speech AudioNative Player...
Resumir este artículo

Los servicios de generación de Galtea crean casos de prueba sintéticos para productos de IA. Hay un generador para cada tipo de caso que admitimos: comportamiento para cobertura de múltiples turnos, precisión para generación de RAG y llamadas a herramientas, seguridad para entradas adversarias. Elija el que elija, obtendrá una lista de casos de prueba listos para evaluar frente a su agente.

La generación de casos de prueba para agentes de IA tiene un problema estructural que la evaluación de chats no tiene. Su agente nunca ve una cadena de texto simple. Ve una carga útil estructurada: un order_id, un requester_type, una configuración regional de sesión, un indicador de función, un nivel de cliente. Hasta hace poco, cada caso de prueba generado por los generadores de Galtea devolvía un único user_message al estilo de chat y nada más. Eso funcionaba para los asistentes de chat. No funcionaba para el conjunto mucho más amplio de agentes de IA donde la entrada en tiempo de ejecución es una carga útil estructurada.

Hemos añadido una nueva etapa que cierra esa brecha y que ahora se ejecuta en todos los generadores. Cuando proporciona un JSON Schema para su entrada, el generador completa cada campo por caso de prueba, utilizando la historia del caso y la especificación bajo prueba para elegir valores que realmente pongan a prueba el comportamiento. El resto de esta publicación explica el diseño utilizando la generación de escenarios como ejemplo práctico, pero el mismo poblador se ejecuta en todos los demás generadores de la plataforma.

Por qué la generación de casos de prueba para agentes de IA necesita su propia etapa

La cobertura es el objetivo principal de la generación de casos de prueba. Cada generador ya gestiona la cobertura al nivel que le interesa: los escenarios se etiquetan como directos, de borde o tangenciales respecto a la especificación, los casos de red-teaming se etiquetan por clase de ataque, los casos de estándar de oro se etiquetan por patrón de recuperación o llamada a herramienta. El problema estructural es lo que sucede después de que se escriben los casos.

Tomemos un escenario etiquetado como un impacto directo en una política de devoluciones: un destinatario de un regalo solicita devolver un portátil. Como historia, está bien. Pero su agente nunca ve la historia. Su agente ve una carga útil, y esa carga útil tiene un campo llamado requester_type; si ese campo está vacío o configurado con un valor predeterminado, ha generado un caso de prueba que en realidad no prueba la política.

Un poblador debe hacer dos cosas a la vez.

La primera es la validez estructural. Cada valor debe satisfacer el esquema: tipo correcto, enumeración permitida, entero dentro del rango, todos los campos obligatorios presentes. Un muestreador que conozca JSON-Schema puede resolver esto por sí solo.

La segunda es la validez narrativa. Cada valor debe coincidir con la historia del caso y, cuando hay una especificación bajo prueba, los valores deben hacer que la especificación sea realmente relevante. Un muestreador no puede resolver esto. El poblador necesita leer el caso y la especificación juntos, y luego elegir valores que pongan al sistema bajo estrés de la manera que describe el caso.

Generación de casos de prueba estructurados: un ejemplo práctico

Aquí está el caso de devoluciones de comercio electrónico que utilizamos internamente. El producto es un agente de atención al cliente para un minorista de electrónica. La especificación es "solo el comprador original puede iniciar una devolución; los destinatarios de regalos deben ser rechazados y redirigidos al comprador". El esquema es intencionalmente pequeño para que se lea de una sola vez.


{
  "type": "object",
  "properties": {
    "requester_type": { "enum": ["account_holder", "gift_recipient", "third_party"] },
    "return_allowed": { "type": "boolean" },
    "user_message":   { "type": "string" }
  },
  "required": ["requester_type", "return_allowed", "user_message"]
}

El generador produce cuatro escenarios que abarcan proximidades directas, de borde y tangenciales a la especificación. Para cada uno, el poblador devuelve un objeto JSON que se ajusta al esquema y refleja el escenario.

Escenario 1, impacto directo. Un destinatario de un regalo quiere devolver un portátil que recibió hace tres semanas.


{
  "requester_type": "gift_recipient",
  "return_allowed": false,
  "user_message": "I received this laptop as a gift three weeks ago and I'd like to return it. It's not quite what I need."
}

Escenario 2, impacto directo en el otro lado de la regla. El titular de la cuenta devuelve un monitor que compró personalmente.


{
  "requester_type": "account_holder",
  "return_allowed": true,
  "user_message": "Hi, I bought a monitor from my account two months ago and I'd like to start a return. The backlight has an issue."
}

Escenario 3, caso límite. Un familiar con autorización procesa una devolución en nombre del titular de la cuenta.


{
  "requester_type": "third_party",
  "return_allowed": false,
  "user_message": "I'm helping my mother process a return on her account. She's given me permission. What should I do?"
}

Escenario 4, tangencial. Una consulta previa a la compra sobre la cobertura de la garantía, sin ninguna devolución en curso.


{
  "requester_type": "account_holder",
  "return_allowed": true,
  "user_message": "Before I buy, can you explain how warranty coverage and returns work for these items?"
}

Vale la pena señalar algunos aspectos sobre los valores poblados. requester_type nunca es aleatorio; sigue la historia de cada escenario. return_allowed se establece según lo que indica la especificación, no según lo que el agente devuelve realmente al ejecutarse. Esa es la verdad fundamental con la que tu evaluador califica. Además, el caso tangencial sigue produciendo una carga útil totalmente válida, porque el agente bajo prueba siempre recibe una carga útil, incluso cuando la intención del usuario no es la que cubre la especificación.

Decisiones de diseño

Algunas decisiones en el poblador que son importantes si lo vas a integrar en un flujo de trabajo.

El modo consciente de la especificación es el predeterminado. Cuando se proporciona una especificación, el poblador se ejecuta en modo de puntuación de especificación. El mensaje enviado al modelo subyacente incluye tanto la historia del caso como la especificación, y se le indica al modelo que elija valores que pongan a prueba la especificación de manera genuina, en lugar de valores que la evadan. Sin una especificación, el poblador recurre al modo basado en mensajes, que mantiene los valores coherentes con la historia del caso pero no intenta forzar ninguna regla en particular.

El poblador utiliza salidas estructuradas, no análisis sintáctico. Se construye un modelo Pydantic de forma dinámica a partir de tu esquema JSON y se pasa como modelo de respuesta en la llamada al LLM. No hay análisis de JSON a partir de cadenas de texto ni bucles de reintento por salidas mal formadas. El modelo devuelve un valor que se valida contra tu esquema, o la llamada falla de forma evidente.

Los campos de toda la sesión se enrutan por separado. Los sistemas reales suelen tener campos de carga útil que son constantes durante toda la vida de una sesión: idioma, región, nivel de cliente, indicadores de funciones. El poblador respeta la anotación x-galtea-is-session-wide: true en cualquier propiedad de tu esquema. Los campos anotados se pueblan una vez por caso y se enrutan a un objeto de contexto independiente, de modo que el arnés pueda almacenarlos por sesión en lugar de por turno.

Cómo generar casos de prueba para agentes de IA con Galtea

El panel de control es la vía más sencilla. Cuando crees una prueba, pega tu esquema JSON en el campo Input Schema de la conexión del endpoint, selecciona "Generated by Galtea", añade una de tus especificaciones y ejecútala.

Si estás creando un producto de IA que acepta algo más complejo que una cadena de chat, esto debería permitirte omitir el paso de escribir tu propio código de integración entre los casos de prueba generados y tu entrada en tiempo de ejecución.