Criterios y graders
Los ocho tipos de criterio en detalle — qué configura cada uno, qué devuelve y cuándo conviene un chequeo determinístico o un juez modelo.
Un criterio (o grader) es una regla que decide si una salida del modelo pasa o no. Un eval puede tener varios; cada uno reporta por separado.
Los tipos disponibles
El selector los ofrece en este orden, deliberado: primero los chequeos determinísticos, al final la evaluación con proveedor.
| Tipo | Nombre en la interfaz | Costo | Qué hace |
|---|---|---|---|
text_check | Evaluar Texto | ⚡ local | Igual, distinto, contiene, regex, conteo de palabras, una sola línea. |
number_check | Evaluar Número | ⚡ local | Compara números como números, con agregaciones y fórmulas. |
json_check | Evaluar JSON | ⚡ local | JSON válido, claves requeridas, longitud de array. |
tool_check | Evaluar Herramientas | ⚡ local | Qué herramienta llamó el modelo y con qué argumentos. |
text_similarity | Evaluar Semántica | ⚡ / 💲 | Parecido con el valor esperado: fuzzy, ROUGE-L o embeddings. |
label_model | Evaluar con Juez (etiqueta) | 💲 proveedor | Un modelo juez clasifica la salida con etiquetas. |
score_model | Evaluar con Juez (puntaje) | 💲 proveedor | Un modelo juez puntúa la salida en un rango. |
span_check | Evaluar Trayectoria | ⚡ local | Sobre el árbol de spans de una traza. Solo en Observabilidad. |
En la mesa de trabajo de un dataset el selector ofrece además Rating & Feedback Manual, que no es un grader: agrega las columnas output_rating (good / bad) y output_feedback para calificar a mano. Solo puede haber uno por dataset.
string_check es heredado. La interfaz ya no lo crea: su reemplazo es text_check, que cubre lo mismo y bastante más. Los criterios string_check que existan siguen calificando y siguen siendo válidos en los snapshots congelados; al abrirlos en el editor se guardan como text_check.Lo que devuelve cualquier criterio
Todos los graders devuelven la misma estructura, con los campos que apliquen:
| Campo | Qué es |
|---|---|
passed | El veredicto. null significa "no se calificó" (hubo un error, o fue N/A). |
score | Solo text_similarity y score_model. |
label | Solo label_model. |
rationale | La explicación en lenguaje llano, en español o inglés según tu idioma. |
error | Un problema de la regla o del proveedor, distinto de "la fila no pasó". |
passed, score y label son campos separados, nunca uno mezclado.
Condición de ejecución
Cualquier criterio puede llevar una condición: "Ejecutar solo si…", con una Variable, una Condición (es igual a, no es igual a, contiene, está vacía, tiene un valor) y un Valor.
Cuando la condición no se cumple, el criterio no se evalúa y no consume tokens — el corto-circuito ocurre antes de cualquier llamada al proveedor. El campo "De lo contrario, marcar como" decide qué queda registrado:
- N/A (por defecto) — la fila no cuenta en el pass rate. Sale del denominador.
- PASS / FAIL — se registra ese veredicto.
Los tipos en detalle
text_check — Evaluar Texto
Reemplaza a string_check. Se configura en tres partes:
- Sobre qué (
Sobre qué): La respuesta completa, Un campo del JSON (con su Campo (path)) o Elementos de un array del JSON. Fuera de la respuesta completa, el campo Se cumple en decide si debe cumplirse en todas, alguna o ninguna. - Qué se valida: una de seis operaciones.
- Los parámetros de esa operación.
| Operación | Parámetros |
|---|---|
| Es igual a | El valor esperado y Distinguir mayúsculas de minúsculas (apagado por defecto). |
| Es distinto de | Lo mismo. |
| Contiene texto | Una lista de Textos a buscar, más Palabra completa y sensibilidad a mayúsculas. |
| Coincide (regex) | Uno o más Patrones, uno por línea, y Flags opcionales. |
| Conteo de palabras | Un Mínimo de palabras, un Máximo, o ambos (hace falta al menos uno). |
| Una sola línea | Sin parámetros: pasa si el texto no tiene saltos de línea. |
Si el ámbito no es la respuesta completa y la salida no es JSON válido, el criterio falla con esa explicación (no es un error de configuración).
number_check — Evaluar Número
Compara números como números, no como texto: "42" cuenta como 42.
- Sobre qué: la respuesta completa, un campo del JSON, los elementos de un array, una agregación de un array (suma, promedio, mínimo, máximo) o una fórmula.
- Comparación:
igual a,distinto de,mayor que,mayor o igual que,menor que,menor o igual que. - Comparar contra: un valor o columna, u otro campo del JSON.
- Tolerancia (±): opcional, y solo aplica a igual/distinto. Sin tolerancia la comparación es exacta, con un epsilon de punto flotante de
1e-9— por eso=0.1 + 0.2es igual a0.3.
El campo del objetivo y el del valor esperado aceptan fórmulas estilo Excel que empiezan con =. La gramática completa, con ejemplos y catálogo de errores, está en Gramática de fórmulas. El editor muestra un Cálculo en vivo contra la salida de muestra mientras escribes.
En una agregación sobre un array vacío, sum y count dan 0; avg, min y max fallan explícitamente.
json_check — Evaluar JSON
Valida la forma de una salida estructurada. Dos validaciones:
- Es JSON válido — opcionalmente con Claves requeridas (
name, age, order.items). Si una ruta atraviesa un array, la clave debe estar en todos los elementos. Requiere el ámbito La respuesta completa. - Longitud de array — Igual a, Mínimo, Máximo y Todos los elementos no vacíos. Requiere apuntar a un campo.
Las validaciones de valor que antes vivían aquí (contiene, regex, comparación numérica, agregaciones) ahora pertenecen a text_check y number_check. Los criterios viejos que las usen siguen calificando igual.
tool_check — Evaluar Herramientas
Verifica la decisión del modelo sobre las herramientas. Nada se ejecuta nunca: las llamadas capturadas son la salida evaluable.
- Qué se espera: Debe llamar una herramienta o No debe llamar ninguna.
- Herramienta esperada — se autocompleta con las herramientas que define el prompt. Es una plantilla, así que puedes poner
{{ herramienta_esperada }}y que cada caso espere la suya. - Chequeos de argumentos — cada uno nombra un Argumento (
order_id,filtro.estado), una comparación (es igual a,es distinto de,contiene) y un Valor esperado, que puede referenciar columnas con{{ }}. Debe cumplir: Todos o Cualquiera.
Si no defines chequeos de argumentos, alcanza con que la herramienta haya sido llamada. Si el modelo la llamó varias veces, basta con que una de las llamadas cumpla.
text_similarity — Evaluar Semántica
Mide qué tan parecida es la salida al valor esperado. Se configura con Texto a evaluar, Valor esperado, una Métrica y un umbral Pasa desde (0–1).
| Métrica | Qué mide | Costo |
|---|---|---|
| parecido literal (fuzzy) | Distancia de edición normalizada, ignorando mayúsculas. | ⚡ gratis |
| solapamiento de frases (ROUGE-L) | F1 sobre la subsecuencia común más larga de palabras. | ⚡ gratis |
| semántica (embeddings de OpenAI) | Similitud coseno entre vectores de embedding. | 💲 consume tokens |
Las tres devuelven un puntaje entre 0 y 1, y passed es simplemente puntaje ≥ umbral.
label_model — Evaluar con Juez (etiqueta)
Un modelo juez clasifica la salida con una de tus etiquetas.
| Campo | Qué es |
|---|---|
| Prompt de Sistema del juez | Opcional. Si lo dejas vacío, no se envía ningún mensaje de sistema. |
| Consigna del juez (mensaje user) | La instrucción. Obligatoria. |
| Etiquetas (separadas por coma) | Al menos dos. Por defecto correcta, incorrecta. |
| Pasan con | El subconjunto de etiquetas que cuenta como aprobado. Por defecto correcta. |
| Modelo juez y Credencial del juez | Ambos obligatorios. |
score_model — Evaluar con Juez (puntaje)
Igual que el anterior, pero el juez devuelve un número. Se configura con Mínimo, Máximo y Pasa desde. El puntaje se recorta al rango y passed es puntaje ≥ umbral.
Es el único tipo que soporta el barrido de umbral de la calibración.
Cómo funcionan los jueces por dentro
La consigna es 100% tuya. Verica no inyecta nada implícitamente — ni la fila, ni la salida del modelo, ni la entrada. Vos referencias lo que necesitas con {{ output.text }}, {{ columna }} o {{ output.json.ruta }}. Lo único que Verica controla es el formato del veredicto, que se fuerza con un JSON schema estricto para que el juez no pueda responder en prosa.
Otros detalles:
- El juez corre con temperatura 0 salvo que configures otra.
- Cada juez debe tener una credencial elegida explícitamente. No hay respaldo silencioso a "la credencial más nueva de ese proveedor" — eso hacía que un juez corriera contra una clave que nadie eligió.
- Antes de lanzar, un juez sobre un endpoint OpenAI-compatible se prueba con una llamada mínima para confirmar que el modelo sabe devolver JSON estricto.
- Si el juez falla, el mensaje lo dice sin rodeos: "El juez no pudo evaluar. Si persiste, puede que el modelo o el endpoint no soporten salida estructurada (JSON) — elige otro modelo o credencial."
span_check — Evaluar Trayectoria
Solo aplica a trazas de producción: comprueba el árbol de spans, no el texto.
Un Patrón de nombre (glob con *, insensible a mayúsculas; vacío = todos los spans) más una de tres comprobaciones:
| Comprobación | Parámetros |
|---|---|
| Cantidad de spans | Mínimo y/o Máximo (hace falta al menos uno). |
| Duración de spans | Duración máxima (ms). Los spans sin duración conocida no cuentan como violación. |
| Spans con error | Errores permitidos (0 por defecto). |
El campo del patrón se autocompleta con los nombres de span que Verica ya vio en tu proyecto. Si la traza no tiene árbol de spans, el criterio devuelve un error explícito — nunca un falso "pasó".
Múltiples jueces
Cada criterio es independiente: su propia columna, su propio veredicto, su propio razonamiento. No hay agregación, consenso ni votación entre jueces. Dos jueces sobre el mismo eval son dos opiniones lado a lado; la reconciliación la haces vos.
Ojo con una consecuencia: el pass rate de la ejecución mezcla todos los criterios en un solo número (aprobados sobre calificados, a través de todos los criterios). El gate por criterio individual todavía no existe; el gate de CI usa el pass rate agregado.
El costo de calificar
Los criterios locales no cuestan nada. Los que llaman al proveedor (los dos jueces, y text_similarity con embeddings) sí, y ese costo se rastrea por separado:
- Los totales de la ejecución muestran
neto {sampling} + jueces {grading}= total. El costo de calificar nunca se esconde dentro del costo de generar. - La cifra grande de la página de resultados es el costo neto por caso — lo que cuesta un caso en producción, donde no hay jueces.
- Un modelo sin precio configurado no rompe nada: su costo simplemente queda fuera del total, y la página lo aclara.
Determinístico o juez: cómo elegir
La regla práctica: usa un juez solo para lo que un juez hace mejor que una regla.
Un juez modelo es la herramienta correcta para criterios semánticos — si la respuesta aborda la pregunta, si el tono es apropiado, si se apoya en el contexto recuperado. Ahí una regla escrita a mano no llega.
Para todo lo demás, un chequeo determinístico gana en tres frentes a la vez:
- Cuesta cero. No consume tokens ni cuenta contra el límite de gradings de tu plan.
- Es auditable. El veredicto sale de una regla escrita, con fecha, que puedes mostrarle a quien pregunte.
- No tiene falsos positivos. Y ese es el punto que más duele en la práctica: un juez que marca la palabra "cubierto" tanto si el bot dijo "estás cubierto" como "no puedo confirmar que estés cubierto" llena la revisión de falsas alarmas. Cuando la mitad de las filas marcadas son ruido, el equipo deja de mirar los flags en cuestión de semanas.
El caso más claro es la aritmética: comparar totales, sumas y conversiones es exactamente donde un LLM es el peor calificador posible. Para eso están number_check y sus fórmulas.
Siguientes pasos
- Gramática de fórmulas — la referencia completa de
number_check. - Calibración — medir qué tan alineado está un juez con tu criterio.
- Ejecuciones y comparación — cómo se leen los veredictos.