DEV Community

Cover image for Cómo Probar Agentes de IA No Deterministas (Cuando temperatura=0 No Basta)
Roobia
Roobia

Posted on • Originally published at apidog.com

Cómo Probar Agentes de IA No Deterministas (Cuando temperatura=0 No Basta)

Tu prueba pasó el lunes: misma entrada, mismo código y temperature=0. El martes falló sin cambios en tu aplicación. La aserción esperaba una cadena exacta, pero el modelo devolvió la misma respuesta con una redacción ligeramente distinta. El agente funciona; tu suite de pruebas no.

Prueba Apidog hoy

Este es el coste de probar sistemas que llaman a modelos de lenguaje. Incluso con temperatura cero, no obtendrás salidas idénticas byte a byte entre ejecuciones. En lugar de probar la redacción exacta, prueba el contrato: estructura, campos, rangos y efectos esperados. Este artículo profundiza en el tercer modo de fallo de nuestra guía sobre por qué los agentes de IA fallan en producción.

Por qué temperature=0 no significa determinismo

La temperatura controla cómo el modelo selecciona el siguiente token. Con temperature=0, el modelo elige el token más probable, lo que parece reproducible. Sin embargo, esa configuración no garantiza resultados idénticos.

La causa está debajo del modelo:

  • Las operaciones de punto flotante en GPU no son asociativas: el orden de las sumas puede modificar mínimamente el resultado.
  • Esa diferencia puede cambiar cuál token queda en primer lugar.
  • El orden de ejecución puede depender de cómo el proveedor agrupa solicitudes, del hardware, de la región o de la versión del kernel.
  • Los proveedores pueden cambiar GPUs, bibliotecas de inferencia o cuantización de pesos.

Una discusión extensa en vLLM explica por qué una semilla fija y temperature=0 no bastan para lograr reproducibilidad bit a bit.

La conclusión práctica es simple: el determinismo es una propiedad de toda la pila de servicio, no una opción de tu solicitud. Tu prueba debe aceptar variaciones de redacción cuando el significado y el contrato siguen siendo correctos.

Por qué las aserciones de cadena exacta vuelven inestable tu suite

Esta prueba es frágil:

assert response == "Your order total is $42.00."
Enter fullscreen mode Exit fullscreen mode

Puede pasar hoy y fallar mañana si el modelo responde:

Your total comes to $42.00.
Enter fullscreen mode Exit fullscreen mode

La respuesta sigue siendo correcta, pero la prueba se pone en rojo.

Las pruebas inestables tienen un coste operativo:

  1. El equipo empieza a ignorar los fallos.
  2. Se reintenta el pipeline hasta que pase.
  3. Las regresiones reales quedan ocultas entre falsas alarmas.
  4. La confianza en toda la suite disminuye.

Ya hemos explicado qué causa las pruebas inestables y cómo se propagan. La salida no determinista de un LLM es una de las formas más rápidas de crearlas.

No intentes resolverlo capturando más texto en snapshots. Haz lo contrario: desacopla la prueba de la redacción variable.

Prueba estructura y significado, no texto exacto

Un agente de soporte puede confirmar un reembolso de muchas maneras, pero una respuesta válida debería mantener los mismos hechos:

  • Importe del reembolso.
  • ID del pedido.
  • Estado de la operación.

Cambia esta pregunta:

¿El modelo dijo exactamente esta frase?

Por esta:

¿La respuesta tiene la forma correcta, los campos necesarios y valores válidos?

Estas son las estrategias más útiles.

1. Valida la respuesta con un esquema JSON

Si tu agente devuelve datos estructurados, define un esquema y valida cada respuesta contra él.

Por ejemplo, un resultado de reembolso podría exigir:

{
  "type": "object",
  "required": ["order_id", "status", "amount"],
  "properties": {
    "order_id": {
      "type": "string",
      "pattern": "^ORD-[0-9]+$"
    },
    "status": {
      "type": "string",
      "enum": ["refunded", "pending", "denied"]
    },
    "amount": {
      "type": "number",
      "minimum": 0
    }
  },
  "additionalProperties": false
}
Enter fullscreen mode Exit fullscreen mode

Este enfoque detecta fallos que sí importan:

  • Falta un campo obligatorio.
  • El modelo devuelve prosa en lugar de JSON.
  • Un objeto está anidado incorrectamente.
  • Un campo tiene un tipo inválido.
  • El estado contiene un valor no permitido.

