RAG (Retrieval-Augmented Generation): conectando IA aos seus dados
1. Fundamentos do RAG: O que é e por que usar?
1.1. Definição e motivação: superando as limitações de conhecimento dos LLMs
Modelos de linguagem de grande escala (LLMs) possuem um conhecimento limitado ao seu corte temporal de treinamento. Se um LLM foi treinado até 2023, ele não saberá de eventos de 2024. Além disso, LLMs não têm acesso a documentos internos de uma empresa, como manuais técnicos, políticas de RH ou bases de conhecimento proprietárias. O RAG (Retrieval-Augmented Generation) surge como solução: um sistema que primeiro recupera informações relevantes de uma base de dados externa e depois gera uma resposta baseada nesse contexto recuperado. Isso permite que a IA responda com precisão sobre dados atualizados e privados sem necessidade de re-treinar o modelo.
1.2. Arquitetura básica: recuperação (retrieval) + geração (generation)
A arquitetura RAG segue um pipeline de três etapas:
- Indexação: documentos são divididos em chunks, convertidos em embeddings e armazenados em um banco vetorial.
- Recuperação: a consulta do usuário é convertida em embedding e busca os chunks mais similares no banco vetorial.
- Geração: os chunks recuperados são inseridos no prompt do LLM como contexto adicional, e o modelo gera a resposta final.
Entrada do usuário: "Qual o prazo de garantia do produto X?"
↓
[1] Embedding da consulta
↓
[2] Busca no banco vetorial → top-3 chunks relevantes
↓
[3] Prompt: "Contexto: [chunk1] [chunk2] [chunk3] \n Pergunta: ... \n Resposta:"
↓
Saída do LLM: "O prazo de garantia do produto X é de 12 meses."
1.3. Casos de uso prático: chatbots corporativos, assistentes de documentação e pesquisa acadêmica
- Chatbots corporativos: um assistente de RH que responde com base no manual do funcionário.
- Assistentes de documentação: sistema que responde dúvidas sobre APIs usando a documentação técnica oficial.
- Pesquisa acadêmica: ferramenta que resume artigos científicos relevantes para uma pergunta específica.
2. Componentes-chave de um sistema RAG
2.1. Indexação de dados: chunking, embedding e armazenamento em vector databases
O processo começa com a divisão dos documentos em chunks (pedaços) de tamanho controlado, tipicamente entre 256 e 1024 tokens. Cada chunk é convertido em um embedding (vetor numérico) usando modelos como text-embedding-ada-002 da OpenAI ou all-MiniLM-L6-v2 do SentenceTransformers. Esses vetores são armazenados em um vector database como Pinecone, Weaviate, Qdrant ou Chroma, que permite busca eficiente por similaridade.
Documento original: "A garantia do produto X cobre defeitos de fabricação por 12 meses.
A garantia do produto Y cobre por 24 meses."
Chunks:
- Chunk 1: "A garantia do produto X cobre defeitos de fabricação por 12 meses."
- Chunk 2: "A garantia do produto Y cobre por 24 meses."
Embeddings (vetores de 384 ou 1536 dimensões):
- Embedding_1: [0.12, -0.45, 0.78, ...]
- Embedding_2: [0.89, 0.23, -0.11, ...]
2.2. Mecanismos de recuperação: busca por similaridade semântica vs. busca lexical
- Busca semântica: usa embeddings para encontrar chunks com significado similar à consulta, mesmo sem palavras exatas.
- Busca lexical: usa correspondência de palavras-chave (como BM25) — rápida e precisa para termos específicos.
- Abordagem híbrida: combina ambas, atribuindo pesos e fazendo fusão dos resultados (ex: Reciprocal Rank Fusion).
2.3. Modelo de geração: integração com LLMs (locais ou via API) e contexto limitado
O LLM recebe um prompt que inclui os chunks recuperados como contexto. A maioria dos modelos tem limite de contexto (ex: 4K, 8K ou 128K tokens). É crucial que os chunks recuperados caibam nesse limite, priorizando os mais relevantes.
3. Fluxo de implementação passo a passo
3.1. Preparação dos dados: limpeza, divisão em chunks e criação de embeddings
from sentence_transformers import SentenceTransformer
import chromadb
# 1. Carregar modelo de embedding
modelo = SentenceTransformer('all-MiniLM-L6-v2')
# 2. Documentos de exemplo
documentos = [
"O produto X tem garantia de 12 meses contra defeitos de fabricação.",
"O produto Y possui garantia estendida de 24 meses.",
"Para acionar a garantia, entre em contato com o suporte pelo telefone 0800."
]
# 3. Criar chunks (aqui cada documento já é um chunk)
chunks = documentos
# 4. Gerar embeddings
embeddings = modelo.encode(chunks).tolist()
# 5. Armazenar no ChromaDB
cliente = chromadb.Client()
colecao = cliente.create_collection("garantias")
colecao.add(
documents=chunks,
embeddings=embeddings,
ids=["doc1", "doc2", "doc3"]
)
3.2. Configuração do pipeline de recuperação: query embedding, busca no índice e ranking
# 6. Consulta do usuário
consulta = "Qual a garantia do produto X?"
# 7. Embedding da consulta
embedding_consulta = modelo.encode([consulta]).tolist()
# 8. Busca no banco vetorial (top-2 chunks)
resultados = colecao.query(
query_embeddings=embedding_consulta,
n_results=2
)
print("Chunks recuperados:")
for doc in resultados['documents'][0]:
print(f"- {doc}")
3.3. Montagem do prompt final: template com contexto recuperado + instrução para o LLM
# 9. Montar prompt com contexto
contexto = "\n".join(resultados['documents'][0])
prompt = f"""Você é um assistente especializado em garantias de produtos.
Use APENAS as informações abaixo para responder.
Contexto:
{contexto}
Pergunta: {consulta}
Resposta:"""
# 10. Enviar para o LLM (exemplo com OpenAI)
import openai
resposta = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}]
)
print(resposta.choices[0].message.content)
# Saída esperada: "O produto X tem garantia de 12 meses contra defeitos de fabricação."
4. Estratégias avançadas de recuperação
4.1. Recuperação híbrida: combinando similaridade semântica e correspondência de palavras-chave
A fusão por ranking recíproco (RRF) combina resultados de busca semântica e lexical:
# Simulação de rankings
ranking_semantico = {"doc1": 1, "doc2": 2, "doc3": 3}
ranking_lexical = {"doc2": 1, "doc1": 2, "doc4": 3}
# RRF score = 1 / (k + posição), onde k=60
k = 60
scores = {}
for doc, pos in ranking_semantico.items():
scores[doc] = scores.get(doc, 0) + 1 / (k + pos)
for doc, pos in ranking_lexical.items():
scores[doc] = scores.get(doc, 0) + 1 / (k + pos)
# Ranking final ordenado por score
ranking_final = sorted(scores.items(), key=lambda x: x[1], reverse=True)
print(ranking_final)
# [('doc2', 0.0328), ('doc1', 0.0323), ('doc3', 0.0159), ('doc4', 0.0159)]
4.2. Técnicas de reranking: refinando resultados com modelos cross-encoder
Modelos cross-encoder como cross-encoder/ms-marco-MiniLM-L-6-v2 avaliam pares (consulta, chunk) e atribuem scores de relevância mais precisos que a similaridade de embeddings.
4.3. Recuperação iterativa e multi-hop: consultas encadeadas para perguntas complexas
Para perguntas que exigem múltiplos saltos de conhecimento, recupera-se informações em etapas:
Pergunta: "Quem fundou a empresa que criou o produto X?"
Etapa 1: "Qual empresa criou o produto X?" → "Empresa Y"
Etapa 2: "Quem fundou a Empresa Y?" → "João Silva"
5. Otimização e boas práticas para produção
5.1. Avaliação de qualidade: métricas de precisão, recall e relevância do contexto
Use métricas como:
- Precisão@k: proporção de chunks relevantes entre os k recuperados.
- Recall@k: proporção de chunks relevantes recuperados em relação ao total.
- Faithfulness: quão fiel a resposta gerada é ao contexto recuperado.
5.2. Gerenciamento de latência: caching de embeddings e paralelização de consultas
- Cache de embeddings de consultas frequentes em Redis.
- Paralelização da busca em múltiplos shards do banco vetorial.
- Uso de modelos de embedding mais leves para consultas em tempo real.
5.3. Atualização incremental: como lidar com dados dinâmicos e versionamento
Implemente pipelines de ingestão que adicionam novos chunks sem reindexar tudo. Use versionamento de coleções no banco vetorial para rollback rápido.
6. Desafios e limitações do RAG
6.1. Problemas de alucinação: quando o contexto recuperado é ignorado ou mal interpretado
LLMs podem ignorar o contexto e "alucinar" respostas. Mitigação: prompts que enfatizam "responda apenas com base no contexto fornecido" e validação pós-geração.
6.2. Ruído e irrelevância: como o excesso de chunks pode degradar a resposta
Muitos chunks no prompt podem confundir o modelo. Solução: limitar a 3-5 chunks e usar reranking para garantir alta relevância.
6.3. Segurança e privacidade: riscos de vazamento de dados sensíveis no pipeline
Dados sensíveis podem ser recuperados e expostos. Use:
- Filtragem de chunks contendo informações confidenciais.
- Controle de acesso baseado em roles (RBAC) no banco vetorial.
- Criptografia de embeddings em repouso e em trânsito.
7. Tendências e futuro do RAG
7.1. RAG agêntico: combinando com LangGraph e loops de decisão
Agentes que decidem quando recuperar, qual ferramenta usar e como encadear consultas, usando frameworks como LangGraph.
7.2. RAG multimodal: recuperação de imagens, áudio e vídeo junto com texto
Modelos como CLIP permitem recuperar imagens por similaridade semântica com texto. Sistemas RAG multimodais integram diferentes tipos de mídia.
7.3. RAG self-adaptive: sistemas que ajustam dinamicamente estratégias de chunking e busca
Sistemas que monitoram métricas de desempenho e ajustam automaticamente o tamanho dos chunks, o número de resultados e os pesos da busca híbrida.
Referências
- LangChain RAG Documentation — Guia oficial da LangChain para implementação de sistemas RAG com exemplos práticos em Python.
- Pinecone RAG Guide — Tutorial completo sobre RAG usando o banco vetorial Pinecone, incluindo chunking e embeddings.
- Hugging Face RAG Paper — Documentação oficial do modelo RAG da Hugging Face, com detalhes sobre a arquitetura original.
- ChromaDB Getting Started — Guia rápido para usar o ChromaDB como banco vetorial open-source em sistemas RAG.
- OpenAI Embeddings Guide — Documentação oficial da OpenAI sobre embeddings e como usá-los para busca semântica em RAG.
- SentenceTransformers Documentation — Biblioteca para gerar embeddings de frases, essencial para pipelines de recuperação em RAG.
- RAG vs Fine-Tuning Comparison — Artigo técnico da Databricks comparando RAG com fine-tuning para adaptação de LLMs a dados proprietários.