10 min de lectura

Emilio Carrión

Tu LLM aprueba el benchmark y suspende en producción

Las métricas genéricas te dicen si tu LLM se equivoca, no si se equivoca para tu negocio. Por qué evaluar LLMs es un problema de dominio y cómo abordarlo con LLM-as-a-Judge.

iaingenieríaverificaciónllmevaluación

Esta semana habrás visto el chatbot de soporte de McDonald's escribiendo código Python para invertir una linked list. El usuario le pide ayuda con un script, el bot se lo resuelve con complejidad O(n), y luego le pregunta si quiere unos McNuggets. La broma se ha hecho viral: "deja de pagar por Claude Code, el soporte de McDonald's es gratis".

Es fácil reírse. Un LLM de soporte al cliente que responde preguntas de programación es un fallo obvio que cualquiera detecta. Pero el caso que a mí me da más que pensar es otro: cuando el LLM se queda dentro de tu dominio, responde exactamente lo que le has pedido, y aun así se equivoca de una forma que solo alguien que conoce tu negocio puede detectar.

Un equipo al que apoyo opera algo así. Un sistema de IA interno que genera informes operativos para centenares de personas dentro de la organización, no un chatbot de cara al cliente. No puedo contar los detalles, pero los patrones que voy a explicar son transferibles. Voy a usar un chatbot de customer service como hilo conductor, porque el mecanismo es idéntico y es el caso que todo el mundo tiene en la cabeza después de lo de McDonald's.

Llevo meses escribiendo sobre verificación como disciplina de ingeniería. La tesis es que en sistemas complejos, la capacidad de verificar que lo que produces es correcto importa tanto como producirlo. Con LLMs en producción esa tesis se vuelve todavía más urgente. Porque las métricas genéricas de evaluación (BLEU, ROUGE, detectores de alucinación) te dicen si la salida es incorrecta, pero no si es incorrecta para tu negocio.

El problema con un ejemplo

Voy a montar el caso con un chatbot de soporte para un e-commerce. El cliente pregunta por un retraso en su pedido. El bot responde: "Tu pedido lleva 5 días de retraso. Esto es un problema grave. Te recomendamos que contactes con nuestro equipo de escalado urgente."

Datos correctos. Respuesta relevante. Cero alucinaciones factuales. Y sin embargo, el tono es un desastre. "Problema grave" genera ansiedad innecesaria. "Escalado urgente" no es el nombre del equipo, es jerga interna que se ha filtrado. Un detector de alucinaciones no ve nada malo. ROUGE te dice que la respuesta es parecida a las buenas. Pero el responsable de experiencia de cliente lo lee y dice: esto no puede salir.

Y ahí es donde las métricas genéricas te dejan solo.

Newsletter Semanal

¿Te gusta lo que lees?

Unete a otros ingenieros que reciben reflexiones sobre carrera, liderazgo y tecnologia cada semana.

Dos niveles de exigencia

Usamos GEval de DeepEval. Cada métrica es un string de criterio en lenguaje natural que un LLM juez (Claude Sonnet) evalúa puntuando de 0 a 1. Pero no todas tienen el mismo umbral, y esa es la primera decisión de diseño que quiero compartir.

Hay criterios de compliance con umbral alto (0.9). Son casi binarios: "la respuesta no revela que es generada por IA", "la respuesta no usa lenguaje alarmista con el cliente". O lo cumple, o no. Podrías pensar que una regex lo resuelve. Enseguida te explico por qué no.

Y hay criterios de calidad con umbral más bajo (0.7): "la respuesta es empática y práctica", "no promete lo que no puede cumplir", "las sugerencias son acotadas y accionables". Estos son inherentemente subjetivos. Dos personas razonables discrepan sobre si un tono es "suficientemente empático". El umbral más bajo permite varianza estilística sin dejar pasar fallos claros.

Los umbrales exactos los calibramos empíricamente: revisamos un lote de respuestas a mano y ajustamos. Pero la decisión que sí es transferible es esta: no pongas todos los criterios al mismo umbral. Si lo haces, o dejas pasar violaciones de compliance o generas falsos positivos en calidad. Dos niveles separan lo binario de lo subjetivo.

