Email copiado — support@tuurt.com
Cargando experiencia
ia · 17 de octubre de 2026 · 7 min

Evaluar agentes LLM con casos de prueba reproducibles: por qué un prompt que funciona en demo no implica un agente confiable en producción

Evaluamos agentes LLM a mano hasta que un cambio de tono rompió el orden de las llamadas a herramientas sin que el texto final lo delatara. Así armamos los casos de prueba que lo detectaron.

Por Equipo Tuurt

Evaluar agentes LLM con casos de prueba reproducibles: por qué un prompt que funciona en demo no implica un agente confiable en producción

Durante bastante tiempo evaluamos nuestros agentes LLM de la misma forma en que cualquiera empieza: alguien prueba el agente a mano con dos o tres conversaciones representativas, lee la respuesta final, y si "suena bien" se considera que el cambio de prompt está listo para producción. Esa evaluación manual funciona mientras el agente hace una sola cosa y el prompt cambia poco. Deja de funcionar en el momento en que el agente empieza a decidir qué herramienta llamar, con qué argumentos, y en qué orden, porque ahí el texto final que ve el usuario deja de ser la única superficie que puede romperse.

El problema de evaluar solo el texto final

Un agente que responde correctamente a la pregunta del usuario puede estar llegando a esa respuesta por un camino que no vamos a poder sostener. El caso que más nos costó detectar a mano fue uno donde el agente, ante una consulta de reembolso, respondía con el texto correcto -"tu reembolso fue procesado"- pero en una fracción de las conversaciones había llegado a esa conclusión sin llamar a la herramienta verificar_estado_reembolso, infiriendo el estado a partir del contexto de la conversación en lugar de consultarlo. El texto final era indistinguible entre el camino correcto y el camino inventado. Si el criterio de evaluación es "¿la respuesta final es razonable?", ese tipo de falla es invisible por diseño: la respuesta es razonable las dos veces.

Esto nos obligó a separar dos preguntas que antes tratábamos como una sola: si el agente dijo algo razonable, y si el agente hizo lo que tenía que hacer para poder decirlo con fundamento. La segunda pregunta solo se puede responder mirando la traza de llamadas a herramientas, no el mensaje final.

Qué forma toma un caso de prueba reproducible

Un caso de prueba para un agente necesita, como mínimo, tres partes: una entrada fija (el mensaje o la secuencia de mensajes que recibe el agente), un estado inicial fijo para cualquier sistema externo que el agente pueda consultar (en lugar de llamar a la API real de reembolsos, un doble de prueba con datos conocidos), y un conjunto de aserciones que no se limitan al texto de salida.

def test_reembolso_ya_procesado():
    entrada = [
        {"role": "user", "content": "¿Qué pasó con mi reembolso del pedido 4821?"}
    ]
    estado_inicial = {
        "pedido_4821": {"estado_reembolso": "procesado", "monto": 45.00}
    }

    resultado = ejecutar_agente(entrada, mock_backend(estado_inicial))

    llamadas = resultado.tool_calls
    assert any(
        c.name == "verificar_estado_reembolso" and c.args["pedido_id"] == "4821"
        for c in llamadas
    ), "el agente respondió sin consultar el estado real del reembolso"

    assert resultado.texto_final is not None

La aserción sobre tool_calls es la parte que el criterio manual nunca iba a capturar, porque evaluar a mano significa leer el mensaje final, no inspeccionar la lista de llamadas que el agente hizo para llegar ahí. Agregamos una aserción explícita, deliberadamente más estricta que "la respuesta es correcta": si el agente no llamó a la herramienta de verificación, el caso falla aunque el texto final sea el correcto, porque lo que estamos probando no es si esta vez adivinó bien, es si el camino que siguió es el que vamos a poder confiar la próxima vez con datos distintos.

