Phase 05 - Lesson 28

Evaluación de Contexto Largo — NIAH, RULER, LongBench, MRCR

Gemini 3 Pro anuncia 10M de tokens de contexto. En 1M de tokens, el MRCR de 8 agujas cae al 26,3%. Anunciado ≠ utilizable. La evaluación de contexto largo te dice la capacidad real del modelo sobre el que estás desplegando.

Tipo: Aprender Lenguajes: Python Requisitos previos: Fase 5 · 13 (Preguntas y Respuestas), Fase 5 · 23 (Estrategias de Chunking) Tiempo: ~60 minutos

El Problema

Tienes un contrato de 200 páginas. El modelo afirma tener un contexto de 1M de tokens. Pegas el contrato completo y preguntas: "¿Cuál es la cláusula de rescisión?" El modelo responde — pero responde desde la portada, porque la cláusula de rescisión está a 120k tokens de profundidad, más allá de donde el modelo realmente presta atención.

Esta es la brecha de capacidad de contexto de 2026. Las fichas técnicas dicen 1M o 10M. La realidad dice que el 60-70% de eso es utilizable, y "utilizable" depende de la tarea.

  • Recuperación (una sola aguja en el pajar): casi perfecta hasta el máximo anunciado en modelos de frontera.
  • Multi-salto / agregación: se degrada bruscamente por encima de ~128k en la mayoría de los modelos.
  • Razonamiento sobre hechos dispersos: la primera tarea en fallar.

La evaluación de contexto largo mide estos ejes. Esta lección nombra los benchmarks, lo que cada uno realmente mide, y cómo construir una prueba de aguja personalizada para tu dominio.

El Concepto

NIAH baseline, RULER multi-task, LongBench holistic

Needle-in-a-Haystack (NIAH, 2023). Coloca un hecho ("la palabra mágica es piña") a una profundidad controlada dentro de un contexto largo. Pide al modelo que lo recupere. Barre profundidad × longitud. El benchmark original de contexto largo. Los modelos de frontera ahora saturan esta prueba; es una línea base necesaria pero no suficiente.

RULER (Nvidia, 2024). 13 tipos de tarea en 4 categorías: recuperación (clave única / múltiples claves / múltiples valores), rastreo multi-salto (seguimiento de variables), agregación (frecuencia de palabra común), QA. Longitud de contexto configurable (4k a 128k+). Revela modelos que saturan el NIAH pero fallan en multi-salto. En el lanzamiento de 2024, solo la mitad de los 17 modelos que afirmaban tener contexto de 32k+ mantuvo la calidad en 32k.

LongBench v2 (2024). 503 preguntas de opción múltiple, contextos de 8k a 2M palabras, seis categorías de tarea: QA de documento único, QA multi-documento, aprendizaje en contexto largo, diálogo largo, repositorio de código, datos estructurados largos. El benchmark de producción para el comportamiento de contexto largo en el mundo real.

MRCR (Multi-Round Coreference Resolution). Correferencia multi-turno a escala. Variantes de 8 agujas, 24 agujas, 100 agujas. Expone cuántos hechos puede manejar un modelo antes de que la atención se degrade.

NoLiMa. "Aguja no léxica." La aguja y la consulta no comparten ninguna superposición literal; la recuperación requiere un paso de razonamiento semántico. Más difícil que el NIAH.

HELMET. Concatena muchos documentos, hace una pregunta a partir de cualquiera de ellos. Prueba la atención selectiva.

BABILong. Inserta cadenas de razonamiento bAbI dentro de pajares irrelevantes. Prueba el razonamiento-en-el-pajar, no solo la recuperación.

Qué reportar realmente

  • Ventana de contexto anunciada. El número de la ficha técnica.
  • Longitud efectiva de recuperación. Aprobación en NIAH en algún umbral (por ejemplo, 90%).
  • Longitud efectiva de razonamiento. Aprobación en multi-salto o agregación en ese umbral.
  • Curva de degradación. Precisión vs longitud de contexto, graficada por tipo de tarea.

Dos números para tu ficha técnica: efectivo-para-recuperación y efectivo-para-razonamiento. Normalmente el efectivo-para-razonamiento es 25-50% de la ventana anunciada.

Constrúyelo

Paso 1: un NIAH personalizado para tu dominio

Ver code/main.py. El esqueleto:

def build_haystack(filler_text, needle, depth_ratio, total_tokens):
    if not (0.0 <= depth_ratio <= 1.0):
        raise ValueError(f"depth_ratio must be in [0, 1], got {depth_ratio}")
    if total_tokens <= 0:
        raise ValueError(f"total_tokens must be positive, got {total_tokens}")

    filler_tokens = tokenize(filler_text)
    needle_tokens = tokenize(needle)
    if not filler_tokens:
        raise ValueError("filler_text produced no tokens")

    # Repeat filler until long enough to fill the haystack body.
    body_len = max(total_tokens - len(needle_tokens), 0)
    while len(filler_tokens) < body_len:
        filler_tokens = filler_tokens + filler_tokens
    filler_tokens = filler_tokens[:body_len]

    insert_at = min(int(body_len * depth_ratio), body_len)
    haystack = filler_tokens[:insert_at] + needle_tokens + filler_tokens[insert_at:]
    return " ".join(haystack)


def score_niah(model, haystack, question, expected):
    answer = model.complete(f"Context: {haystack}\nQ: {question}\nA:", max_tokens=50)
    return 1 if expected.lower() in answer.lower() else 0

Barre depth_ratio ∈ {0, 0.25, 0.5, 0.75, 1.0} × total_tokens ∈ {1k, 4k, 16k, 64k}. Grafica el mapa de calor. Esa es la tarjeta NIAH de tu modelo objetivo.

