Tu prueba pasó el lunes. Misma entrada, mismo código, temperature=0. El martes falló y no cambiaste nada. La aserción verificaba una cadena exacta y el modelo devolvió la misma respuesta formulada de forma ligeramente diferente. La prueba está en rojo, el agente funciona bien y ahora estás depurando tu suite de pruebas en lugar de tu producto.
Este es el costo de probar cualquier cosa que llame a un modelo de lenguaje. La salida se mueve, incluso cuando le dijiste que no lo hiciera. Establece la temperatura en cero y aun así no obtendrás respuestas idénticas byte a byte en diferentes ejecuciones. La mayoría de los desarrolladores aprenden esto por las malas, una vez, y luego reescriben cómo prueban. Esta guía te muestra cómo escribir aserciones que se mantengan firmes cuando el texto subyacente sigue cambiando. Es el análisis en profundidad del modo de fallo tres de nuestra guía sobre por qué los agentes de IA fallan en producción.
Por qué temperature=0 no significa determinista
La temperatura controla cómo el modelo muestrea el siguiente token. En cero, toma el token más probable cada vez, lo que parece que debería ser reproducible. No lo es, y las razones se encuentran debajo del modelo.
Las matemáticas de punto flotante no son asociativas en una GPU. Suma los mismos números en un orden diferente y obtendrás un resultado ligeramente diferente en la última cifra decimal. Esa pequeña diferencia puede inclinar qué token ocupa el lugar más alto, y un token diferente lo cambia todo después. El orden de esas adiciones depende de cómo el proveedor agrupa tu solicitud con otro tráfico, qué hardware la ejecuta y qué versión del kernel se implementa ese día. No controlas nada de eso.
Los proveedores también cambian cosas por su parte. Intercambian GPUs, actualizan bibliotecas de inferencia, recuantifican pesos y dirigen tu llamada a una región diferente. Una larga discusión en vLLM explica por qué una semilla fija y temperature=0 aún no son suficientes para la reproducibilidad bit a bit. La versión corta: el determinismo es una propiedad de toda la pila de servicio, no una bandera que configuras en tu solicitud.
Así que deja de tratar la salida idéntica como la línea base. El modelo te da una respuesta que significa lo mismo, expresada de la forma en que salga en esta ejecución. Tus pruebas tienen que aceptar eso.
Las aserciones de cadena exacta hacen que tu suite sea inestable
Aquí está la trampa. Escribes assert response == "Your order total is $42.00." porque eso es lo que volvió la primera vez. Pasa. Luego el modelo devuelve “Your total comes to $42.00” y la prueba falla con una respuesta correcta.
Una prueba que falla con una respuesta correcta es peor que no tener ninguna prueba. El equipo aprende que esta suite es una falsa alarma. La gente la ejecuta de nuevo hasta que se pone verde, luego dejan de leer los fallos, y luego se pierden la regresión real enterrada en el ruido. Las pruebas inestables no solo hacen perder tiempo, sino que erosionan la confianza en toda la suite, y ya hemos escrito antes sobre qué causa las pruebas inestables y por qué se propagan. La salida no determinista es una de las formas más rápidas de generarlas.
El instinto es fijar la salida más firmemente: capturar la cadena exacta, hacerle una instantánea, compararla. Eso empeora la inestabilidad, porque has acoplado tu prueba a lo único que está garantizado que cambiará. Necesitas el movimiento opuesto.
Aserciones sobre la estructura y el significado, no sobre el texto exacto
La salida varía, pero el contrato subyacente no debería. Un agente de soporte podría redactar una confirmación de reembolso de cien maneras, pero cada respuesta válida conlleva los mismos hechos: un importe de reembolso, un ID de pedido, un estado. Prueba los hechos, no la redacción.
Ese es todo el cambio. Deja de preguntar “¿dijo el modelo exactamente esto?” y empieza a preguntar “¿la respuesta tiene la forma correcta, los campos correctos y valores en el rango adecuado?” Esas propiedades sobreviven a la reformulación. Una regresión real, un campo faltante, un número fuera de los límites, una carga malformada, aún activará la aserción. Aquí están las estrategias que ponen esto en práctica.
Valida la respuesta contra un esquema JSON
Si tu agente devuelve datos estructurados, define un esquema JSON para ellos y valida cada respuesta contra ese esquema. El esquema verifica tipos, campos obligatorios, enumeraciones permitidas y formatos sin preocuparse por valores específicos. Un campo `status` debe ser uno de `refunded`, `pending` o `denied`. Un `order_id` debe coincidir con tu patrón de ID. Un `amount` debe ser un número, no una cadena.
Esta es la aserción más fuerte que puedes escribir contra una respuesta no determinista, porque detecta los fallos que duelen: el modelo omitió un campo, anidó el objeto incorrectamente o devolvió prosa donde esperabas JSON. Carga el esquema de tu respuesta en Apidog y valida las respuestas en vivo del agente contra él. Una discrepancia nombra el campo exacto que falló, no una diferencia de cadena de 400 caracteres.
Asegúrate de que la llamada a la herramienta tenga la forma y el objetivo correctos
Cuando tu agente decida llamar a una herramienta, prueba la llamada, no la frase que la originó. Aserciona tres cosas: que eligió la herramienta correcta, que apuntó al objetivo correcto y que la carga útil coincide con el esquema de la herramienta. Un agente de reservas que llama a `POST /reservations` debería enviar `guests` como un entero y una `date` válida, sin importar el razonamiento en lenguaje natural que produjo esa llamada.
Esta es la misma disciplina que validar un cuerpo de respuesta, aplicada a la solicitud saliente. Verifica que existan los parámetros requeridos, que los tipos sean correctos y que no se hayan colado campos inventados. El método de extremo a extremo para probar las llamadas API de un agente cubre la captura de esos esquemas de herramientas y la aserción contra ellos. La carga útil de una llamada a herramienta tiene un contrato incluso cuando la redacción que la rodea no lo tiene.
Usa rangos numéricos en lugar de valores exactos
Para cualquier número que el modelo produzca o pase, aserciona un rango, no un valor. Un agente de carrito de compras calcula un total. No conoces la cifra exacta en cada ejecución, carrito y regla de impuestos, pero sabes que no puede ser negativa y no puede exceder el valor del carrito más el envío máximo y los impuestos. Así que aserciona eso: la respuesta contiene un `total` entre 0 y ese límite superior.
Ese único límite detecta los fallos que importan, un total negativo, un total diez veces demasiado grande, un total de cero en un carrito lleno, mientras ignora la variación que no te importa. Los rangos funcionan para puntuaciones de confianza, recuentos de artículos, uso de tokens, presupuestos de latencia y cualquier cifra derivada. Elige el límite más amplio que siga fallando con un error genuino.
Verifica que existan las claves requeridas y que los campos prohibidos estén ausentes
Dos aserciones baratas tienen mucho peso. Primero, que las claves de las que dependes estén presentes y no sean nulas. Segundo, que las claves que nunca deben aparecer estén ausentes. Un agente que maneja un ticket de soporte debe devolver una `resolution`, y nunca debe filtrar un campo `internal_notes` o `raw_prompt` al cliente.
Las verificaciones de presencia y ausencia son inmunes a la reformulación por diseño, ya que prueban el esqueleto de la respuesta, no su contenido. También son tu protección más barata contra toda una clase de fugas de privacidad, donde el modelo incluye útilmente un campo que debería haber mantenido privado.
Usa verificaciones semánticas y de umbral para texto libre
A veces la carga útil es prosa y aun así necesitas probarla. La coincidencia exacta no funcionará, así que verifica las propiedades en su lugar. ¿La respuesta contiene el número de pedido que le pasaste? ¿Se mantiene por debajo de un límite de longitud? ¿Evita una lista negra de frases que nunca quieres enviar a un usuario?
Cuando realmente necesites probar el significado, compara por similitud de incrustaciones contra una respuesta de referencia y aserciona que la puntuación supera un umbral, en lugar de exigir que las cadenas coincidan. Trata estas verificaciones semánticas como una puerta gruesa, no precisa. Atrapan una respuesta que se desvió del tema. No detectarán un error factual sutil, así que combínalas con las aserciones estructurales anteriores.
Captura rangos, no instantáneas exactas
Las pruebas de instantáneas todavía tienen un lugar, siempre y cuando captures las partes estables. Congela la forma de la respuesta, el conjunto de claves, los tipos, los valores enumerados y permite que los campos de flujo libre varíen dentro de los límites. En la práctica, tu instantánea registra “esta respuesta tiene las claves a, b, c, con b en este rango y c de este conjunto” en lugar de un bloque congelado de texto exacto. Cuando la instantánea falla, falla por un cambio estructural que vale la pena revisar, no por un sinónimo.
El estado y la memoria lo hacen más difícil
Todo lo anterior asume una solicitud de entrada, una respuesta de salida. Los agentes no funcionan así. Llevan memoria entre turnos, y ese estado multiplica las fuentes de variación.
La respuesta de un agente con estado depende de lo que recuperó, lo que almacenó anteriormente y en qué orden se ejecutaron los turnos anteriores. Dos ejecuciones de la misma conversación pueden divergir porque un paso de recuperación clasificó los documentos de manera diferente, o porque un resumen escrito en el turno dos dio forma al razonamiento en el turno cinco. Ahora tu salida varía por dos razones combinadas: el no determinismo propio del modelo y un estado inicial diferente. Nuestro explicador sobre cómo funciona la memoria del agente de IA detalla dónde reside ese estado y cómo se construye.
Dos hábitos mantienen esto probado. Primero, controla el estado que puedas. Siembra la memoria del agente a un punto de partida conocido antes de cada prueba, de modo que estés variando una cosa y no dos. Segundo, aserciona sobre invariantes que se mantienen independientemente del camino. Un saldo corriente nunca debería volverse negativo. Una conversación que reservó un vuelo debería terminar con exactamente una reserva, sin importar cuántos turnos tomó. Las aserciones independientes de la ruta son las que sobreviven a un agente con estado y no determinista.
Simula las dependencias para que la prueba se repita
No puedes ensayar nada de esto contra APIs de terceros en vivo. Te aplican límites de tasa, cambian sus datos y añaden una segunda fuente de aleatoriedad además del modelo. Para obtener una prueba repetible, fija todo lo que no sea el comportamiento que estás probando.
Simula las APIs que el agente llama y programa respuestas fijas. Ahora la API de pagos siempre devuelve el mismo recibo, la API de búsqueda siempre devuelve los mismos tres resultados, y lo único que queda en movimiento es el propio razonamiento del agente, que es lo que quieres observar. Una dependencia simulada también te permite forzar los casos extremos que una API saludable no producirá bajo demanda, y luego asercionar que el agente los maneja. Apuesta Apidog a las dependencias del agente para configurar esos simulacros con cuerpos estables y controlables, y emparejarlos con las aserciones de esquema anteriores. Esto se enmarca dentro de la práctica más amplia de las pruebas de IA agéntica, donde la simulación y la aserción trabajan juntas.
Dónde encaja Apidog (y dónde no)
Sé exacto sobre la función de la herramienta. Apidog es una plataforma de diseño, pruebas y simulación de APIs. No es un framework de agente, un host de modelo, un tiempo de ejecución de agente o una plataforma de evaluación y observabilidad. No construye tu agente, lo ejecuta, orquesta sus pasos ni puntúa su razonamiento.
Lo que sí posee es la capa API con la que tu agente se comunica, y ahí es donde residen estas pruebas. Dos encajes honestos. Escribes aserciones sobre las respuestas API del agente (validación de esquema, forma de respuesta, rangos numéricos, claves requeridas y prohibidas, forma de la carga útil de la llamada a la herramienta) que sobreviven a la salida no determinista. Y simulas las dependencias del agente para que una prueba se ejecute de la misma manera dos veces. Esa es la brecha que Apidog llena: el contrato sobre las solicitudes y respuestas, no el modelo que las produce.
Prueba el contrato, no la redacción
El no determinismo no es un error que puedas eliminar con la configuración. Es una propiedad de ejecutar un modelo de lenguaje, y `temperature=0` no lo desactiva. Los equipos que distribuyen agentes fiables dejaron de luchar contra ello. Prueban las cosas que permanecen constantes: el esquema, la forma, los rangos, los campos obligatorios, y permiten que la redacción cambie. Haz eso y tu suite se calmará de buena manera: se mantendrá en verde mientras el texto varía, y se pondrá en rojo solo cuando algo esté roto.
Elige una aserción inestable en tu suite esta semana y reescríbela como una verificación de esquema y rango. Descarga Apidog para validar las respuestas de tu agente contra un contrato y simular las dependencias que hacen que las pruebas sean repetibles.
