Trust, but Trace
EN ES

Metodología de evaluación

Veredictos binarios: cómo mantiene Ragas a raya a los jueces

Ragas descompone los juicios complejos en preguntas atómicas de sí o no. A cambio de menos varianza, pierdes información.

¿Acabas de llegar a la serie? Empieza aquí: qué da por sabido y qué no.

La parte 1 puso nombre a cuatro ejes de varianza del LLM como juez. Lo más sencillo que puede hacer una herramienta para combatirla es restringir lo que el juez puede decir, y en eso consiste la estrategia de restricción del alcance. En esta parte recorro cómo la aplica Ragas en dos de sus métricas.

Estoy construyendo AgentAnvil, un framework de pruebas guiado por contratos para agentes basados en LLM, y leo el código de otros evaluadores para averiguar qué forma deberían tener los contratos de AgentAnvil. El pipeline de fidelidad (faithfulness) de Ragas es de los ejemplos más claros de este patrón que he visto. Un año más tarde, sus autores aplicaron el mismo esquema a los agentes.

La intuición

Con un LLM como juez, la varianza contra la que peleas es mayor en el centro de la escala. Si le pides a un juez una puntuación de 1 a 5, el ruido se concentra en la frontera entre el 3 y el 4. Ahí es donde discrepan dos jueces entre sí y donde un mismo juez se contradice. Los extremos son más fáciles, porque un 1 y un 5 suelen ser casos claramente malos o claramente buenos, que no se deciden a cara o cruz.

Si eliminas el centro, el ruido se queda sin sitio.

La idea es sustituir una rúbrica continua por un veredicto binario, y así «¿Es esta respuesta fiel al contexto?» pasa a ser «¿Está respaldada la afirmación K, sí o no?». El juez ya no recorre una escala y se limita a caer a un lado u otro de una línea. La varianza no desaparece de la frontera, pero ahora esa frontera es una decisión de implicación (entailment) y ha dejado de ser una nota de calidad.

Al agregar los bits vuelves a tener un número de aspecto continuo, la fracción de afirmaciones respaldadas. Sale de átomos binarios, sin ningún juicio continuo de por medio. Cada veredicto que cambia mueve la puntuación 0,1 si hay diez afirmaciones y 0,05 si hay veinte. En la medida en que los errores de los veredictos sean independientes, el ruido del juez se promedia y no se acumula. Ragas juzga todas las afirmaciones juntas en una sola llamada y vuelve a descomponer la respuesta en cada ejecución, así que en la práctica la dispersión se reduce más despacio de lo que muestra la demo de abajo.

Simulación de una misma respuesta que un juez ruidoso puntúa una y otra vez. El histograma muestra dónde cae la puntuación en las distintas ejecuciones y la línea discontinua marca su media. Con más afirmaciones la dispersión se estrecha, suponiendo que cada veredicto se equivoque de forma independiente sobre un conjunto fijo de afirmaciones. La línea continua es el umbral de la puerta: si la llevas dentro de la dispersión, la puerta se vuelve inestable, y si la sacas de ella, se estabiliza.
Dispersión de la puntuación de fidelidad entre ejecucionesHistograma de puntuaciones de fidelidad simuladas en muchas ejecuciones del mismo juez sobre la misma respuesta. Con más afirmaciones, la distribución se estrecha hasta formar un pico. Una línea discontinua marca la media de la puntuación y una línea continua, el umbral de la puerta. Las barras a la izquierda del umbral son ejecuciones que no pasan la puerta, y las de la derecha, ejecuciones que la pasan.umbral00,51puntuación de fidelidad

El pipeline de fidelidad de Ragas gira en torno a esta idea.

La fidelidad en Ragas, paso a paso

En Ragas, la fidelidad se calcula con dos llamadas al LLM y un paso aritmético. La primera llamada descompone, la segunda juzga y la puntuación es una fracción.

Pipeline de fidelidad de RagasUn flujo de datos vertical. Un LLM descompone la respuesta de entrada en afirmaciones atómicas. Después, una segunda llamada al LLM juzga cada afirmación frente al contexto recuperado y la marca como respaldada (1) o no (0). La puntuación es la fracción de veredictos distintos de cero, entre cero y uno, o NaN si no se genera ninguna afirmación.respuestaStatementGeneratorPromptllamada al LLM[s₁, s₂, …, sₙ]NLIStatementPromptllamada al LLMcontextorecuperado[v₁, v₂, …, vₙ]∈ {0, 1}count(vᵢ≠0) / naritméticafidelidad∈ [0, 1] o NaN
Fidelidad en Ragas: descomponer, juzgar, agregar.

