Modelo como verificador: el nuevo eje de escalado de los LLM
Qué es LLM-as-a-Verifier, en qué se diferencia del modelo como juez y qué cuesta de verdad el best-of-N que llevó a DeepSeek V4 Flash de 79% a 88%.
Hace unas semanas circuló por X un resultado que parece un error de medición: DeepSeek V4 Flash, un modelo abierto y barato, pasando de 79% a 88% en Terminal-Bench sin reentrenar nada. Solo generando cinco soluciones y verificándose a sí mismo. Lo publicó Jacky Kwok[4], primer autor del paper que hay debajo de la técnica[1], y lo interesante para nosotros es que la técnica se monta encima del modelo como juez que muchos ya tenemos en producción, cambiando solo cómo se lee su respuesta.
La idea cabe en una frase. Deja de pedirle al juez un número y quédate con la distribución entera.
El empate: por qué el juez de 1 a 5 se queda corto
Un juez que puntúa de 1 a 5 empata casi siempre que los candidatos son razonables. Si ya usas el patrón de modelo como juez sabes de qué hablo: le pasas dos soluciones largas, las dos compilan, las dos hacen lo que pide el enunciado, y el juez contesta “4” a las dos. Con eso no puedes elegir.
Los autores lo midieron. Sobre una misma tarea, un juez con escala de 1 a 5 devolvió empate en 88 de cada 100 evaluaciones; con puntuación continua y granularidad de 20 niveles, el ranking fue correcto en 77 de cada 100[1]. El modelo sí distinguía; lo que fallaba era pedirle que metiera esa distinción en un solo token.
Porque el modelo sí sabe algo más de lo que escribe.
¿Cómo se saca una puntuación continua de los logprobs?
Cuando un modelo genera un token no elige una palabra: calcula una probabilidad para cada token posible del vocabulario y luego muestrea uno. Si le pides que puntúe del 1 al 20, internamente reparte probabilidad entre “13”, “14”, “15” y el resto, y después te escribe uno. Los logprobs son ese reparto, en escala logarítmica, y varias APIs te lo devuelven si lo pides.
En vez de leer el token que salió, lees toda la distribución sobre los tokens de puntuación y calculas su valor esperado: R = Σ p(v_g) · φ(v_g), donde φ normaliza cada nivel al intervalo [0, 1]. Un juez que duda entre 13 y 14 ya no te da un 13 seco, te da un 0,672.
# De la distribución de tokens de puntuación a un número continuo entre 0 y 1
import math
def puntuacion_continua(top_logprobs, granularidad=20):
# top_logprobs: [{"token": "13", "logprob": -0.21}, ...] en la posición de la nota
esperanza, masa = 0.0, 0.0
for cand in top_logprobs:
token = cand["token"].strip()
if not token.isdigit():
continue # descartamos lo que no es una nota
p = math.exp(cand["logprob"]) # logprob -> probabilidad
esperanza += p * (int(token) / granularidad) # phi(): normaliza a [0, 1]
masa += p
if masa == 0:
return None # ninguna nota entre los candidatos: pasa con tokenizadores que parten los números
return esperanza / masa # renormalizamos sobre los tokens válidos
La fórmula completa del paper es esta misma suma anidada tres veces: R(x, τ) = (1/CK) Σ_c Σ_k Σ_g p·φ. La suma interna recorre los G niveles de la escala, la de en medio las K repeticiones de la evaluación, y la externa los C criterios que has definido. Cada una de esas tres sumas es una palanca que puedes subir o bajar, y ahí está la parte del paper que de verdad cambia cómo montas un evaluador.
Para comparaciones por pares el framework hace lo mismo con Bradley-Terry: la probabilidad de que A gane a B es la sigmoide de la diferencia de sus puntuaciones continuas[1].
Los tres ejes por los que escala la verificación
Cada suma de la fórmula es un eje de escalado independiente, y el paper mide cuánto rinde cada uno en Terminal-Bench 2.0[1].
Granularidad. Ampliar la escala de 1 a 20 niveles sube el resultado de 73,1% a 77,5%, y el punto de partida de esa ablación es G=1, no el juez de 1 a 5 del caso de arriba. Es el cambio más barato de todos: no añade ni una llamada, solo cambias el enunciado del criterio y el rango que esperas.
Repetición. Evaluar K veces y promediar es Monte Carlo puro sobre la puntuación: la varianza cae como O(1/K). De K=1 a K=16 el resultado pasa de 74,7% a 77,4%, y ahí se aplana. No se aplana por casualidad. Los errores del juez son sesgo, no ruido independiente, y un sesgo repetido dieciséis veces sigue siendo el mismo sesgo.
Criterios descompuestos. En código, en vez de preguntar “¿está bien esto?”, el paper separa la evaluación en Specification, Output y Errors. Cada criterio por su cuenta se mueve entre 75,2% y 76,4%, pero promediando los tres se llega a 78,3%. Es la única de las tres palancas que ataca el sesgo en lugar de promediarlo, porque cada criterio mira una parte distinta de la solución.
| Juez discreto (1-5) | Verificador continuo | |
|---|---|---|
| Salida | el token de nota que el modelo escribió | la esperanza sobre la distribución completa de tokens de nota |
| Empates | constantes en cuanto los candidatos son razonables | raros: la diferencia aparece en el tercer decimal |
| Escalado | subir la escala por sí sola no arregla el empate | granularidad, repeticiones y criterios, cada uno con su curva medida |
| Rankear N candidatos | O(N²) comparaciones por pares | O(Nk) con torneo probabilístico de pivotes |
| Requisito de API | ninguno | logprobs expuestos por el proveedor |
Un verificador que ordena bien candidatos parecidos sirve para algo más que evaluar: sirve para elegir.
Best-of-N: generar barato y elegir bien
Best-of-N consiste en generar N soluciones al mismo problema, puntuarlas con el verificador y quedarte con la mejor. El paper trabaja con N entre 3 y 5, y para no comparar todos contra todos usa un torneo probabilístico de pivotes que baja el coste de O(N²) a O(Nk)[1].
Los números del paper, en las cuatro suites que reporta[1][2]: Terminal-Bench V2 86,5%, SWE-Bench Verified 78,2%, MedAgentBench 73,3% y RoboRewardBench 87,4%. En Terminal-Bench V2 el contexto es lo que da la medida: el mismo generador sin verificación se queda en 83,1% de pass@1, GPT-5.5 llega a 84,7%, y un oráculo que siempre eligiera el mejor de los candidatos daría 92,1%.
Ese hueco entre 86,5% y 92,1% es la parte honesta del resultado. Los candidatos buenos ya estaban ahí; el verificador recupera una porción, no todo. Cuando falla, falla eligiendo una solución plausible y equivocada, que es exactamente el fallo que un juez tiene.
El 79% a 88% de DeepSeek V4 Flash con cinco muestras no está en el paper[4]. Es un experimento posterior que Kwok publicó en X, sobre Terminal-Bench 2.1, sin revisión ni tabla de ablaciones. Que venga del primer autor lo hace creíble, pero no lo convierte en un resultado revisable. Yo lo trataría como una señal fuerte de que la técnica generaliza a modelos pequeños, y nada más.
La letra pequeña del “11x más barato”
El 11x del hilo es precio por token, no coste por tarea resuelta. DeepSeek lista V4 Flash a 0,14 $ por millón de tokens de entrada y 0,28 $ de salida[5], y comparado con el precio de un modelo frontier la ratio sale. El problema es que la unidad no es la misma.
Haz la cuenta con lo que consume el patrón. Generas N candidatos, así que multiplicas por N la generación completa. Después verificas cada candidato con K repeticiones y C criterios, y cada una de esas llamadas se come la trayectoria entera del agente como entrada, que en Terminal-Bench son trayectorias largas. Con N=5, K=4 y tres criterios, el número de llamadas por tarea no se parece nada al de una ejecución directa.
El framework mitiga por los dos lados: el torneo de pivotes recorta las comparaciones, y la versión 0.2.0 añade caché de prefijos, que según su changelog reduce unas 3,4 veces los tokens de entrada no cacheados en benchmarks con trayectorias largas, además de un token_usage() para que lo midas tú mismo[3]. Aun así el multiplicador sigue siendo grande, y el precio por token es un número que se mueve: DeepSeek tiene anunciada una estructura de recargo por horas punta que cambiaría la aritmética entera[5].
Nada de esto lo vuelve caro en términos absolutos. Sale barato comparado con usar un modelo frontier para la misma tarea, y compensa siempre que acertar valga más que los tokens: parches que van a producción, migraciones, cualquier cosa donde un humano tenga que revisar el fallo si sale mal. Para un endpoint de alto volumen que responde en línea, no compensa.
Cómo probarlo mañana
El framework está publicado con licencia MIT y se instala con pip install llm-verifier[3]. La función de selección recibe el problema, los candidatos y el diccionario de criterios, y devuelve el índice ganador junto con la puntuación continua de cada candidato.
# Best-of-N con el framework del paper: pip install llm-verifier
import llm_verifier
problem = "Escribe una función que invierta una cadena."
candidates = [
"def rev(s): return s[::-1]",
"def rev(s): return s",
"def rev(s): return ''.join(reversed(s))",
]
result = llm_verifier.select(
problem=problem,
candidates=candidates,
criteria={"Correctness": "¿La función invierte realmente la cadena?"},
)
print(result.index) # índice del candidato ganador
print(result.scores) # una puntuación continua por candidato
Hay dos aplicaciones más en el repositorio que se salen del best-of-N. Con track() y ProgressTracker puntúas la trayectoria de un agente paso a paso mientras corre, y como en las trayectorias que acaban bien la puntuación sube con el paso, puedes abortar las que se están yendo por el desagüe antes de pagar el resto. Si ya tienes montada la parte de cómo evaluar agentes en producción, esto encaja como la señal en vivo que le falta a un eval offline. La otra aplicación es entrenamiento por refuerzo: la puntuación continua sirve de recompensa densa sin entrenar un reward model aparte, con una eficiencia de muestras alrededor de 1,8 veces mejor en LIBERO[1].
Y el requisito que decide si puedes o no: el proveedor tiene que devolverte logprobs. DeepSeek los expone con logprobs y top_logprobs hasta 20 candidatos por posición, aunque su modo de razonamiento los rechaza con un error, así que el verificador va contra el modo normal[6]. Gemini y Vertex los dan con response_logprobs, y cualquier servidor compatible con OpenAI, vLLM incluido, también. La API de Anthropic no expone logprobs, así que Claude no puede ser el verificador tal cual; el apéndice B.6 del paper describe un rodeo en dos etapas para ese caso[1].
Errores comunes
Citar el 88% como si fuera del paper
Es el error más fácil de cometer y el más caro de defender delante de tu equipo. El paper reporta 86,5% en Terminal-Bench V2 con Gemini 2.5 Flash de verificador; el 79% a 88% de DeepSeek V4 Flash es un hilo de X posterior, en otra versión del benchmark. Son números distintos y con distinta solidez.
Presupuestar con el precio por token
Si llevas el 11x a una hoja de cálculo sin multiplicar por N candidatos y por K×C verificaciones, la estimación se te va a quedar corta por un factor grande. Mide sobre una muestra real de tus tareas antes de prometer un ahorro:
# problem y candidates: los mismos del ejemplo de select() de más arriba
llm_verifier.USAGE.reset()
llm_verifier.select(problem=problem, candidates=candidates, criteria={"Correctness": "..."})
print(llm_verifier.token_usage()) # llamadas, tokens de entrada cacheados y sin cachear, tokens de salida
Verificarse a uno mismo sin contar el sesgo de autopreferencia
Que el generador y el verificador sean el mismo modelo es justo lo que hace atractivo el resultado viral, y también lo que introduce el sesgo: un modelo puntúa mejor su propio estilo de solución. Descomponer criterios lo atenúa, porque preguntar “¿cumple la especificación?” deja menos margen a la preferencia estética que preguntar “¿es buena?”. Atenuar no es eliminar. Si vas a usar el mismo modelo en los dos lados, mide una vez contra un verificador distinto y quédate con la diferencia como tu margen de error.
Subir K esperando una mejora proporcional
De K=1 a K=16 ganas 2,7 puntos, y más de la mitad los tienes ya en K=4: 74,7% con una evaluación, 76,1% con cuatro, 77,4% con dieciséis. Promediar reduce el ruido, no el sesgo, y los errores de un juez son sobre todo sesgo.
Elegir el proveedor antes de comprobar los logprobs
Descubrir que tu API no devuelve la distribución cuando ya tienes el pipeline montado duele. Antes de nada, haz una llamada suelta pidiendo logprobs y mira si vuelven, sobre el modelo y el modo exactos que vas a usar en producción.
Checklist de implementación
- La API del verificador devuelve logprobs en el modelo y el modo concretos que vas a usar
- La escala de puntuación tiene granularidad suficiente (20 niveles, no 5)
- Los criterios están descompuestos y promediados, en vez de un único “¿está bien?”
- Tienes medido el pass@1 sin verificación como línea base, para saber cuánto aporta de verdad el verificador
- El coste está medido por tarea resuelta con
token_usage(), no estimado con el precio por millón de tokens - El ranking de N candidatos usa el torneo de pivotes y no todos contra todos
- Si generador y verificador son el mismo modelo, has contrastado una muestra contra un verificador distinto
Fuentes
- LLM-as-a-Verifier: A General-Purpose Verification Framework — Kwok, Li, Atreya, Liu, Jiang, Finn, Pavone, Stoica, Mirhoseini (arXiv:2607.05391) — método, fórmula de la puntuación continua, ablaciones de granularidad, repeticiones y criterios, resultados de best-of-N y apéndice B.6.
- Página del proyecto — Stanford Scaling Intelligence Lab — confirmación de los resultados en Terminal-Bench V2, SWE-Bench Verified, MedAgentBench y RoboRewardBench.
- Framework llm-verifier en GitHub — licencia MIT, API
select()/track()/ProgressTracker, proveedores soportados, caché de prefijos ytoken_usage()en la v0.2.0. - Hilo de Jacky Kwok en X — experimento posterior al paper: DeepSeek V4 Flash de 79% a 88% en Terminal-Bench 2.1 con cinco muestras, y el “11x más barato”.
- Precios de la API de DeepSeek — 0,14 $ por millón de tokens de entrada y 0,28 $ de salida en V4 Flash, y el recargo por horas punta anunciado.
- Chat Completions API — DeepSeek API Docs — parámetros
logprobsytop_logprobs(hasta 20) y el error que devuelve el modo de razonamiento si se los pides.
Preguntas Frecuentes
¿Puedo usar el modelo como verificador con la API de Anthropic?
Como verificador no, al menos directamente: la API de Anthropic no expone logprobs, y sin la distribución sobre los tokens de puntuación no hay puntuación continua que calcular. Tienes dos salidas. El apéndice B.6 del paper describe un procedimiento en dos etapas para modelos que no dan logprobs, y la opción práctica es separar los papeles: genera con Claude y verifica con Gemini o DeepSeek, que sí los devuelven. Esa separación tiene además la ventaja de que generador y verificador son modelos distintos, lo que reduce el sesgo de autopreferencia.
¿Esto sustituye al modelo como juez?
No. Es el mismo patrón con el mismo prompt, leyendo la distribución en vez del token que el juez escribió; para evaluación offline con histórico comparable, el juez discreto de toda la vida sigue valiendo.
¿Cuántos candidatos necesito para best-of-N?
El paper trabaja con N entre 3 y 5, y el experimento del autor con DeepSeek V4 Flash usó cinco muestras. A partir de ahí el coste crece de forma lineal y la mejora no, porque el techo lo pone el oráculo: si el candidato correcto no está entre los que generaste, ningún verificador lo va a encontrar.
¿Sirve para vigilar agentes en producción?
Sí, y es la aplicación que más me interesa de las tres que trae el framework. En las trayectorias que terminan bien, la puntuación del verificador sube conforme avanza el agente, así que puedes puntuar paso a paso con ProgressTracker y cortar una ejecución que lleva veinte pasos sin mejorar, en vez de esperar a que se le acabe el presupuesto. Con una salvedad que no puedes saltarte al llevarlo a producción: la señal está validada sobre trayectorias que acaban bien, así que calibra el umbral de corte contra tus propias ejecuciones fallidas antes de dejarlo cortando solo. Requiere además que tengas los pasos instrumentados y accesibles en tiempo real, que suele ser el trabajo de verdad.