Carga el esquema de respuesta en Apidog y valida las respuestas del agente contra el contrato. Cuando falle, verás el campo concreto que incumple el esquema, no una diferencia textual de cientos de caracteres.

2. Valida la forma de las llamadas a herramientas

Cuando un agente decide llamar a una herramienta, prueba la llamada, no la frase que la produjo.

Comprueba tres cosas:

  1. Que eligió la herramienta correcta.
  2. Que llamó al endpoint correcto.
  3. Que la carga útil cumple el esquema esperado.

Por ejemplo, un agente de reservas que llama a POST /reservations debería enviar:

{
  "guests": 2,
  "date": "2025-06-15"
}
Enter fullscreen mode Exit fullscreen mode

La prueba debe validar tipos y campos, independientemente del razonamiento textual del agente:

assert tool_call["name"] == "create_reservation"
assert tool_call["arguments"]["guests"] >= 1
assert isinstance(tool_call["arguments"]["guests"], int)
assert is_valid_date(tool_call["arguments"]["date"])
Enter fullscreen mode Exit fullscreen mode

También verifica que no aparezcan parámetros inventados:

allowed_fields = {"guests", "date"}
assert set(tool_call["arguments"]).issubset(allowed_fields)
Enter fullscreen mode Exit fullscreen mode

El método de extremo a extremo para probar las llamadas API de un agente cubre cómo capturar esos esquemas de herramientas y validarlos.

3. Usa rangos numéricos en lugar de valores exactos

Para números generados o calculados por el modelo, valida límites razonables en lugar de una cifra exacta.

Por ejemplo, para el total de un carrito:

assert response["total"] >= 0
assert response["total"] <= cart_subtotal + max_shipping + max_taxes
Enter fullscreen mode Exit fullscreen mode

Este tipo de prueba detecta errores relevantes:

  • Un total negativo.
  • Un importe desproporcionadamente alto.
  • Un total de cero para un carrito con productos.

También sirve para:

  • Puntuaciones de confianza.
  • Número de artículos.
  • Presupuestos de latencia.
  • Uso de tokens.
  • Límites de gasto.

Elige el rango más amplio que siga detectando un fallo real.

4. Verifica campos obligatorios y campos prohibidos

Dos comprobaciones simples ofrecen mucha cobertura:

  • Las claves necesarias existen y no son null.
  • Las claves sensibles o internas no aparecen.

Ejemplo para una respuesta de soporte:

required_fields = {"resolution", "ticket_id", "status"}
for field in required_fields:
    assert field in response
    assert response[field] is not None

forbidden_fields = {"internal_notes", "raw_prompt"}
for field in forbidden_fields:
    assert field not in response
Enter fullscreen mode Exit fullscreen mode

Estas aserciones no dependen de cómo se redacte el texto. Además, ayudan a evitar fugas de privacidad si el modelo incluye información que no debe llegar al usuario.

5. Usa verificaciones semánticas y umbrales para texto libre

A veces la salida debe ser prosa. En ese caso, valida propiedades estables del texto.

Por ejemplo:

assert order_id in response_text
assert len(response_text) <= 500

blocked_phrases = ["contraseña", "instrucciones internas", "raw prompt"]
for phrase in blocked_phrases:
    assert phrase.lower() not in response_text.lower()
Enter fullscreen mode Exit fullscreen mode

Si necesitas comprobar significado, compara la salida con una respuesta de referencia mediante similitud de incrustaciones y exige un umbral:

assert cosine_similarity(response_embedding, expected_embedding) >= 0.85
Enter fullscreen mode Exit fullscreen mode

Usa esta técnica como una puerta amplia, no como una garantía de precisión factual. Puede detectar que la respuesta se desvió del tema, pero no sustituye validaciones estructurales, de tipos y de rango.

6. Captura rangos, no snapshots de texto completo

Los snapshots siguen siendo útiles si congelas solo los elementos estables:

  • Conjunto de claves.
  • Tipos.
  • Valores enumerados.
  • Rangos numéricos.
  • Campos obligatorios.

En lugar de guardar una respuesta completa como esta:

{
  "message": "Tu reembolso de $42.00 ha sido procesado correctamente."
}
Enter fullscreen mode Exit fullscreen mode

Captura el contrato:

{
  "required_keys": ["message", "status", "amount"],
  "status": ["refunded", "pending", "denied"],
  "amount": {
    "minimum": 0,
    "maximum": 10000
  }
}
Enter fullscreen mode Exit fullscreen mode