Los fragmentos que siguen salen de los módulos originales ragas.metrics._faithfulness y _goal_accuracy. Desde la v0.4.2, Ragas recomienda importar estas métricas desde ragas.metrics.collections, que conserva los mismos prompts (salvo la frase sobre el formato JSON), los tipos de veredicto y el cálculo de la puntuación.

La descomposición está en StatementGeneratorPrompt.

class StatementGeneratorPrompt(
PydanticPrompt[StatementGeneratorInput, StatementGeneratorOutput]
):
instruction = (
"Given a question and an answer, analyze the complexity of each "
"sentence in the answer. Break down each sentence into one or more "
"fully understandable statements. Ensure that no pronouns are used "
"in any statement. Format the outputs in JSON."
)

La instrucción de no usar pronombres es la pieza que hace funcionar el resto del pipeline. Cada afirmación tiene que entenderse por sí sola, porque la siguiente llamada la juzga sin tener delante el resto de la respuesta. El propio prompt de descomposición de Ragas trae un ejemplo few-shot en el que una respuesta de dos frases sobre Einstein se descompone en cuatro afirmaciones independientes que pueden juzgarse por separado. Por los pronombres se cuela la dependencia, y una buena descomposición le cierra el paso.

El veredicto lo emite NLIStatementPrompt.

class NLIStatementPrompt(PydanticPrompt[NLIStatementInput, NLIStatementOutput]):
instruction = (
"Your task is to judge the faithfulness of a series of statements "
"based on a given context. For each statement you must return "
"verdict as 1 if the statement can be directly inferred based on "
"the context or 0 if the statement can not be directly inferred "
"based on the context."
)

Una sola llamada juzga todas las afirmaciones a la vez y devuelve un veredicto por cada una. La instrucción acota explícitamente la salida a 1 o 0, sin término medio.

Después viene la puntuación.

def _compute_score(self, answers: NLIStatementOutput):
# check the verdicts and compute the score
faithful_statements = sum(
1 if answer.verdict else 0 for answer in answers.statements
)
num_statements = len(answers.statements)
if num_statements:
score = faithful_statements / num_statements
else:
logger.warning("No statements were generated from the answer.")
score = np.nan
return score

Es la fracción de afirmaciones respaldadas, una salida de aspecto continuo obtenida al promediar juicios binarios.

Quedan tres detalles de implementación.

En primer lugar, lo que hace en realidad el juez cuando puntúa la «fidelidad» es inferencia en lenguaje natural, una tarea muy estudiada. Ragas reduce a dos las tres etiquetas habituales de esa tarea (implicación, neutral y contradicción) y solo distingue si hay implicación o no la hay. El planteamiento lo toma prestado de una tarea que ya existía.

En segundo lugar, todas las afirmaciones cuentan lo mismo, sin ponderar por importancia, sin penalizar la longitud y sin tener en cuenta la confianza. Esa uniformidad hace que acotar la varianza salga barato, y también que la puntuación se pueda manipular. Basta con rellenar una respuesta con tres afirmaciones triviales que el contexto respalda, colocadas delante de la que de verdad importa, para que la fidelidad suba. La puntuación no sabe en qué átomo está el significado.

Por último, el contrato de tipos es verdict: int (cualquier entero). El prompt es el que acota el valor a 0 o 1, y _compute_score recurre a la semántica truthy. La restricción está, por tanto, en la capa del prompt; la métrica de agentes la endurece en la capa de tipos.

El mismo patrón en AgentGoalAccuracy

Más o menos un año después de su artículo de 2023, Ragas llevó el mismo patrón a los agentes.

AgentGoalAccuracy hace dos llamadas al LLM sobre la traza de una conversación de varios turnos, y el veredicto es directamente la métrica. La primera deduce qué buscaba la ejecución y cómo terminó.

class WorkflowOutput(BaseModel):
user_goal: str = Field(...)
end_state: str = Field(...)

La segunda compara las dos cosas y responde a una pregunta binaria.

class CompareOutcomeOutput(BaseModel):
reason: str = Field(...)
verdict: t.Literal["0", "1"] = Field(...)

Con Literal["0", "1"], el alcance queda fijado en el tipo, además de en el prompt. Pydantic no admite nada que no sea "0" o "1", así que, si un LLM intenta devolver "1.0", "yes" o un objeto JSON, el parser lo rechaza. El paso de reintento de Ragas puede pedirle a un LLM que arregle el formato, pero a la puntuación nunca llega otra cosa que "0" o "1".

