Tu propio benchmark de LLMs: por qué empezaría con programación competitiva

Cada nuevo modelo llega acompañado de una colección de números: razonamiento, matemáticas, código, multimodalidad, uso de herramientas, contextos largos y agentes.

El problema es que esos números responden, sobre todo, a las preguntas de quien diseñó el benchmark.

Si quieres decidir qué modelo funciona mejor para tus propios sistemas, puede ser más útil construir una capa de evaluación que puedas controlar, versionar y repetir.

La idea no es inventar un único “superbenchmark”. Es construir un benchmark harness: una infraestructura donde distintos conjuntos de tareas puedan ejecutarse bajo las mismas reglas, contra distintos modelos y con resultados auditables.

Y hay un primer dominio especialmente atractivo para empezar:

programación competitiva.

No porque represente toda la ingeniería de software, sino porque tiene tres propiedades excelentes para evaluar modelos: problemas claramente especificados, respuestas ejecutables y un juez objetivo.

El benchmark público no necesariamente mide lo que necesitas

Un leaderboard puede ser útil para descubrir tendencias, pero tiene limitaciones importantes.

La primera es la contaminación. Si un problema, su solución o una variante cercana apareció en datos de entrenamiento, una puntuación alta puede reflejar exposición previa además de capacidad de generalización.

La segunda es la calidad del propio benchmark. En julio de 2026, OpenAI publicó una auditoría de SWE-Bench Pro en la que su pipeline automático marcó el 27,4% de las tareas como problemáticas y una campaña humana identificó el 34,1%. Entre los fallos aparecieron tests demasiado estrictos, prompts incompletos, tests con poca cobertura y descripciones engañosas.

Eso importa porque un benchmark defectuoso puede medir la capacidad del modelo para adivinar las peculiaridades del test, no para resolver correctamente el problema.

La tercera limitación es más práctica: quizá el benchmark simplemente no representa tu carga de trabajo.

Un equipo que construye agentes de programación puede querer medir cosas diferentes a un laboratorio que evalúa razonamiento matemático. Puede importarle, por ejemplo:

  • cuánto cuesta completar una tarea;
  • cuántos intentos necesita el agente;
  • si sabe reparar un programa después de un error;
  • cuánto tiempo consume;
  • si utiliza correctamente el shell;
  • si introduce regresiones;
  • o si una versión nueva del modelo empeora una tarea que antes resolvía.

Ahí empieza a tener sentido un sistema propio.

Benchmark #1: problemas de programación competitiva

La programación competitiva ofrece una unidad de evaluación muy limpia.

El modelo recibe un enunciado y debe producir un programa. Después, el sistema compila o ejecuta ese programa contra tests y obtiene uno de los resultados clásicos de los jueces online:

AC  Accepted
WA  Wrong Answer
TLE Time Limit Exceeded
MLE Memory Limit Exceeded
RE  Runtime Error
CE  Compilation Error

No necesitas preguntarle a otro LLM si “la solución parece buena”.

El código funciona o no funciona bajo un conjunto de tests determinado.

Un problema podría representarse así:

id: cp-000314
source: codeforces
source_id: 2045-C
published_at: 2026-08-17
difficulty: hard
topics:
  - dynamic-programming
  - strings

languages:
  - python
  - cpp

time_limit_ms: 2000
memory_limit_mb: 256

prompt: problem.md
tests: private

Después, el runner ejecuta una secuencia determinista:

modelo
  ↓
código generado
  ↓
compilación / ejecución
  ↓
tests privados
  ↓
AC / WA / TLE / MLE / RE / CE

Ese diseño es simple, pero produce una señal muy valiosa.

LiveCodeBench ya demostró por qué los problemas frescos importan

Esta idea tiene un precedente importante: LiveCodeBench.

El proyecto recopila continuamente problemas de concursos de LeetCode, AtCoder y Codeforces y conserva su fecha de publicación. Eso permite evaluar un modelo usando ventanas temporales concretas.

Si conoces aproximadamente el cutoff de entrenamiento de un modelo, puedes seleccionar únicamente problemas publicados después de esa fecha.

Conceptualmente:

training cutoff del modelo
            │
            ▼
────────────┼──────────────────────── tiempo
            │   problemas frescos
            │   usados para evaluar

LiveCodeBench también muestra por qué no conviene reducir “programar” a una sola tarea. Además de generación de código, evalúa capacidades como self-repair, ejecución de código y predicción del output de tests.

