antonio leandro

claude, na prática

Introducing Contextual Retrieval

post · núcleo · 03 · contexto · Anthropic ·

a tese

o chunk perde o referente quando você o corta do documento; colar de volta 50 a 100 tokens de contexto gerados por um llm antes de indexar derruba a taxa de falha de recuperação pela metade

o que fica

  1. Um chunk isolado costuma perder o sujeito e a data: "a receita cresceu 3% sobre o trimestre anterior" não diz de qual empresa nem de quando, e por isso não é recuperado.
  2. Gerar 50 a 100 tokens de contexto por chunk e prepend antes de indexar reduziu a falha de recuperação no top-20 em 35% só nos embeddings, e em 49% quando o mesmo texto também entra no índice BM25.
  3. Embedding erra match exato: uma busca por um código de erro específico pode voltar conteúdo genérico sobre códigos de erro, e é para isso que BM25 continua no pipeline em 2024.
  4. Contextualizar é pré-processamento, não runtime: o custo é único e ficou em US$ 1,02 por milhão de tokens de documento porque o documento inteiro vai para o prompt cache uma vez, em vez de ser reenviado a cada chunk.
  5. Se a base cabe em 200.000 tokens, a recomendação dos próprios autores é não fazer RAG nenhum e jogar tudo no prompt.
  6. A queda de 67% com reranking sai de 5,7% para 1,9% de falha: o ganho relativo é grande porque a linha de base já era boa, e são 3,8 pontos percentuais em valor absoluto.

o problema

RAG resolveu o problema de escala e criou outro. Para caber numa base grande, o documento é picado em chunks de algumas centenas de tokens, cada chunk vira um vetor, e a busca acontece por similaridade semântica. O corte é cego: ele não sabe que a frase “a receita da empresa cresceu 3% sobre o trimestre anterior” só significa alguma coisa se você souber que o documento é um filing da ACME sobre o segundo trimestre de 2023. Isolado, esse chunk não casa com a pergunta “qual foi o crescimento de receita da ACME no Q2 de 2023” — não porque o dado não está lá, mas porque o texto indexado não carrega o referente.

O segundo problema é mais antigo. Embedding captura relação semântica e erra match literal. Quem procura “error code TS-999” quer aquela string, e o modelo de embedding devolve conteúdo sobre códigos de erro em geral. A resposta usual é rodar BM25 junto — lexical, com TF-IDF, saturação de frequência e normalização por tamanho de documento — e fundir os rankings. Só que BM25 indexa os mesmos chunks decapitados. Os dois canais herdam o mesmo defeito.

a ideia

Antes de indexar, pedir a um modelo que olhe o documento inteiro e escreva uma frase curta situando aquele chunk dentro dele. Esse texto é prepended ao chunk e vai junto para os dois índices: o vetorial e o BM25. O chunk do exemplo deixa de ser uma frase solta e vira “este trecho é de um filing da ACME sobre o Q2 de 2023; a receita do trimestre anterior foi de US$ 314 milhões” seguido do texto original.

Não é resumo de documento colado em todo chunk — os autores testaram isso e viram ganho muito limitado. O contexto é específico do chunk: ele responde “o que falta aqui para esta passagem se sustentar sozinha”, e a resposta é diferente para cada pedaço do mesmo documento.

como funciona

O pipeline é de pré-processamento. Para cada chunk, um prompt manda o documento inteiro entre tags, o chunk entre tags, e pede contexto sucinto para melhorar a recuperação, com a instrução de responder só o contexto e nada mais. O modelo usado foi o Claude 3 Haiku e a saída fica em 50 a 100 tokens. Esse texto é concatenado à frente do chunk, e só então o chunk é embeddado e entra no índice BM25.

O custo poderia inviabilizar tudo: reenviar um documento de 8.000 tokens para cada um dos seus chunks de 800 tokens é pagar dez vezes pelo mesmo documento. É onde entra prompt caching — o documento vai para o cache uma vez e os chunks seguintes referenciam o conteúdo cacheado. Com essas premissas, a conta fecha em US$ 1,02 por milhão de tokens de documento, custo único.

Em runtime nada muda em relação a um RAG híbrido comum: BM25 traz os top chunks por match exato, os embeddings trazem os top por similaridade, rank fusion junta e deduplica, e os top-20 vão para o prompt. Na configuração com reranking, a recuperação inicial pega 150 chunks, um reranker pontua todos em paralelo contra a query, e os 20 melhores seguem.

A métrica é 1 menos recall@20 — o percentual de documentos relevantes que não aparecem entre os 20 chunks recuperados. Com o melhor embedding testado (Gemini Text 004), a média entre os domínios avaliados foi: 5,7% de falha na linha de base, 3,7% com contextual embeddings, 2,9% somando contextual BM25, e 1,9% acrescentando o reranker da Cohere.

o que isso custou

O ganho de 67% é relativo sobre uma base que já acertava 94,3% das vezes: em valor absoluto são 3,8 pontos percentuais. Vale a conta em domínio onde a falha é cara, e o post é honesto ao ancorar tudo em números absolutos.

O reranking adiciona uma etapa em runtime e, portanto, latência e custo, com trade-off explícito entre reranquear mais chunks e responder rápido. O reranker da Voyage não foi testado. Os autores também não escondem que o resultado depende de decisões que continuam sendo suas: tamanho do chunk, fronteira, overlap, e qual modelo de embedding — a técnica ajudou em todas as combinações avaliadas, mas alguns modelos ganham mais que outros. Passar 20 chunks bateu 10 e 5, com a ressalva de que mais informação também distrai o modelo, então o número ótimo é empírico.

E há o limite de cima: se a base tem menos de 200.000 tokens, mais ou menos 500 páginas, a recomendação é não montar RAG nenhum e colocar tudo no prompt.

onde isso aparece hoje

O post é um dos textos que consolidaram a receita padrão de recuperação: busca híbrida em vez de só vetorial, contexto gerado por llm no momento da indexação, e reranker antes de entregar ao gerador. A observação de que os ganhos empilham é o que ficou — cada peça sozinha rende pouco, o conjunto rende.

O outro efeito é sobre prompt caching, que aqui deixa de ser otimização de latência e vira condição de viabilidade econômica: sem cache, contextualizar uma base grande custaria uma ordem de grandeza a mais. Chamar o modelo milhões de vezes em pré-processamento passou a ser uma linha de orçamento defensável.

lido na íntegra por pipeline de llm, revisado por antonio leandro antes de publicar ·