Así, el snapshot falla por un cambio estructural que merece revisión, no por un sinónimo.

El estado y la memoria complican las pruebas

Las técnicas anteriores asumen una entrada y una salida. Los agentes con memoria añaden otra fuente de variación.

Una respuesta puede depender de:

  • Documentos recuperados.
  • Datos guardados en turnos previos.
  • Resúmenes de la conversación.
  • Orden de los mensajes anteriores.

Dos ejecuciones de la misma conversación pueden divergir porque la recuperación ordenó documentos de otra manera o porque un resumen anterior influyó en el razonamiento posterior. El explicador sobre cómo funciona la memoria del agente de IA detalla dónde reside ese estado y cómo se construye.

Aplica dos hábitos:

Inicializa el estado antes de cada prueba

Parte de una memoria conocida para no mezclar variación del modelo con variación del contexto:

agent.reset_memory()
agent.seed_memory({
    "customer_id": "CUST-123",
    "current_balance": 120.00,
    "open_reservations": []
})
Enter fullscreen mode Exit fullscreen mode

Prueba invariantes independientes de la ruta

No pruebes cada frase o cada paso interno. Prueba propiedades que deben mantenerse sin importar el recorrido:

assert final_state["current_balance"] >= 0
assert len(final_state["reservations"]) == 1
assert final_state["reservations"][0]["status"] == "confirmed"
Enter fullscreen mode Exit fullscreen mode

Estas aserciones sobreviven a un agente con estado y salida no determinista.

Simula las dependencias para repetir la prueba

No pruebes este comportamiento contra APIs externas en vivo. Las dependencias de terceros introducen límites de tasa, cambios de datos y otra fuente de aleatoriedad.

Para lograr pruebas repetibles, fija todo lo que no estés intentando probar.

Por ejemplo, simula:

  • La API de pagos con un recibo fijo.
  • La API de búsqueda con los mismos tres resultados.
  • La API de inventario con una disponibilidad conocida.
  • Los errores de red o respuestas 500 que necesitas reproducir.

Una dependencia simulada permite probar casos extremos de forma controlada:

{
  "status": "failed",
  "reason": "payment_provider_timeout"
}
Enter fullscreen mode Exit fullscreen mode

Después puedes verificar que el agente responde correctamente:

assert response["status"] == "pending"
assert "intenta de nuevo" in response["message"].lower()
Enter fullscreen mode Exit fullscreen mode

Usa Apidog para configurar simulacros con cuerpos de respuesta estables y combinarlos con validaciones de esquema. Esto forma parte de las pruebas de IA agéntica, donde simulación y aserción trabajan juntas.

Dónde encaja Apidog y dónde no

Es importante definir el alcance de la herramienta.

Apidog es una plataforma para diseño, pruebas y simulación de APIs. No es:

  • Un framework de agentes.
  • Un host de modelos.
  • Un runtime de agentes.
  • Una plataforma de evaluación u observabilidad.
  • Un sistema que construya, ejecute u orqueste el razonamiento del agente.

Su encaje está en la capa API con la que el agente se comunica.

Puedes usarlo para:

  1. Validar contratos de respuestas API del agente:

    • Esquemas JSON.
    • Campos obligatorios y prohibidos.
    • Tipos.
    • Rangos numéricos.
    • Forma de llamadas a herramientas.
  2. Simular dependencias externas:

    • Respuestas fijas.
    • Errores controlados.
    • Casos límite reproducibles.

La brecha que cubre Apidog es el contrato de solicitudes y respuestas, no el modelo que las genera.

Prueba el contrato, no la redacción

El no determinismo no es un error que se elimine con una configuración. Es una propiedad de ejecutar modelos de lenguaje, y temperature=0 no lo desactiva.

Para construir una suite fiable:

  • Valida esquemas.
  • Comprueba tipos y claves requeridas.
  • Bloquea campos prohibidos.
  • Usa rangos para valores numéricos.
  • Prueba la forma de las llamadas a herramientas.
  • Simula dependencias externas.
  • Inicializa la memoria del agente.
  • Aserciona invariantes de estado.

El resultado es una suite más útil: permanece en verde cuando solo cambia la redacción y falla cuando el contrato realmente se rompe.

Esta semana, elige una aserción inestable de tu suite y sustitúyela por una validación de esquema o de rango. Usa Apidog para validar las respuestas de tu agente contra un contrato y simular las dependencias que hacen repetibles tus pruebas.

Top comments (0)