La lección importante no es copiar LiveCodeBench exactamente.

Es adoptar su principio de freshness.

Tu benchmark podría mantener vistas como:

ALL
POST-CUTOFF
FRESH-365D
FRESH-90D
FRESH-30D
PRIVATE

Y entonces un resultado empieza a tener mucho más contexto:

Modelo X

Todos los problemas       81%
Post-cutoff                68%
Últimos 90 días            64%
Últimos 30 días            61%
Problemas privados         59%

Ese 61% o 59% puede ser más informativo que una puntuación brillante sobre un dataset que lleva años circulando por Internet.

El juez online debería ser una fuente, no tu infraestructura de evaluación

Hay una tentación evidente:

LLM
 ↓
submit a Codeforces
 ↓
esperar resultado

Pero depender del juez externo para cada evaluación introduce demasiadas variables:

  • latencia;
  • disponibilidad;
  • cuentas y autenticación;
  • límites de uso;
  • cambios en la plataforma;
  • dificultad para repetir exactamente una corrida;
  • y condiciones de uso que pueden limitar la automatización o redistribución de contenido.

Por eso resulta más robusto separar dos funciones.

Los jueces online pueden ser fuente de problemas y referencia histórica. Tu plataforma debería intentar ejecutar la evaluación en un sandbox propio cuando las licencias, tests y términos de cada fuente lo permitan.

Online judges / tareas propias
            ↓
      problem ingestion
            ↓
     benchmark registry
            ↓
       sandbox local
            ↓
     evaluator determinista

La infraestructura queda bajo tu control.

Eso permite congelar una versión del benchmark y repetirla seis meses después sin que un servicio externo cambie debajo de tus pies.

No mezcles “modelo” y “agente” en el mismo ranking

Este punto es crítico.

Hay dos evaluaciones distintas que a menudo aparecen mezcladas.

Model-only

El modelo recibe el problema y produce una única respuesta.

problema → modelo → solución

Sin shell. Sin ejecutar tests. Sin navegar. Sin feedback.

Aquí intentas medir principalmente la capacidad del modelo.

Agent

El sistema puede escribir código, ejecutarlo, observar errores, modificarlo y volver a intentarlo.

problema
  ↓
agente escribe solución
  ↓
ejecuta tests
  ↓
observa error
  ↓
corrige
  ↓
vuelve a ejecutar

Aquí ya estás midiendo otra cosa:

modelo + harness + herramientas + estrategia de iteración.

Los dos rankings son interesantes, pero no significan lo mismo.

Un modelo que pierde en model-only podría convertirse en un agente superior si utiliza mejor el feedback, administra mejor el contexto o repara sus errores con mayor eficiencia.

pass@1 es sólo el comienzo

La métrica más intuitiva es pass@1: qué porcentaje de problemas se resuelve correctamente en el primer intento.

Pero un benchmark propio puede registrar bastante más.

MétricaQué revela
pass@1capacidad de resolver a la primera
pass@3capacidad con varios intentos
compile ratefrecuencia con que genera código ejecutable
test pass ratioporcentaje de tests superados
repair successcapacidad de corregirse tras feedback
attempts-to-ACintentos necesarios para llegar a Accepted
latencyvelocidad de respuesta
tokenseficiencia de contexto y generación
costcoste monetario por corrida
runtimeeficiencia del programa generado
memoryconsumo de memoria de la solución

Así, una comparación deja de ser:

Modelo A: 74
Modelo B: 71

Y se convierte en algo mucho más útil:

                   Modelo A   Modelo B
pass@1                74%        71%
repair success        42%        68%
avg attempts          1.8        1.4
median latency        9.2s       15.7s
avg cost/problem     $0.06      $0.03

Ahora ya puedes tomar una decisión de ingeniería.

El coste correcto puede ser “dólares por tarea resuelta”

Los proveedores suelen publicar precios por millón de tokens.

Para un sistema agéntico, esa unidad no siempre cuenta la historia completa.

Imagina dos modelos:

Modelo A
$0.03 por intento
40% de éxito

Modelo B
$0.07 por intento
85% de éxito

El modelo A parece más barato por llamada.

Pero el dato realmente importante podría ser:

coste por problema resuelto correctamente

Cuando incorporas retries, ejecuciones, herramientas y tiempo de cómputo, el ranking económico puede cambiar por completo.

Un benchmark propio te permite medir justamente esa unidad.

Benchmark #2: ingeniería de software real