Es una vuelta de tuerca respecto a la fidelidad, donde verdict: int acepta cualquier entero. La métrica tiene dos variantes. WithReference compara con un objetivo que se le pasa y WithoutReference, con el que acaba de deducir el propio modelo. El mecanismo (deducir y luego hacer una sola pregunta binaria) es idéntico, y se transfiere porque también se transfiere el juicio de fondo. En la mayoría de los planteamientos razonables, «¿Ha conseguido la ejecución el objetivo del usuario?» se responde con un sí o un no.

Un detalle para quien vaya a meter esto en la CI: la traza nunca llega en bruto al juez. Antes de que la vea el primer prompt, la métrica llama a sample.pretty_repr() para aplanar la conversación de varios turnos en una sola cadena, y el segundo prompt solo ve lo que ha deducido el primero (más la referencia, cuando se pasa). Por eso dos pipelines con formateadores distintos podrían dar veredictos distintos a partir de la misma traza. El formateador forma parte de la métrica, aunque nunca aparezca en su nombre.

Lo que pierdes

Los veredictos binarios no salen gratis.

Un veredicto binario no puede decirte que una respuesta es correcta en parte y otra es excelente, ya que las dos acaban en «respaldada» o «no respaldada». Para una puerta de pasa o no pasa, esa granularidad es la adecuada, pero a la hora de orientar al desarrollador («¿cómo lo mejoro?») los veredictos binarios se quedan cortos. Una puntuación de 0,6 no dice cuáles eran las tres afirmaciones respaldadas de las cinco, ni si las dos sin respaldo eran pequeñas licencias o alucinaciones en toda regla. La forma del fallo se pierde.

Ejemplo construido a mano de una respuesta errónea que se cuela por la puerta. Su única afirmación con contenido (la roja) es inventada y el contexto de abajo no la respalda; todo lo demás es relleno. Sube la puntuación con relleno, eleva después el umbral de la puerta para defenderte y verás lo poco que sirve.
contexto TechCorp publicó su informe financiero del tercer trimestre el 14 de octubre. El informe, de 12 páginas, recoge los ingresos, el margen operativo y la plantilla del trimestre, pero no hace ninguna comparación interanual.
Los ingresos del tercer trimestre crecieron un 30 % interanual. inventada
El informe abarca el tercer trimestre.
TechCorp publicó el informe.
El informe salió el 14 de octubre.
respaldada por el contexto no está en el contexto
umbral 0,80
3 de 4 afirmaciones respaldadas 0,75 puerta · no pasa
relleno mínimo para pasar 4
De momento no pasa, y es lo correcto, porque su única afirmación con contenido es inventada.

Para ser justos con el diseño, que la forma sea binaria no quiere decir que Ragas se olvidara de la granularidad. Sus autores eligieron lo binario porque el caso de uso con el que creció la herramienta, la evaluación de la salida de sistemas RAG, tiene justo esa forma. En RAG, la fidelidad es implicación: o la afirmación está en el contexto recuperado o no está. El cumplimiento del objetivo del agente, la métrica que añadieron más tarde para agentes, también tiene forma de implicación. En los dos casos, la forma de la pregunta encaja con la del veredicto.

«¿Es bueno lo binario?» es la pregunta equivocada. La que hay que hacerse es «¿Tiene el juicio forma binaria?».

Cuándo encaja este enfoque

Los veredictos binarios son el enfoque adecuado cuando se cumplen tres condiciones.

La decisión es pasa o no pasa, sin grados intermedios. En el fondo, una puerta de CI es un pasa o no pasa, aunque la puntuación sea un float de 0 a 1. En cambio, una métrica de cara al usuario que tenga que distinguir entre «bueno», «muy bueno» y «excelente» no lo es.

Los juicios intermedios se descomponen en comprobaciones independientes de sí o no. La fidelidad se presta a ello de forma natural: dado el contexto, cada afirmación es independiente de las demás. Un juicio cuyas partes solo tienen sentido juntas no sobrevivirá al pipeline.

La varianza de la zona media sale más cara que perder información. Una puerta de CI inestable que falla 1 de cada 20 ejecuciones por los vaivenes del juez es peor que una puerta que no da ningún detalle de diagnóstico. De los dos costes, quédate con el que te salga más barato.

En cuanto a los umbrales, elige a la vez el punto de corte y el N habitual. Un umbral de fidelidad de 0,8 con tres afirmaciones equivale a «tres de tres»: basta una afirmación sin respaldo para que la puerta falle, de modo que ya es binaria en la propia métrica. Con veinte, equivale a «dieciséis de veinte», una puerta más cercana a lo continuo. Mientras no decidas cuántos átomos esperas, el umbral es un número sin significado operativo.

Cuando se cumplen las tres condiciones, los veredictos binarios son la herramienta más limpia que tienes.

LLM como juezMetodología de evaluación