METHODOLOGY · 3 de julio de 2026
No puedes hacer un test unitario a una tirada de dados
Los desarrolladores acoplan un LLM a un sistema, escriben un test normal de pasa/falla a su alrededor, lo ven fallar de forma intermitente, y entonces o borran el test o mockean el modelo hasta dejarlo sin sentido. Ambas cosas están mal. Un componente probabilístico no está roto cuando varía — pero 'varía' no es permiso para dejar de probarlo. Simplemente tienes que probar la distribución en lugar de la muestra: puntúa un conjunto dorado con tolerancia, condiciona el paso a una tasa de aciertos, afirma las invariantes que deben cumplirse siempre, y mantén una línea dura entre el núcleo estocástico y la cáscara determinista que lo rodea.
Aquí hay un error que he visto lanzar a ingenieros inteligentes una y otra vez. Conectan un LLM a una funcionalidad y luego hacen lo responsable y escriben un test: entra la entrada, afirma que sale exactamente la cadena esperada. Pasa en su máquina. Falla en CI. Vuelve a pasar en un reintento. Así que hacen una de dos cosas — borrar el test, o mockear el modelo para que devuelva una respuesta enlatada — y ahora la parte del sistema con más probabilidades de portarse mal es la única parte sin ningún test.
El error no es el test inestable. Es el marco. Estás intentando hacer un test unitario a una tirada de dados.
Afirmar sobre una sola ejecución es la herramienta equivocada
Un test unitario hace una pregunta de sí/no sobre una función determinista: dado x, ¿obtengo exactamente
y? Esa es la pregunta correcta para un parser y una pregunta sin sentido para un modelo, al que se le permite
— por diseño — decir lo mismo cierto de cinco maneras distintas. Ejecútalo suficientes veces y el mismo prompt
te da una distribución, no un valor. Afirmar sobre una sola extracción de esa distribución no te dice casi
nada; solo mueve la moneda al aire a tu pipeline de CI.
Por esto los números de productividad en programación con IA son tan turbios. Los individuos se sienten rápidos, pero se midió a desarrolladores experimentados más lentos en tareas reales, y los equipos ven más pull requests pero revisiones más largas y una rotación creciente. Buena parte de eso es gente intentando validar salidas no deterministas con hábitos deterministas, una afirmación frágil a la vez, y ahogándose.
"No es determinista" es una afirmación cierta sobre el modelo y una excusa perezosa sobre el sistema. No puedes fijar el dado. Sí puedes acotar por completo cómo se le permite caer.
Prueba la distribución, no la muestra
La jugada es dejar de probar una única respuesta correcta y empezar a probar la forma del comportamiento:
- Puntúa un conjunto dorado, no compares una cadena. Guarda 30–100 pares reales de entrada/salida y califica las nuevas ejecuciones por similitud, una rúbrica o un modelo-como-juez — no por igualdad exacta. Estás midiendo calidad, que tiene un rango, no identidad, que no lo tiene.
- Condiciona el paso a una tasa de aciertos, no a un solo verde. Ejecuta el caso N veces y exige, por ejemplo, un 95% de aciertos. Un fallo de cada veinte no es un build roto — es el dado comportándose como un dado. Una tasa de aciertos que cruza una línea sí es una regresión que puedes detectar.
- Afirma las invariantes que deben cumplirse absolutamente siempre. El contenido varía; el contrato no debe. Siempre JSON válido. Nunca filtra los datos de otro usuario. Siempre dentro del presupuesto de tokens. Rechaza los tres prompts que debe rechazar. Esos sí son deterministas, y los pruebas como cualquier otra cosa.
- Separa el núcleo estocástico de la cáscara determinista. El enrutamiento, el parsing, la validación, los reintentos y los fallbacks alrededor del modelo son código ordinario — hazles tests unitarios a fondo, con el modelo mockeado. Reserva las pruebas probabilísticas para la única frontera que de verdad es probabilística.
En resumen
El no-determinismo no es una razón para saltarse las pruebas — es una razón para probar de otra manera. Un modelo que no puedes fijar es exactamente la parte de tu sistema que más necesita una correa medida, porque "normalmente funciona" es cómo se siente el software poco fiable desde dentro justo hasta que deja de hacerlo.
Deja de afirmar sobre una tirada afortunada. Califica un conjunto dorado con tolerancia, condiciona el paso a una tasa de aciertos, blinda las invariantes y hazle tests unitarios a la cáscara determinista como si tu vida dependiera de ello — porque en producción, esa cáscara es lo que sostiene los dados.
Comentarios
Aún no hay comentarios
Inicia sesión para unirte a la conversación.
Sé el primero en compartir una idea.