La programación competitiva es un gran primer laboratorio, pero no representa mantener un repositorio real.

El segundo benchmark natural sería algo parecido a SWE-bench:

snapshot de repositorio
+
issue
+
tests secretos
        ↓
agente
        ↓
git diff
        ↓
tests
        ↓
PASS / FAIL

SWE-bench ejecuta repositorios en Docker y evalúa si el patch generado resuelve un issue real. Esa reproducibilidad es una idea que vale la pena conservar.

Pero la experiencia reciente de SWE-bench también deja otra lección: los tests y los prompts del benchmark necesitan su propia QA.

Un problema aparentemente válido puede estar mal especificado, exigir mediante tests algo que el enunciado nunca pidió o permitir shortcuts no deseados.

Por eso, para un benchmark privado, sería especialmente valioso escribir tareas nuevas deliberadamente para evaluación.

Eso reduce la contaminación y permite diseñar tests alrededor del comportamiento deseado, en lugar de reconstruir retrospectivamente la intención de un issue histórico.

OpenAI, en sus recomendaciones recientes sobre evaluaciones de terceros, también señala que los evaluadores deberían preferir tareas privadas o recién construidas cuando sea posible y tratar los problemas rotos como un riesgo estándar de validez.

Guarda el trace completo de cada corrida

Una puntuación sin contexto envejece mal.

Cada ejecución debería producir un artefacto reproducible con información como:

{
  "benchmark": "competitive-programming",
  "benchmark_version": "2026.09.1",
  "problem": "cp-314",
  "model": "provider/model-x",
  "mode": "agent",
  "temperature": 0,
  "prompt_hash": "...",
  "tokens_in": 1820,
  "tokens_out": 2921,
  "latency_ms": 12421,
  "cost_usd": 0.031,
  "attempts": 2,
  "result": "AC",
  "tests_passed": 47,
  "tests_total": 47
}

En modo agente también conviene conservar el trace operacional:

qué vio
→ qué decidió
→ qué herramienta llamó
→ qué devolvió la herramienta
→ qué archivo modificó
→ qué test falló
→ cómo reaccionó

Eso transforma el benchmark en una herramienta de diagnóstico, no solamente en un leaderboard.

Si un modelo nuevo baja del 72% al 68%, puedes investigar por qué.

La arquitectura: construir un harness, no una colección de scripts

El sistema puede separarse en cinco piezas.

Benchmark Registry
       │
       ▼
Benchmark Runner
       │
       ├──────── Model adapters
       │          ├ OpenAI
       │          ├ Anthropic
       │          ├ Google
       │          └ modelos locales
       │
       ▼
Sandbox / executor
       │
       ▼
Evaluator
       │
       ▼
Results DB + traces + dashboard

Cada benchmark define su contrato.

Cada proveedor implementa un adapter.

El runner se ocupa de ejecutar bajo reglas consistentes.

Y el evaluator decide qué significa éxito.

Eso permite imaginar una CLI sencilla:

llmbench run cp \
  --model provider/model-x \
  --suite fresh-30d

llmbench run swe \
  --model provider/model-y \
  --suite private-bugs-v1

llmbench compare \
  provider/model-x \
  provider/model-y

La parte valiosa no sería el comando.

Sería poder repetir exactamente la misma evaluación cuando aparezca un modelo nuevo.

Tu benchmark no tiene que ser universal

Ésta quizá sea la idea más importante.

Un benchmark propio no tiene que convencer a toda la industria.

Tiene que ayudarte a responder preguntas concretas:

  • ¿qué modelo elijo para este agente?
  • ¿la nueva versión realmente mejoró?
  • ¿cuánto cuesta resolver una tarea real?
  • ¿qué modelo repara mejor sus propios errores?
  • ¿qué harness obtiene más valor del mismo modelo?
  • ¿qué regresiones introdujo una actualización?
  • ¿cuánto cae el rendimiento cuando usamos problemas posteriores al cutoff?

La programación competitiva es un excelente comienzo porque ofrece una señal objetiva y barata de automatizar.

Después puedes añadir debugging, ingeniería de repositorios, terminal, tool use, contextos largos, investigación web o incluso benchmarks privados derivados de tus propios flujos de trabajo.

El resultado final no sería simplemente otro leaderboard.

Sería algo más útil:

tu propio laboratorio para decidir cuándo un LLM realmente es mejor para el trabajo que quieres hacer.

Fuentes