Phase 05 - Lesson 28

Avaliação de Contexto Longo — NIAH, RULER, LongBench, MRCR

O Gemini 3 Pro anuncia 10M de tokens de contexto. Em 1M de tokens, o MRCR de 8 agulhas cai para 26,3%. Anunciado ≠ utilizável. A avaliação de contexto longo revela a capacidade real do modelo no qual você está embarcando.

Tipo: Aprender Linguagens: Python Pré-requisitos: Fase 5 · 13 (Perguntas e Respostas), Fase 5 · 23 (Estratégias de Chunking) Tempo: ~60 minutos

O Problema

Você tem um contrato de 200 páginas. O modelo afirma ter um contexto de 1M de tokens. Você cola o contrato inteiro e pergunta: "Qual é a cláusula de rescisão?" O modelo responde — mas responde a partir da página de capa, porque a cláusula de rescisão está a 120k tokens de profundidade, além de onde o modelo realmente presta atenção.

Esse é o vão de capacidade de contexto de 2026. As fichas técnicas dizem 1M ou 10M. A realidade diz que 60-70% disso é utilizável, e "utilizável" depende da tarefa.

  • Recuperação (uma única agulha no palheiro): quase perfeita até o máximo anunciado em modelos de fronteira.
  • Multi-salto / agregação: degrada acentuadamente acima de ~128k na maioria dos modelos.
  • Raciocínio sobre fatos dispersos: a primeira tarefa a falhar.

A avaliação de contexto longo mede esses eixos. Esta lição nomeia os benchmarks, o que cada um realmente mede, e como construir um teste de agulha personalizado para o seu domínio.

O Conceito

NIAH baseline, RULER multi-task, LongBench holistic

Needle-in-a-Haystack (NIAH, 2023). Coloque um fato ("a palavra mágica é abacaxi") em uma profundidade controlada dentro de um contexto longo. Peça ao modelo que o recupere. Varra profundidade × comprimento. O benchmark original de contexto longo. Modelos de fronteira agora saturam este teste; ele é uma linha de base necessária, mas não suficiente.

RULER (Nvidia, 2024). 13 tipos de tarefa em 4 categorias: recuperação (chave única / múltiplas chaves / múltiplos valores), rastreamento multi-salto (rastreamento de variáveis), agregação (frequência de palavra comum), QA. Comprimento de contexto configurável (4k a 128k+). Revela modelos que saturam o NIAH mas falham em multi-salto. No lançamento de 2024, apenas metade dos 17 modelos que afirmavam ter contexto de 32k+ manteve a qualidade em 32k.

LongBench v2 (2024). 503 perguntas de múltipla escolha, contextos de 8k a 2M palavras, seis categorias de tarefa: QA de documento único, QA multi-documento, aprendizado em contexto longo, diálogo longo, repositório de código, dados estruturados longos. O benchmark de produção para comportamento de contexto longo no mundo real.

MRCR (Multi-Round Coreference Resolution). Correferência multi-turno em escala. Variantes de 8 agulhas, 24 agulhas, 100 agulhas. Expõe quantos fatos um modelo consegue manejar antes que a atenção degrade.

NoLiMa. "Agulha não lexical." A agulha e a consulta não compartilham nenhuma sobreposição literal; a recuperação exige um passo de raciocínio semântico. Mais difícil que o NIAH.

HELMET. Concatena muitos documentos, faz uma pergunta a partir de qualquer um deles. Testa a atenção seletiva.

BABILong. Insere cadeias de raciocínio bAbI dentro de palheiros irrelevantes. Testa raciocínio-no-palheiro, não apenas recuperação.

O que de fato reportar

  • Janela de contexto anunciada. O número da ficha técnica.
  • Comprimento efetivo de recuperação. Aprovação no NIAH em algum limiar (por exemplo, 90%).
  • Comprimento efetivo de raciocínio. Aprovação em multi-salto ou agregação naquele limiar.
  • Curva de degradação. Acurácia vs comprimento de contexto, plotada por tipo de tarefa.

Dois números para a sua ficha técnica: efetivo-para-recuperação e efetivo-para-raciocínio. Normalmente o efetivo-para-raciocínio é 25-50% da janela anunciada.

Construa Isso