Las excepciones de dominio

Hasta aquí, nada que no puedas montar en una tarde. La parte donde de verdad invertimos tiempo fue en las excepciones. Y creo que es la parte que más equipos subestiman. Nosotros desde luego la subestimamos. Pensábamos que definir los criterios sería un par de tardes. Nos llevó bastante más de lo que esperábamos.

Semántica invertida: cuando "subir" es malo

Volvamos al chatbot de soporte. El bot analiza métricas y dice al responsable de turno: "el tiempo medio de resolución se acerca al objetivo". Suena positivo, ¿no? Pero si el objetivo es un máximo (resolver en menos de 24 horas), acercarse al objetivo significa que estás tardando más. Estás empeorando.

Sin esta aclaración en el criterio de evaluación, el juez LLM interpreta "acercarse al objetivo" como positivo, porque esa es la semántica por defecto. Tuvimos que ser explícitos:

text
"Todos los KPIs de soporte son métricas a minimizar (tiempo de
resolución, tasa de reapertura, tiempo de primera respuesta).
Un valor más alto siempre es peor. 'Subir' siempre significa
empeorar. 'Acercarse al objetivo' significa acercarse al límite
máximo, lo cual es NEGATIVO."

Este tipo de excepción es el más peligroso porque no es una palabra que puedas buscar. Es una inversión semántica que solo existe en tu dominio. A nosotros nos pasó con métricas diferentes, pero el mecanismo fue idéntico. Y te digo la verdad: tardamos en darnos cuenta. Las primeras semanas los scores de coherencia salían bien y no entendíamos por qué los resúmenes sonaban "raro" al leerlos. Hasta que alguien del equipo de operaciones señaló que el modelo estaba celebrando cosas que eran malas noticias.

Jerga interna que parece una violación

Pero no solo pasa con la semántica. Un criterio típico en customer service sería "la respuesta no debe exponer procesos internos al cliente". Regla clara. Pero en muchos equipos de soporte, "escalar" es una acción estándar que el cliente conoce y espera ("voy a escalar tu caso al equipo especializado"). El juez penaliza "escalar" porque suena a proceso interno. O piensa en un estado de ticket que se llama "bloqueado" y que el bot menciona al cliente. Internamente es un estado operativo normal. Para el cliente suena a que nadie va a mirar su caso.

Una regex que filtre estas palabras las penalizaría siempre. Un LLM juez sin contexto, también. La solución es codificar la excepción directamente en el string de criterio: "'Escalar' es terminología aceptable para el cliente en este contexto y no debe penalizarse. 'Bloqueado' SÍ es terminología interna y no debe exponerse."

Terminología que suena alarmista fuera de contexto

Y luego está el caso inverso. El criterio prohíbe lenguaje alarmista: nada de "grave", "crítico", "urgente". Tiene sentido, no quieres que el bot genere ansiedad. Pero "ticket crítico" es una categoría de prioridad estándar en cualquier sistema de soporte. Cuando el bot dice "he clasificado tu caso como crítico", no está siendo alarmista. Está informando de la prioridad.

Mismo mecanismo, misma solución: carve-out en el criterio. "'Crítico' referido a la prioridad del ticket NO es lenguaje alarmista y no debe penalizarse. 'Crítico' como adjetivo general ('la situación es crítica') SÍ es lenguaje alarmista."

El patrón común

En los tres casos, la solución fue la misma: codificar la excepción como carve-out dentro del string de criterio, no en código de post-procesado. El juez LLM necesita ver la excepción en el mismo prompt donde ve la regla. Si la mueves a lógica Python, el juez penaliza correctamente según su criterio, y tú descartas su juicio después. Eso no escala.

El 80% del tiempo de desarrollo de nuestro sistema de evaluación fue iterar los strings de criterio. No la infraestructura, no el pipeline, no la integración. Los strings. El conocimiento de dominio que tu equipo tiene en la cabeza pero que nunca ha escrito en ningún sitio. Convertir eso en criterios evaluables fue el trabajo real. No el código.

Escenarios como tests de regresión

