RAG do Zero em 2026: Construa Seu Sistema de Busca Inteligente em Python com LangChain e ChromaDB
Enquanto você lia esta frase, algum sistema de IA em algum lugar provavelmente alucinou uma resposta. O problema não é novo — mas a solução dominante em 2026 tem nome: RAG.
Não é hype. O mercado global de RAG saiu de US$ 1,94 bilhão em 2025 e deve chegar a US$ 9,86 bilhões até 2030, crescendo 38,4% ao ano (MarketsandMarkets). Mais importante: 73% das implantações empresariais de IA em 2026 usam RAG ou arquitetura híbrida (Precision AI Academy).
Mas tem um porém. A maioria dos tutoriais por aí ensina o "Naive RAG" — que, segundo o RAG Architecture Guide de 2026, falha na recuperação em aproximadamente 40% dos casos. O modelo responde com confiança, mas baseado nos documentos errados.
Neste tutorial, você vai aprender a construir um sistema RAG completo do zero — não o raso, mas o que realmente funciona. Vamos passar por indexação, chunking inteligente, embeddings, busca semântica, avaliação com RAGAS e um upgrade para Advanced RAG com reranking. Tudo em Python, com LangChain e ChromaDB.
No final, tem uma versão que roda 100% gratuita com Ollama. Sem API key, sem cartão de crédito.
O Problema Que RAG Resolve
Modelos de linguagem são incrivelmente bons em gerar texto. Mas eles têm um problema grave: não sabem o que não sabem. Pergunte sobre documentos internos da sua empresa, um relatório de 2025 ou um artigo científico recente — e o modelo vai inventar uma resposta convincente.
RAG resolve isso com uma ideia simples: antes de responder, o sistema busca os documentos relevantes para aquela pergunta, e só então gera a resposta com base neles.
"RAG turns a general-purpose language model into a domain expert on your specific documents — without retraining anything." — Precision AI Academy
O resultado é expressivo: redução de 85% na taxa de alucinação quando implementado corretamente, contra prompting puro (Precision AI Academy). Empresas que deployam RAG reportam 30-70% de ganho de eficiência em workflows intensivos em conhecimento (Techment).
Como Funciona: A Arquitetura em 2 Fases
Um sistema RAG tem duas fases distintas. A primeira roda offline, uma vez. A segunda roda online, a cada pergunta do usuário.
| Fase | O que acontece | Quando roda |
|---|---|---|
| Indexação | Documentos são carregados, divididos em chunks, convertidos em embeddings e armazenados no banco vetorial | Offline (processamento único) |
| Recuperação | A pergunta do usuário é convertida em embedding e usada para buscar os chunks mais similares | Online (a cada consulta) |
| Geração | Os chunks recuperados são injetados no prompt como contexto, e o LLM gera a resposta final | Online (a cada consulta) |
Pense em RAG como uma biblioteca com dois funcionários: um bibliotecário (retriever) que busca os livros certos nas estantes, e um assistente (LLM) que lê os livros e responde sua pergunta. Sozinho, o assistente inventaria tudo. Com o bibliotecário, ele só responde com base no que leu.
Setup do Projeto
Crie um diretório, isole as dependências e instale os pacotes:
mkdir rag-do-zero && cd rag-do-zero
python -m venv .venv
source .venv/bin/activate
# No Windows: .venv\Scripts\activate
pip install langchain langchain-community langchain-chroma chromadb pip install langchain-openai python-dotenv pip install ragas datasets
Coloque sua chave da OpenAI em um arquivo .env:
OPENAI_API_KEY=sua-chave-aqui
Sem chave? Pule para a seção "RAG Gratuito com Ollama" no final. O código é quase o mesmo.
Passo a Passo: Construindo o RAG
Vou dividir a implementação em 8 blocos de código. Cada um é auto-contido e explicado.
Passo 1: Carregar os documentos
Primeiro, crie uma pasta ./docs/ com alguns arquivos .txt de exemplo — pode ser documentação técnica, artigos, ou relatórios. Depois carregue tudo:
from langchain_community.document_loaders import DirectoryLoader, TextLoader
loader = DirectoryLoader( path="./docs/", glob="**/*.txt", loader_cls=TextLoader, ) documents = loader.load()
print(f"Documentos carregados: {len(documents)}")
Passo 2: Chunking inteligente
Dividir documentos em pedaços é a decisão mais subestimada do pipeline. Chunks grandes demais diluem a relevância da busca. Pequenos demais perdem contexto.
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, # ~250 tokens chunk_overlap=200, # sobreposição para não cortar ideias no meio separators=["\n\n", "\n", ". ", " ", ""], ) chunks = text_splitter.split_documents(documents)
print(f"Total de chunks: {len(chunks)}")
O chunk_overlap de 200 caracteres garante que contextos importantes não sejam cortados entre dois chunks. É um detalhe pequeno que faz diferença grande.
"Naive RAG pipelines fail at retrieval roughly 40% of the time, generating a confident answer grounded in the wrong documents." — JobsByCulture RAG Architecture Guide 2026
Passo 3: Criar embeddings
Cada chunk vira um vetor numérico — um embedding — que representa seu significado. Quanto mais próximo um embedding do outro, mais semelhante o conteúdo:
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
O modelo text-embedding-3-small da OpenAI custa centavos, tem 1536 dimensões e é o padrão da indústria em 2026.
Passo 4: Armazenar no ChromaDB
Com os embeddings prontos, populamos o banco vetorial. O ChromaDB é open-source, roda localmente e persiste os dados em disco:
from langchain_chroma import Chroma
vectorstore = Chroma.from_documents( documents=chunks, embedding=embeddings, persist_directory="./chroma_db", )
print("Banco vetorial salvo em ./chroma_db")
Passo 5: Configurar o retriever
O retriever busca os chunks mais relevantes para cada pergunta. Por padrão, a busca semântica top-k funciona bem:
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 4}
)
Isso retorna os 4 chunks mais similares à pergunta. Quatro é um bom ponto de partida — pouco para não poluir o contexto, suficiente para cobrir diferentes aspectos.
Passo 6: Montar a chain completa
Aqui juntamos recuperação + prompt + LLM em um pipeline só:
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnablePassthrough
template = """Você é um assistente especializado em responder com base APENAS no contexto fornecido. Se a resposta não estiver no contexto, diga que não sabe.
Contexto: {context}
Pergunta: {question}
Resposta:"""
prompt = ChatPromptTemplate.from_template(template) llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
def format_docs(docs): return "\n\n---\n\n".join(doc.page_content for doc in docs)
chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | prompt | llm )
Perceba o RunnablePassthrough(): a pergunta do usuário passa direto para o prompt, enquanto o retriever busca e formata o contexto.
Passo 7: Perguntar
A chain está pronta. Vamos testar:
pergunta = "O que é RAG e como ele reduz alucinações em modelos de linguagem?"
resposta = chain.invoke(pergunta)
print(resposta.content)
O fluxo é:
- Sua pergunta vira embedding e busca no ChromaDB
- Os 4 chunks mais similares são recuperados
- Eles viram o
{context}no template - O GPT-4o-mini gera a resposta com base apenas nesse contexto
Se o banco vetorial não tiver documentos relevantes, o modelo responde "não sei" — em vez de alucinar.
Passo 8: Avaliar com RAGAS
Construir o RAG é a parte fácil. Saber se ele funciona é o que separa amadores de profissionais. O RAGAS fornece métricas objetivas:
| Métrica | O que mede | Score ideal |
|---|---|---|
| Faithfulness | A resposta é fiel ao contexto recuperado? | > 0,85 |
| Answer Relevancy | A resposta responde de fato à pergunta? | > 0,80 |
| Context Precision | Os documentos recuperados são relevantes? | > 0,75 |
| Context Recall | O contexto cobre a informação necessária? | > 0,80 |
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy
from ragas.metrics import context_precision, context_recall
from datasets import Dataset
docs_recuperados = retriever.invoke(pergunta) dataset = Dataset.from_dict({ "question": [pergunta], "answer": [resposta.content], "contexts": [[doc.page_content for doc in docs_recuperados]], })
resultados = evaluate( dataset, metrics=[ faithfulness, answer_relevancy, context_precision, context_recall, ], )
print("Faithfulness:", resultados["faithfulness"]) print("Answer Relevancy:", resultados["answer_relevancy"]) print("Context Precision:", resultados["context_precision"]) print("Context Recall:", resultados["context_recall"])
Se o context_precision estiver baixo, o chunking ou a qualidade dos embeddings está ruim. Se o faithfulness for baixo, o LLM está ignorando o contexto — aumente a temperatura ou ajuste o prompt.
Upgrade: Advanced RAG com Re-ranking
O Naive RAG que construímos até aqui funciona. Mas os 40% de falha na recuperação são um risco real. A solução mais eficaz em 2026 é o re-ranking: buscar mais documentos do que o necessário e usar um modelo especializado para reordenar os mais relevantes.
O re-ranking melhora a qualidade das respostas em 15-30% nos benchmarks padrão de RAG (JobsByCulture).
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain_community.cross_encoders import HuggingFaceCrossEncoder
Modelo de re-ranking gratuito (roda local)
reranker_model = HuggingFaceCrossEncoder( model_name="BAAI/bge-reranker-v2-m3" )
compressor = CrossEncoderReranker( model=reranker_model, top_n=4, )
advanced_retriever = ContextualCompressionRetriever( base_compressor=compressor, base_retriever=vectorstore.as_retriever( search_kwargs={"k": 20} ), )
Chain atualizada com re-ranking
advanced_chain = ( { "context": advanced_retriever | format_docs, "question": RunnablePassthrough(), } | prompt | llm )
resposta_avancada = advanced_chain.invoke(pergunta) print(resposta_avancada.content)
A lógica: busca 20 chunks, passa pelo re-ranking (que é mais lento mas mais preciso), e seleciona os 4 melhores. O custo computacional extra vale cada centavo — especialmente em domínios técnicos onde precisão importa.
RAG Gratuito: Rodando Tudo com Ollama
Não quer pagar por API? O ecossistema open-source em 2026 está maduro. Com o Ollama, você roda embeddings e LLM localmente — 100% gratuito, 100% offline:
ollama pull nomic-embed-text
ollama pull llama3.2:3b
O código muda muito pouco:
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.llms import Ollama
Embeddings locais
embeddings_local = OllamaEmbeddings(model="nomic-embed-text")
LLM local
llm_local = Ollama(model="llama3.2:3b", temperature=0)
Pipeline idêntico, só troca o provider
vectorstore_local = Chroma.from_documents( documents=chunks, embedding=embeddings_local, persist_directory="./chroma_db_local", )
retriever_local = vectorstore_local.as_retriever(search_kwargs={"k": 4})
chain_local = ( {"context": retriever_local | format_docs, "question": RunnablePassthrough()} | prompt | llm_local )
print(chain_local.invoke("O que é RAG?").content)
Mesma arquitetura. Zero custo de API. Perfeito para prototipagem, dados sensíveis, ou simplesmente para aprender sem gastar nada.
Comparativo: Estratégias de Embedding
| Modelo | Dim. | Custo | Precisão (MTEB) | Offline? |
|---|---|---|---|---|
| text-embedding-3-small | 1536 | $$ baixo | 62,3% | ❌ |
| text-embedding-3-large | 3072 | $$ médio | 64,6% | ❌ |
| nomic-embed-text | 768 | Grátis | 59,7% | ✅ |
| bge-large-en-v1.5 | 1024 | Grátis | 63,7% | ✅ |
Para produção, o text-embedding-3-small é o melhor custo-benefício. Para prototipação ou dados sensíveis, nomic-embed-text roda de graça na sua máquina.
Próximos Passos
RAG não é um projeto que se faz uma vez e pronto. O que separa uma implementação mediana de uma excelente é a iteração:
- Teste diferentes estratégias de chunking: 512 vs 1024 tokens, overlap de 10% vs 20%
- Experimente embeddings do seu domínio: modelos fine-tunados superam os genéricos
- Implemente feedback loop: usuários marcam respostas como úteis ou inúteis → dados para refinar
- Adicione Graph RAG: para perguntas que conectam múltiplos documentos
"RAG is still the dominant architecture for grounding LLMs with external knowledge in 2026 — but the landscape has fractured into multiple distinct patterns." — Starmorph Blog
O mercado de sistemas de gestão de conhecimento com IA atingiu US$ 11,24 bilhões em 2026, crescendo 46,7% ao ano (Virtual Assistant VA). RAG é a base de tudo isso. Saber construir, avaliar e iterar é uma habilidade que vai valer ouro nos próximos anos.
Agora você tem um sistema funcional, métricas para medir qualidade e um caminho claro de evolução. O código está na sua mão — é só rodar.
Quer ir além? No próximo tutorial, vamos explorar Graph RAG — quando a busca semântica não é suficiente e você precisa conectar entidades através de múltiplos documentos. É onde o RAG realmente fica interessante.
Artigos Relacionados
NeuralPulse
Blog profissional sobre Inteligencia Artificial. Exploramos tendencias, ferramentas, tutoriais e analises profundas sobre como a IA esta transformando negocios, tecnologia e o dia a dia.
Receba as novidades sobre IA
Junte-se a milhares de leitores que acompanham as ultimas tendencias em inteligencia artificial.
Artigos Relacionados
Automação de Licitações com IA: Guia Prático para Órgãos Públicos
Aprenda a usar IA gratuita para automatizar a análise de editais e propostas em licitações públicas com Python, dados abertos e modelos como Sabiá-4 e Gemini.
Function Calling na Prática: Tutorial Python para Chatbots com LLMs que Executam Ações em 2026
Aprenda a implementar function calling em Python com OpenAI, Anthropic Claude e Google Gemini. Tutorial completo com código para integrar APIs, bancos de dad...
Árvore de Decisão vs Random Forest vs XGBoost: Tutorial Prático de Machine Learning em 2026 (com Código Python e Dados Reais)
Comparação prática entre Árvore de Decisão, Random Forest e XGBoost para classificação em 2026, com implementação passo a passo em Python e análise de perfor...
Comentarios
Powered by Disqus
Para ativar os comentarios, configure seu shortname do Disqus no componente.
<div id="disqus_thread"></div>