Esto nos lleva a un segundo componente necesario: el backend simulado (mock_backend) tiene que devolver exactamente los datos que el caso de prueba define, no una aproximación. Si el doble de prueba devuelve datos reales de un entorno de staging que cambian entre corridas, el caso deja de ser reproducible: una corrida puede fallar simplemente porque el dato de fondo cambió, no porque el agente se comportó distinto. La reproducibilidad del caso depende tanto de la entrada como del estado del mundo que el agente puede consultar, y ambos tienen que quedar fijos en el código del test, versionados junto con el prompt que están probando.

Por qué la evaluación manual ad hoc no escala

El problema de fondo con la evaluación manual no es que sea lenta -aunque lo es-, es que no es acumulativa. Cuando alguien prueba un cambio de prompt a mano con tres conversaciones, esas tres conversaciones no quedan documentadas en ningún lado reproducible: la próxima persona que toque el prompt no sabe qué casos ya se habían probado, así que vuelve a probar casos parecidos, y los casos raros -el usuario que pregunta por un pedido que no existe, el que pide el reembolso de otra persona, el que manda dos preguntas en el mismo mensaje- dependen de que a alguien se le ocurra probarlos de nuevo cada vez.

Con casos de prueba versionados en el repositorio, cada caso que alguna vez encontramos roto se queda ahí como regresión permanente. La regla que nos funcionó fue simple: todo bug de agente que llegó a producción se convierte, antes de cerrarse, en un caso de prueba que reproduce exactamente esa falla con una entrada fija. Esto no evita que aparezcan bugs nuevos, pero evita que el mismo bug vuelva a colarse dos versiones de prompt después, que es el patrón que más veces nos pasó antes de automatizar esto: arreglábamos un caso, cambiábamos el prompt por otra razón un mes después, y el caso original volvía a fallar sin que nadie lo notara hasta que un usuario se quejó otra vez.

La regresión que nos pasó inadvertida hasta que automatizamos esto

El caso concreto que terminó de convencernos de invertir en este set de pruebas fue un cambio de prompt pensado para mejorar el tono de las respuestas -hacerlas más breves, menos genéricas- que, como efecto secundario no buscado, modificó el orden en que el agente decidía llamar a las herramientas disponibles. Antes del cambio, el agente siempre llamaba a verificar_estado_reembolso antes de verificar_politica_devolucion cuando ambas aplicaban. Después del cambio, el modelo empezó a invertir ese orden en una parte de los casos, lo cual en sí mismo no rompía nada funcionalmente -ambas herramientas son independientes entre sí-, pero sí rompía una aserción de nuestro set de pruebas que no sabíamos que dependía implícitamente del orden, porque un test posterior asumía que el resultado de la primera llamada ya estaba disponible en el contexto cuando se evaluaba la segunda.

Leyendo solo las respuestas finales de esas conversaciones, el cambio de prompt se veía como una mejora clara: los mensajes eran efectivamente más cortos y menos genéricos. La regresión solo se hizo visible cuando la suite de pruebas automatizadas, corriendo las mismas entradas fijas de siempre, marcó en rojo un caso que llevaba tiempo en verde. Sin esa suite, ese cambio de orden hubiera llegado a producción invisible durante la revisión, y probablemente se hubiera descubierto más adelante, con una traza de producción mucho más difícil de reconstruir que un test que falla en el momento exacto del cambio que lo rompió.

Qué revisamos antes de dar por buena una nueva versión de un agente

Antes de promover un cambio de prompt o de lógica de un agente a producción, confirmamos que el set de casos de prueba cubra al menos los flujos felices principales, los casos límite que ya rompimos antes en producción, y los casos donde el agente tiene que decidir no llamar a ninguna herramienta. Revisamos que cada caso tenga aserciones sobre la traza de llamadas a herramientas, no solo sobre el texto final, porque esa es la parte que la revisión manual sistemáticamente deja pasar. Verificamos que el estado inicial de cada caso esté fijo en el código del test y no dependa de un entorno externo que pueda cambiar entre corridas. Y cuando encontramos un bug nuevo, no lo cerramos hasta que exista un caso de prueba que lo reproduzca, porque esa es la única garantía real de que no va a volver a aparecer sin que nadie lo note.

llm agentes testing ia
← Volver al blog