# RAG: dando contexto ao modelo

> O que é RAG, por que contexto longo não acaba com ele e como funcionam a busca por termos, por embeddings e os bancos vetoriais.

- Autor: Marcelo Silva
- Publicado em: 2026-02-19
- Tema: IA
- Série: Engenharia de IA, parte 10 de 14 (https://marcelxsilva.dev/series/engenharia-de-ia/)
- URL: https://marcelxsilva.dev/artigos/rag-recuperacao-de-contexto/

Para resolver uma tarefa, o modelo precisa de duas coisas: instruções de como fazer e as informações necessárias para fazer. Uma pessoa sem informação suficiente tem mais chance de errar, e com modelo é igual. Sem contexto, ele erra mais e **alucina** mais.

Hoje existem dois padrões principais para montar esse contexto:

- **RAG** (*retrieval-augmented generation*, ou geração aumentada por recuperação): o modelo busca informações relevantes em fontes de dados externas.
- **Agentes:** o modelo usa ferramentas, como pesquisa na web ou APIs, para coletar o que precisa.

O RAG é usado principalmente para construir contexto. Os agentes vão além: as ferramentas ajudam o modelo a compensar suas limitações e, mais importante, permitem que ele interaja com o mundo e execute ações. Agentes ficam para os próximos artigos da série, aqui o foco é o RAG.

## O que é RAG

RAG é uma técnica que melhora a resposta do modelo buscando informações relevantes em uma **memória externa**. Essa memória pode ser um banco de dados interno, o histórico de conversas do usuário ou a própria internet.

A ideia de *recuperar e depois gerar* apareceu em ["Reading Wikipedia to Answer Open-Domain Questions"](https://arxiv.org/abs/1704.00051) (Chen et al., 2017). O sistema buscava as cinco páginas da Wikipedia mais relevantes para uma pergunta e um modelo lia essas páginas para montar a resposta.

![Pergunta passando por um recuperador de documentos da Wikipedia e por um leitor que extrai a resposta](https://marcelxsilva.dev/articles/images/rag-recuperacao-de-contexto/01.png)
*Recuperar e depois gerar: o recuperador encontra as páginas relevantes e o leitor extrai a resposta delas.*

O nome RAG veio depois, em ["Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks"](https://arxiv.org/abs/2005.11401) (Lewis et al., 2020). A proposta era resolver tarefas que exigem muito conhecimento, onde não dá para colocar tudo dentro do modelo. Com RAG, só entra no prompt o que o recuperador considera mais relevante para aquela consulta. O resultado foram respostas mais detalhadas e menos alucinação.

Um jeito simples de pensar no RAG: ele constrói um **contexto específico para cada consulta**, em vez de usar o mesmo contexto para todas. Isso também ajuda com dados de usuário, porque as informações de uma pessoa só entram nas consultas relacionadas a ela.

### Contexto longo não acaba com o RAG

No começo, o RAG surgiu principalmente para contornar o limite de contexto dos modelos. Por isso muita gente acha que, com janelas de contexto cada vez maiores, o RAG vai deixar de existir. Tem pelo menos dois motivos para isso não acontecer:

1. **Sempre vai ter mais dado do que contexto.** A quantidade de dados só cresce. As pessoas criam informação nova o tempo todo e quase nunca apagam a antiga. As janelas de contexto crescem rápido, mas não no mesmo ritmo.
2. **Caber no contexto não é o mesmo que ser bem usado.** Quanto mais longo o contexto, maior a chance de o modelo prestar atenção na parte errada. E cada token a mais custa dinheiro e pode aumentar a latência. Com RAG, o modelo recebe só o que importa para aquela consulta, com menos tokens e melhor resultado.

Ao mesmo tempo que os contextos aumentam, os provedores também trabalham para os modelos usarem melhor o contexto que recebem. Não seria estranho ver mecanismos parecidos com recuperação embutidos nos próprios modelos.

> A Anthropic sugeriu que, para os modelos Claude, se "sua base de conhecimento for menor que 200.000 tokens (cerca de 500 páginas de material), você pode simplesmente incluir toda a base de conhecimento no prompt que fornecer ao modelo, sem necessidade de RAG ou métodos semelhantes" ([Anthropic, 2024](https://www.anthropic.com/engineering/contextual-retrieval)). Seria ótimo se outros provedores dessem uma orientação parecida para os seus modelos.

## Arquitetura do RAG

Um sistema RAG tem dois componentes:

- **Recuperador:** busca as informações na memória externa.
- **Gerador:** gera a resposta usando o que foi recuperado.

![Arquitetura básica de um sistema RAG com memória externa, recuperador e modelo generativo](https://marcelxsilva.dev/articles/images/rag-recuperacao-de-contexto/02.png)
*O prompt do usuário vai para o recuperador, que busca o contexto relevante na memória externa e entrega para o modelo generativo.*

O sucesso de um RAG depende muito da qualidade do recuperador. Ele tem duas funções:

- **Indexação:** processar os dados para que possam ser encontrados rápido depois.
- **Consulta:** enviar uma busca e receber os dados relevantes para ela.

E a forma de indexar depende de como você vai buscar depois.

Pense em um exemplo: a memória externa é um banco de documentos da empresa, como contratos, memorandos e atas de reunião. Um documento pode ter 10 tokens ou 1 milhão de tokens. Se você recuperar documentos inteiros, o contexto pode ficar enorme. Por isso cada documento é dividido em **blocos** (*chunks*) de tamanho mais controlado.

Com os documentos já divididos, o objetivo de cada consulta é trazer os blocos mais relevantes. Depois, um pequeno pós-processamento junta esses blocos com o prompt do usuário, e esse prompt final vai para o modelo.

## Algoritmos de recuperação

> Fica como tarefa estudar melhor os algoritmos de buscas em RAG, para entender o que melhor atende dependendo do caso, além de analisar se o banco vetorial atende a necessidade, pois internamente eles carregam algoritmos de indexação e busca.

Recuperação de informação não nasceu com o RAG. É uma área com décadas de pesquisa, que sustenta mecanismos de busca, sistemas de recomendação, análise de logs e muito mais. Muita coisa criada para esses sistemas funciona bem em RAG também.

> Recuperação normalmente se limita a um banco ou sistema, enquanto pesquisa envolve buscar em vários sistemas. Aqui uso os dois termos como se fossem a mesma coisa.

No fundo, recuperar é **ordenar documentos pela relevância** para uma consulta. O que muda de um algoritmo para outro é como essa relevância é calculada.

### Esparso e denso

Na literatura é comum ver os algoritmos divididos em dois grupos.

**Esparsos** representam os dados com vetores em que quase todos os valores são 0. A recuperação baseada em termos entra aqui, porque cada termo pode ser representado por um vetor *one-hot*: tudo 0, menos uma posição com 1. O tamanho do vetor é o tamanho do vocabulário.

Com um dicionário simples como `{"comida": 0, "banana": 1, "lesma": 2}`, os vetores ficam:

- comida: `[1, 0, 0]`
- banana: `[0, 1, 0]`
- lesma: `[0, 0, 1]`

**Densos** usam vetores em que a maioria dos valores não é 0. A recuperação baseada em *embeddings* costuma ser densa, porque embeddings geralmente são vetores densos.

Existem exceções. O [SPLADE](https://arxiv.org/abs/2107.05720) (Formal et al., 2021) usa embeddings esparsos: parte dos embeddings gerados pelo BERT e força a maioria dos valores para 0, o que deixa as operações mais eficientes.

### Recuperação baseada em termos

O jeito mais direto de achar documentos relevantes é por **palavra-chave**. Isso também é chamado de recuperação lexical. Se a busca é "engenharia de IA", você traz os documentos que contêm "engenharia de IA". Só que isso tem dois problemas.

**Muitos documentos podem ter o mesmo termo**, e não cabe tudo no contexto. Uma saída é priorizar os documentos onde o termo aparece mais vezes, assumindo que eles são mais relevantes. Essa contagem é a **frequência do termo** (TF, *term frequency*).

**Nem todo termo importa igual.** O prompt "receitas fáceis de comida vietnamita para fazer em casa" tem palavras como "receitas" e "vietnamita", que dizem muito, e palavras como "de" e "para", que não dizem nada. A intuição é: quanto mais documentos têm um termo, menos informativo ele é. Essa medida é a **frequência inversa de documentos** (IDF, *inverse document frequency*). Para calcular, divida o total de documentos pela quantidade de documentos que contêm o termo. Com 10 documentos e o termo aparecendo em 5, o IDF é 10 / 5 = 2. Quanto maior o IDF, mais importante o termo.

O **TF-IDF** combina as duas métricas.

### Recuperação baseada em embeddings

A busca por termos olha para a forma das palavras, não para o significado. Buscar "arquitetura de transformers" pode trazer documentos sobre transformadores elétricos ou sobre o filme *Transformers*. A recuperação baseada em embeddings tenta ordenar os documentos pelo quanto o **significado** deles se aproxima da consulta. Por isso também é chamada de **recuperação semântica**.

Aqui a indexação ganha uma etapa extra: transformar cada bloco em embedding e guardar em um **banco de dados vetorial**. Na consulta acontece o seguinte:

1. **Modelo de embedding:** transforma a consulta em embedding, usando o mesmo modelo da indexação.
2. **Recuperador:** busca os *k* blocos cujos embeddings estão mais próximos do embedding da consulta. O valor de *k* depende do caso de uso, do modelo e da própria consulta.

![Fluxo de recuperação baseada em embeddings com indexação, banco vetorial, recuperador e modelo generativo](https://marcelxsilva.dev/articles/images/rag-recuperacao-de-contexto/03.png)
*Na indexação os documentos são divididos e transformados em embeddings. Na consulta, o embedding da pergunta é comparado com os do banco vetorial.*

Esse é um fluxo simplificado. Em produção é comum ter outros componentes, como um *reranker* para reordenar os candidatos e caches para reduzir a latência.

### Bancos de dados vetoriais

Guardar vetores é a parte fácil. O difícil é a **busca vetorial**: dado o embedding da consulta, encontrar rápido os vetores mais próximos. Para isso, os vetores precisam ser indexados de um jeito que deixe essa busca eficiente.

Busca vetorial aparece em qualquer aplicação que usa embeddings: pesquisa, recomendação, organização de dados, clustering, detecção de fraude.

Normalmente ela é tratada como um problema de **vizinhos mais próximos**. A solução ingênua é o **k-NN** (*k-nearest neighbors*):

1. Calcula a similaridade (por exemplo, similaridade de cosseno) entre a consulta e todos os vetores do banco.
2. Ordena todos os vetores por essa pontuação.
3. Retorna os *k* com maior pontuação.

O resultado é exato, mas é pesado e lento. Só faz sentido com poucos dados. Para bases grandes, usa-se **ANN** (*approximate nearest neighbors*), que troca um pouco de precisão por muita velocidade.

Os bancos vetoriais organizam os vetores em compartimentos, árvores ou grafos, e cada algoritmo usa uma heurística diferente para manter vetores parecidos perto uns dos outros. Os vetores também podem ser quantizados (menos precisão) ou esparsos, o que deixa o cálculo mais leve. A Zilliz tem uma [série muito boa](https://zilliz.com/learn/vector-index) sobre o assunto. Alguns algoritmos importantes:

- **LSH** (*locality-sensitive hashing*): coloca vetores parecidos no mesmo "balde" usando hash, trocando um pouco de precisão por eficiência. Funciona com mais do que vetores e está no FAISS e no Annoy.
- **[HNSW](https://github.com/nmslib/hnswlib)** (*hierarchical navigable small world*): monta um grafo em várias camadas, onde os nós são vetores e as arestas ligam vetores parecidos. A busca percorre as arestas. Está no FAISS e no Milvus.
- **Quantização de produto** (*product quantization*): quebra cada vetor em subvetores e cria uma representação menor e mais simples, o que deixa o cálculo de distância bem mais rápido. É peça central do FAISS e suportada por quase todas as bibliotecas de busca vetorial.
- **IVF** (*inverted file index*): usa K-means para agrupar vetores parecidos. É comum configurar os clusters para ter entre 100 e 10.000 vetores cada. Na consulta, o IVF acha os centroides mais próximos e usa os vetores desses clusters como candidatos. Junto com a quantização de produto, forma a base do FAISS.
- **[Annoy](https://github.com/spotify/annoy)** (*approximate nearest neighbors oh yeah*): usa várias árvores binárias, cada uma dividindo os vetores com cortes aleatórios. Na busca, percorre as árvores para juntar candidatos. Foi aberto pelo Spotify.

## Termos ou embeddings?

As duas abordagens são maduras e fáceis de começar a usar. Cada uma tem seus prós e contras.

A **busca por termos** é bem mais rápida, tanto para indexar quanto para consultar. Extrair termos é mais barato do que gerar embeddings, e achar os documentos de um termo custa menos que uma busca de vizinhos mais próximos. Ela também funciona bem sem ajuste: Elasticsearch e BM25 sustentam muitos sistemas de busca. Por outro lado, tem poucos pontos para ajustar e melhorar.

A **busca por embeddings** pode ser melhorada com o tempo e superar a busca por termos. Dá para ajustar o modelo de embedding e o recuperador, separados ou junto com o modelo generativo. O problema é que, ao virar embedding, palavras-chave específicas podem se perder, como um código de erro `EADDRNOTAVAIL (99)` ou um nome de produto. Combinar as duas abordagens resolve isso, e é o assunto do próximo artigo.

| | Baseada em termos | Baseada em embeddings |
| --- | --- | --- |
| Velocidade de consulta | Muito mais rápida | Mais lenta (gera embedding e faz busca vetorial) |
| Desempenho | Bom de início, difícil de melhorar. Pode trazer documentos errados por ambiguidade | Pode ser melhorado com ajuste fino. Pode esconder termos específicos |
| Custo | Muito mais barata | Embeddings, armazenamento e busca vetorial custam caro |

### Como avaliar o recuperador

A qualidade do recuperador é medida pela qualidade do que ele traz. Duas métricas aparecem bastante nos frameworks de avaliação de RAG:

- **Precisão de contexto** (também chamada de relevância de contexto): de tudo que foi recuperado, qual porcentagem é relevante?
- **Revocação de contexto** (*context recall*): de tudo que é relevante, qual porcentagem foi recuperada?

Para calcular, você monta um conjunto de avaliação com consultas de teste e documentos, e marca cada documento como relevante ou não para cada consulta. Essa marcação pode ser feita por pessoas ou por um juiz de IA.

A revocação é mais trabalhosa, porque exige marcar a relevância de **todos** os documentos do banco para cada consulta. A precisão é mais simples: basta comparar os documentos recuperados com a consulta, o que um juiz de IA consegue fazer.

Se a ordem importa (os mais relevantes devem vir primeiro), entram métricas como [NDCG](https://en.wikipedia.org/wiki/Discounted_cumulative_gain), [MAP](https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Mean_average_precision) e [MRR](https://en.wikipedia.org/wiki/Mean_reciprocal_rank).

Na recuperação semântica, os embeddings também precisam ser avaliados. Um embedding é bom quando documentos parecidos ficam próximos. Também dá para avaliar pelo desempenho em tarefas: o benchmark [MTEB](https://arxiv.org/abs/2210.07316) (Muennighoff et al., 2023) testa embeddings em recuperação, classificação, agrupamento e outras tarefas.

### Custo e latência

Vale a pena ir para a busca semântica? Depende de quanto custo e latência você aceita, principalmente na consulta.

Boa parte da latência de um RAG vem da geração da resposta, então o tempo de gerar o embedding da consulta e fazer a busca vetorial costuma ser pequeno perto do total. Mesmo assim, pode afetar a experiência.

O custo pesa mais. Gerar embeddings custa dinheiro, e isso piora quando os dados mudam com frequência e precisam ser reprocessados. Pense em gerar embeddings para 100 milhões de documentos todo dia. Dependendo do banco vetorial, armazenamento e consultas também saem caros. Não é raro o gasto com banco vetorial chegar a um quinto ou até metade do gasto com APIs de modelo.

### Indexação versus consulta

Existe uma troca entre indexar e consultar. Quanto mais detalhado o índice, mais precisa a busca, mas a indexação fica mais lenta e usa mais memória. É como montar uma base de potenciais clientes: com nome, empresa, e-mail, telefone e interesses fica mais fácil achar as pessoas certas, mas dá mais trabalho montar e ocupa mais espaço.

Um índice detalhado como o **HNSW** tem alta precisão e consulta rápida, mas demora e consome memória para ser criado. Um índice mais simples como o **LSH** é rápido de criar e leve, mas as consultas ficam mais lentas e menos precisas.

O [ANN-Benchmarks](https://ann-benchmarks.com/index.html) compara algoritmos ANN em vários conjuntos de dados usando quatro métricas:

- **Revocação:** fração dos vizinhos mais próximos que o algoritmo encontrou.
- **Consultas por segundo (QPS):** quantas consultas ele aguenta por segundo, importante para alto tráfego.
- **Tempo de construção:** quanto tempo leva para criar o índice, importante se os dados mudam muito.
- **Tamanho do índice:** quanto espaço ele ocupa, importante para escalar.

No fim, um RAG precisa ser avaliado por partes e de ponta a ponta:

- A qualidade da recuperação.
- O resultado final do RAG.
- Os embeddings, quando a recuperação é semântica.

No próximo artigo entram as técnicas para melhorar essa recuperação: busca híbrida, fragmentação, reranking, reescrita de consulta e RAG com imagens e tabelas.

## Referência

Este artigo faz parte dos meus estudos sobre engenharia de IA, baseados no livro *AI Engineering: Building Applications with Foundation Models*, de Chip Huyen (O'Reilly, 2025). As imagens usadas aqui também vêm do livro.