Tenemos escenarios predefinidos con datos mockeados que cubren los casos extremos. Lo interesante no es que existan (cualquier equipo debería tener tests de evaluación), sino que los criterios de los tests son más específicos que los de producción.

En producción preguntas cosas generales: "¿la respuesta expone procesos internos?". En un test de escenario preguntas: "ante un cliente con un pedido retrasado 5 días, ¿menciona el plazo estimado de resolución? ¿No promete una fecha concreta? ¿Ofrece alternativas accionables?".

Esta granularidad extra atrapa regresiones de prompt que las métricas generales no ven. Nos pasó: cambiamos el system prompt y las métricas de producción seguían pasando. Pero un test de escenario detectó que el modelo había dejado de conectar causalmente dos métricas relacionadas (un problema de razonamiento, no de formato). Las métricas generales eran ciegas a eso.

La verificación no es un paso final, es una disciplina continua. Cuando cambias un prompt, necesitas saber qué has roto. Y las métricas genéricas no te lo dicen. Los escenarios de dominio, sí.

Lo que todavía no hemos resuelto

No quiero hacer cherry-picking con lo que funciona. Hay cosas que no tenemos bien resueltas.

El juez tiene varianza. Ejecutas la misma evaluación dos veces y el score puede variar un 5-10%. Mitigamos mirando tendencias en vez de valores absolutos, pero no es ideal.

No tenemos ground truth humano sistemático. Calibramos los umbrales con revisión manual de un lote, pero no tenemos correlación juez-humano continua. Sabemos que coincide "en general" con nuestro criterio, pero no podemos darte un número.

El coste es aceptable para evaluación asíncrona (una llamada al juez por criterio), pero no escalaría a tiempo real.

Y los propios criterios necesitan versionado e iteración, como cualquier otro prompt. Un criterio vago produce scores ruidosos. Uno demasiado específico produce falsos negativos. Encontrar el punto medio es trabajo continuo.

Verificar LLMs es un problema de dominio, no de IA

El chatbot de McDonald's escribiendo Python es gracioso, pero no es el problema real. El problema real es cuando tu LLM se queda dentro de su dominio y aun así rompe reglas que solo tu equipo conoce. Reglas que nunca han sido escritas, que viven en la cabeza de la gente que lleva años operando el negocio, y que ningún benchmark genérico va a evaluar por ti.

Montar un sistema de evaluación con LLM-as-a-Judge no requiere tecnología sofisticada. DeepEval, un modelo juez, un pipeline asíncrono. Lo que requiere es sentarse a articular qué significa "bueno" en tu contexto como lenguaje natural. Y eso no es un problema de IA. Es un problema de ingeniería de dominio. El mismo problema que llevas años resolviendo con tests, con contratos, con métricas de negocio. La diferencia es que ahora el sistema que produce la salida es no determinista, así que tus verificaciones también tienen que serlo. Pero la disciplina es la misma.

Lo que sí tengo claro es que las métricas genéricas no son suficientes. Lo que no tengo tan claro es si el enfoque de LLM-as-a-Judge con criterios de dominio es la solución definitiva o una solución intermedia que funciona hoy. La varianza del juez, la falta de ground truth, la fragilidad de los criterios ante cambios de modelo... son problemas abiertos. Pero de momento es lo mejor que hemos encontrado, y funciona bastante mejor que no evaluar nada.

¿Cómo verificáis vosotros la salida de vuestros LLMs en producción? Me encantaría saber si habéis llegado a patrones similares o a soluciones diferentes.

Contenido de Newsletter

Este contenido fue enviado primero a mi newsletter

Cada semana envío reflexiones exclusivas, recursos y análisis profundos sobre ingeniería de software, liderazgo técnico y desarrollo de carrera. No te pierdas el próximo.

Únete a más de 5,000 ingenieros que ya reciben contenido exclusivo cada semana

Compartir:
Emilio Carrión
Sobre el autor

Emilio Carrión

Staff Engineer en Mercadona Tech. Ayudo a ingenieros a pensar en producto y a construir sistemas que escalan. Obsesionado con la arquitectura evolutiva y los equipos de alto rendimiento.