Resposta rápida (agosto de 2026): Um pipeline RAG recupera trechos relevantes dos seus próprios documentos e os injeta em um prompt de LLM antes da geração, fazendo o modelo responder com base nos seus dados em vez da memória de treinamento. São quatro componentes necessários: um carregador de documentos, um divisor de texto, um modelo de embedding e um banco de vetores. O ponto de partida mais rápido é pip install langchain langchain-openai langchain-chroma chromadb, uma chave de API da OpenAI e uma tarde livre. O text-embedding-3-small da OpenAI custa $0.02 por milhão de tokens na API padrão, então um corpus de 50,000 chunks normalmente sai por menos de $0.50 para indexar do zero.
Última verificação: 17 de agosto de 2026, em comparação com a documentação oficial e páginas de preços.
Como Funciona um Pipeline RAG
RAG é a sigla para retrieval-augmented generation (geração aumentada por recuperação). O mecanismo: você converte seus documentos em embeddings vetoriais com antecedência, armazena-os em um banco de vetores e, na hora da consulta, embeda a pergunta do usuário com o mesmo modelo e recupera os chunks semanticamente mais similares. Esses chunks entram no prompt do LLM junto com a pergunta.
Quatro etapas distintas rodam em cada consulta:
Indexação (executa uma vez): carrega documentos, divide em chunks, embeda cada chunk, grava os vetores no banco.
Recuperação: embeda a consulta recebida, executa uma busca por vizinhos mais próximos, retorna os top-k chunks.
Augmentação: insere esses chunks em um template de prompt ao lado da pergunta do usuário.
Geração: envia o prompt preenchido ao LLM, que responde usando o contexto recuperado como base.
A propriedade essencial que o RAG oferece: o LLM só pode citar o que a recuperação trouxe. Alucinações não são eliminadas, mas reduzidas de forma significativa, pois o modelo tem texto concreto para consultar. Se a etapa de recuperação não encontrar o chunk relevante, o modelo fica sem referência, portanto a qualidade da recuperação é o principal ajuste a otimizar.
Escolha Sua Stack
Dois frameworks Python dominam os workloads de RAG em produção: LangChain (v1.3.15 em agosto de 2026) e LlamaIndex (llama-index-core v0.14.23 em junho de 2026). Ambos suportam os mesmos bancos de vetores e modelos de embedding, então migrar não é catastrófico, mas os modelos de programação são diferentes.
O modelo de composição do LangChain, o LCEL (LangChain Expression Language), conecta as etapas com o operador de pipe |. Isso dá controle explícito sobre cada fase, o que importa quando você quer adicionar reranking, roteamento ou loops agênticos. Se você planeja criar agentes de IA junto ao seu pipeline RAG, o LangChain integra esse trabalho de forma mais natural.
O LlamaIndex foi criado especificamente para Q&A de documentos com grande volume de dados. A chamada VectorStoreIndex.from_documents() cuida de carregamento, chunking, embedding e indexação em uma linha. Menos partes móveis para gerenciar, mas também menos ganchos para customizar cada etapa. O padrão do framework é o text-embedding-ada-002 da OpenAI para embeddings; é preciso sobrescrever isso explicitamente para usar um modelo mais recente.
Para o banco de vetores, sua escolha determina tanto a carga operacional quanto o custo em escala:
| Banco de Vetores | Nível Gratuito | Preço Inicial Pago | Opção Self-Host | Melhor Para |
|---|---|---|---|---|
| Chroma | Gratuito (open-source, roda em processo) | Chroma Cloud: $5 credits, depois por uso | Sim (Apache 2.0) | Dev local; protótipos em processo |
| Qdrant | Gratuito para sempre: 0.5 vCPU, 1 GB RAM, 4 GB de disco | Standard: cobrança por hora com base no uso | Sim (Apache 2.0) | Self-hosting em produção; busca filtrada |
| Pinecone | Starter: 2 GB de armazenamento, 5 índices serverless | Builder: $20/month, taxa fixa | Não (apenas nuvem gerenciada) | Deployments gerenciados sem operações |
| pgvector | Gratuito (extensão do PostgreSQL) | Custo do seu hosting Postgres atual | Sim | Times que já usam Postgres |
Chroma é o padrão certo para desenvolvimento local. O nível gratuito do Qdrant na nuvem é bem provisionado para um protótipo que precisa persistir entre reinicializações. Migre para Pinecone ou um cluster Qdrant em produção quando precisar de SLAs de disponibilidade.
Instale e Configure seu Ambiente
LangChain com Chroma:
pip install langchain langchain-openai langchain-text-splitters langchain-chroma chromadb
Configure sua chave de API:
export OPENAI_API_KEY="sk-..."
LlamaIndex com o armazenamento padrão em memória:
pip install llama-index-core llama-index-llms-openai llama-index-embeddings-openai
LlamaIndex 0.10 e versões posteriores usam uma estrutura de pacotes modular. Instale apenas as integrações que você precisa. Para Qdrant como banco de vetores, adicione llama-index-vector-stores-qdrant. Para Pinecone, adicione llama-index-vector-stores-pinecone. Ambos os frameworks leem OPENAI_API_KEY do ambiente automaticamente.
Coloque seus documentos em uma pasta chamada data/ antes de avançar para a próxima etapa. Ambos os frameworks lidam com PDFs, texto simples, Markdown e HTML sem configuração adicional.
Divida Seus Documentos em Chunks
Os divisores de texto dividem os documentos em partes recuperáveis. O tamanho do chunk tem tanta influência na qualidade da recuperação quanto a escolha do modelo de embedding, então defina-o deliberadamente.
O ponto de partida atual é 512 tokens por chunk com 10% de sobreposição (cerca de 50 tokens para um chunk de 512). Chunks menores proporcionam recuperação mais precisa para perguntas factuais. Chunks maiores dão ao modelo mais contexto por trecho recuperado, o que ajuda quando as respostas exigem raciocínio com múltiplos parágrafos.
A divisão recursiva por caractere é o padrão mais confiável. Ela tenta quebrar nos limites de parágrafo primeiro, depois frases, depois palavras, preservando unidades semânticas sempre que possível.
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import DirectoryLoader
loader = DirectoryLoader("data/")
documents = loader.load()
splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=50,
)
chunks = splitter.split_documents(documents)
print(f"Created {len(chunks)} chunks")
Um aviso: sobreposição além de certo limiar aumenta o custo de armazenamento e embedding sem melhora mensurável na recuperação na maioria dos benchmarks. Se o recall estiver baixo, experimente chunks menores ou um modelo de embedding melhor antes de aumentar a sobreposição.
Embeda e Indexe
O embedding converte cada chunk em um vetor de números de ponto flutuante que codifica o significado semântico. Você executa essa etapa uma vez no momento da indexação; o modelo idêntico roda novamente na hora da consulta sobre a pergunta do usuário.
Os modelos de embedding atuais da OpenAI, verificados na página oficial de preços:
- text-embedding-3-small: $0.02 por milhão de tokens, 1,536 dimensões, limite de entrada de 8,192 tokens
- text-embedding-3-large: $0.13 por milhão de tokens, 3,072 dimensões, limite de entrada de 8,192 tokens
O text-embedding-3-small é o padrão correto para a maioria dos workloads de RAG. O modelo large marca 64.6% nos benchmarks MTEB contra 62.3% do small, um ganho modesto de qualidade a um prêmio de 6.5x no preço. Comece com o small; compare os dois com suas consultas reais de recuperação antes de pagar pelo large.
Indexação com LangChain e Chroma:
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db",
)
print(f"Indexed {vectorstore._collection.count()} vectors")
Com LlamaIndex, sobrescreva o modelo de embedding padrão antes de construir o índice:
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.embeddings.openai import OpenAIEmbedding
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
documents = SimpleDirectoryReader("data").load_data()
index = VectorStoreIndex.from_documents(documents)
Sem o override de Settings.embed_model, o LlamaIndex usa como padrão o text-embedding-ada-002 ($0.10/M tokens), que é mais antigo e superado pelo text-embedding-3-small a um quinto do custo.
Consulta: Recupere e Gere
Na hora da consulta, o pipeline embeda a pergunta, recupera os top-k chunks e os passa para o LLM. O parâmetro k é o ajuste de maior impacto nessa etapa.
Padrão LangChain LCEL:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
prompt = ChatPromptTemplate.from_template(
"Answer using only the context below. "
"If the context does not contain the answer, say so.\n\n"
"Context: {context}\n\nQuestion: {question}"
)
llm = ChatOpenAI(model="gpt-4o-mini")
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
answer = chain.invoke("What does the refund policy cover?")
print(answer)
Padrão LlamaIndex:
query_engine = index.as_query_engine(similarity_top_k=4)
response = query_engine.query("What does the refund policy cover?")
print(response)
Comece com k=4. Aumente para 6 ou 8 se o modelo frequentemente disser que não tem contexto suficiente. Cada chunk adicional recuperado consome tokens da janela de contexto e aumenta o custo de inferência, então há um tradeoff real a gerenciar. A instrução no prompt "if the context does not contain the answer, say so" reduz significativamente as alucinações confiantes em produção.
FAQ
O modelo de embedding importa mais do que a estratégia de chunking?
Um estudo revisado por pares publicado no NAACL 2025 (Vectara) constatou que as decisões de chunking têm tanta influência na qualidade da recuperação quanto a escolha do modelo de embedding. Defina o tamanho do chunk deliberadamente antes de migrar para um modelo mais caro.
Posso rodar tudo localmente sem chamadas a APIs externas?
Sim. Substitua a OpenAI por um modelo local via Ollama para inferência de LLM e instale llama-index-embeddings-huggingface ou um pacote similar para embeddings locais. O Chroma roda totalmente em processo, sem chamadas de rede. Espere menor throughput e, em geral, qualidade de respostas inferior em comparação aos modelos hospedados.
O que acontece quando um documento ultrapassa o limite de 8,192 tokens do modelo de embedding?
O documento precisa ser dividido em chunks antes do embedding. Tanto os divisores de texto do LangChain quanto os parsers de nós do LlamaIndex fazem isso automaticamente. Mantenha o tamanho do chunk bem abaixo de 8,000 tokens; o tokenizador do modelo usa um vocabulário fixo e suas estimativas por contagem de caracteres podem ser ligeiramente imprecisas.
O pgvector é bom o suficiente para substituir um banco de vetores dedicado?
Para corpora menores com um índice HNSW, o pgvector tem desempenho comparável aos bancos de vetores dedicados e elimina um serviço a operar. Em escalas maiores ou quando você precisa de desempenho avançado em busca filtrada, Qdrant e Pinecone oferecem mais opções de ajuste.
Como atualizo o índice quando meus documentos mudam?
A maioria dos bancos de vetores suporta operações de upsert identificadas por um ID de documento. Atribua IDs estáveis (um hash do caminho do arquivo mais a posição do chunk funciona), depois delete e faça upsert apenas dos chunks do documento alterado. Pinecone e Qdrant suportam esse padrão nativamente. Evite reindexação completa a cada atualização; com 50,000 chunks, isso custa $0.50 toda vez.
Mais sobre padrões agênticos que estendem sistemas RAG no guia de configuração de agentes do AI Weekly. Receba o AI Weekly grátis, 3 edições por semana, lido por 40,000+ profissionais de IA.