Paso 2: una variante multi-aguja

def build_multi_needle(filler, needles, total_tokens):
    depths = [0.1, 0.4, 0.7]
    chunks = [filler[:int(total_tokens * 0.1)]]
    for depth, needle in zip(depths, needles):
        chunks.append(needle)
        next_chunk = filler[int(total_tokens * depth): int(total_tokens * (depth + 0.3))]
        chunks.append(next_chunk)
    return " ".join(chunks)

Preguntas como "¿Cuáles son las tres palabras mágicas?" requieren recuperar las tres. El éxito con una sola aguja no predice el éxito con múltiples agujas.

Paso 3: rastreo de variables multi-salto (estilo RULER)

haystack = """X1 = 42. ... (filler) ... X2 = X1 + 10. ... (filler) ... X3 = X2 * 2."""
question = "What is X3?"

La respuesta requiere encadenar tres asignaciones. Los modelos de frontera en 128k a menudo caen al 50-70% de precisión aquí.

Paso 4: LongBench v2 en tu stack

from datasets import load_dataset
longbench = load_dataset("THUDM/LongBench-v2")

def eval_model_on_longbench(model, subset="single-doc-qa"):
    tasks = [x for x in longbench["test"] if x["task"] == subset]
    correct = 0
    for x in tasks:
        answer = model.complete(x["context"] + "\n\nQ: " + x["question"], max_tokens=20)
        if normalize(answer) == normalize(x["answer"]):
            correct += 1
    return correct / len(tasks)

Reporta la precisión por categoría. Las puntuaciones agregadas ocultan grandes diferencias a nivel de tarea.

Trampas

  • Evaluación solo con NIAH. Pasar el NIAH en 1M de tokens no dice nada sobre multi-salto. Ejecuta siempre RULER o una prueba multi-salto personalizada.
  • Muestreo uniforme de profundidad. Muchas implementaciones solo prueban depth=0.5. Prueba depth=0, 0.25, 0.5, 0.75, 1.0 — el efecto "perdido en el medio" es real.
  • Superposición léxica con el relleno. Si la aguja comparte palabras clave con el relleno, la recuperación se vuelve trivial. Usa agujas sin superposición al estilo NoLiMa.
  • Ignorar la latencia. Los prompts de 1M de tokens tardan de 30 a 120 segundos en el prefill. Mide el tiempo hasta el primer token junto con la precisión.
  • Números autorreportados por los proveedores. OpenAI, Google y Anthropic publican todos sus propias puntuaciones. Vuelve a ejecutar siempre de forma independiente en tu caso de uso.

Úsalo

El stack de 2026:

Situación Benchmark
Verificación rápida de cordura NIAH personalizado en 3 profundidades × 3 longitudes
Selección de modelo para producción RULER (13 tareas) en tu longitud objetivo
Calidad de QA en el mundo real Subconjunto single-doc-QA de LongBench v2
Razonamiento multi-salto BABILong o rastreo de variables personalizado
Conversacional / diálogo MRCR 8 agujas en tu longitud objetivo
Regresión en actualización de modelo Harness NIAH + RULER interno fijo, ejecutado en cada nuevo modelo

Regla práctica para producción: nunca confíes en una ventana de contexto hasta tener NIAH + 1 tarea de razonamiento en tu longitud prevista.

Despliégalo

Guarda como outputs/skill-long-context-eval.md:

---
name: long-context-eval
description: Design a long-context evaluation battery for a given model and use case.
version: 1.0.0
phase: 5
lesson: 28
tags: [nlp, long-context, evaluation]
---

Given a target model, target context length, and use case, output:

1. Tests. NIAH depth × length grid; RULER multi-hop; custom domain task.
2. Sampling. Depths 0, 0.25, 0.5, 0.75, 1.0 at each length.
3. Metrics. Retrieval pass rate; reasoning pass rate; time-to-first-token; cost-per-query.
4. Cutoff. Effective retrieval length (90% pass) and effective reasoning length (70% pass). Report both.
5. Regression. Fixed harness, rerun on every model upgrade, surface deltas.

Refuse to trust a context window from the model card alone. Refuse NIAH-only evaluation for any multi-hop workload. Refuse vendor self-reported long-context scores as independent evidence.

Ejercicios

  1. Fácil. Construye un NIAH con 3 profundidades (0.25, 0.5, 0.75) × 3 longitudes (1k, 4k, 16k). Ejecútalo en cualquier modelo. Grafica la tasa de aprobación como un mapa de calor 3×3.
  2. Medio. Añade una variante de 3 agujas. Mide la recuperación de las 3 en cada longitud. Compara con la tasa de aprobación de aguja única en la misma longitud.
  3. Difícil. Construye una tarea de rastreo de variables (X1 → X2 → X3, con 3 saltos) embebida en 64k de relleno. Mide la precisión en 3 modelos de frontera. Reporta la longitud efectiva de razonamiento por modelo.

Términos Clave

Término Lo que dice la gente Lo que realmente significa
NIAH Aguja en el pajar Planta un hecho en el relleno y pide al modelo que lo recupere.
RULER NIAH potenciado 13 tipos de tarea en recuperación / multi-salto / agregación / QA.
Contexto efectivo La capacidad real Longitud en la que la precisión aún se mantiene por encima del umbral.
Perdido en el medio Sesgo de profundidad Los modelos prestan menos atención al contenido en el medio de entradas largas.
Multi-aguja Muchos hechos a la vez Múltiples plantas; prueba el manejo de la atención, no solo la recuperación.
MRCR Correferencia multi-turno Correferencia de 8, 24 o 100 agujas; expone la saturación de la atención.
NoLiMa Aguja no léxica La aguja y la consulta no comparten tokens literales; requiere razonamiento.

Lectura Adicional

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).