Passo 1: um NIAH personalizado para o seu domínio

Veja code/main.py. O 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

Varra depth_ratio ∈ {0, 0.25, 0.5, 0.75, 1.0} × total_tokens ∈ {1k, 4k, 16k, 64k}. Plote o mapa de calor. Esse é o cartão NIAH do seu modelo-alvo.

Passo 2: uma variante multi-agulha

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)

Perguntas como "Quais são as três palavras mágicas?" exigem recuperar as três. O sucesso com uma única agulha não prevê o sucesso com múltiplas agulhas.

Passo 3: rastreamento de variáveis multi-salto (estilo RULER)

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

A resposta exige encadear três atribuições. Modelos de fronteira em 128k frequentemente caem para 50-70% de acurácia aqui.

Passo 4: LongBench v2 na sua 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)

Reporte a acurácia por categoria. Pontuações agregadas escondem grandes diferenças no nível da tarefa.

Armadilhas

  • Avaliação apenas com NIAH. Passar no NIAH em 1M de tokens não diz nada sobre multi-salto. Sempre execute o RULER ou um teste multi-salto personalizado.
  • Amostragem uniforme de profundidade. Muitas implementações só testam depth=0.5. Teste depth=0, 0.25, 0.5, 0.75, 1.0 — o efeito "perdido no meio" é real.
  • Sobreposição lexical com o preenchimento. Se a agulha compartilha palavras-chave com o preenchimento, a recuperação se torna trivial. Use agulhas sem sobreposição no estilo NoLiMa.
  • Ignorar a latência. Prompts de 1M de tokens levam de 30 a 120 segundos para o prefill. Meça o tempo até o primeiro token junto com a acurácia.
  • Números autorreportados pelos fornecedores. OpenAI, Google e Anthropic publicam todos as suas próprias pontuações. Sempre execute novamente de forma independente no seu caso de uso.

Use Isso

A stack de 2026:

Situação Benchmark
Verificação rápida de sanidade NIAH personalizado em 3 profundidades × 3 comprimentos
Seleção de modelo para produção RULER (13 tarefas) no seu comprimento-alvo
Qualidade de QA no mundo real Subconjunto single-doc-QA do LongBench v2
Raciocínio multi-salto BABILong ou rastreamento de variáveis personalizado
Conversacional / diálogo MRCR 8 agulhas no seu comprimento-alvo
Regressão em atualização de modelo Harness NIAH + RULER interno fixo, executado em cada novo modelo

Regra prática para produção: nunca confie em uma janela de contexto até ter NIAH + 1 tarefa de raciocínio no comprimento pretendido.

Entregue Isso

Salve 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.

Exercícios

  1. Fácil. Construa um NIAH com 3 profundidades (0.25, 0.5, 0.75) × 3 comprimentos (1k, 4k, 16k). Execute em qualquer modelo. Plote a taxa de aprovação como um mapa de calor 3×3.
  2. Médio. Adicione uma variante de 3 agulhas. Meça a recuperação das 3 em cada comprimento. Compare com a taxa de aprovação de agulha única no mesmo comprimento.
  3. Difícil. Construa uma tarefa de rastreamento de variáveis (X1 → X2 → X3, com 3 saltos) embutida em 64k de preenchimento. Meça a acurácia em 3 modelos de fronteira. Reporte o comprimento efetivo de raciocínio por modelo.

Termos-Chave

Termo O que as pessoas dizem O que realmente significa
NIAH Agulha no palheiro Planta um fato no preenchimento e pede ao modelo que o recupere.
RULER NIAH turbinado 13 tipos de tarefa em recuperação / multi-salto / agregação / QA.
Contexto efetivo A capacidade real Comprimento no qual a acurácia ainda se mantém acima do limiar.
Perdido no meio Viés de profundidade Modelos prestam menos atenção ao conteúdo no meio de entradas longas.
Multi-agulha Muitos fatos de uma vez Múltiplas plantas; testa o manejo da atenção, não apenas a recuperação.
MRCR Correferência multi-turno Correferência de 8, 24 ou 100 agulhas; expõe a saturação da atenção.
NoLiMa Agulha não lexical Agulha e consulta não compartilham tokens literais; exige raciocínio.

Leitura Adicional

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