Generative AI

Como Criar um Pipeline RAG: Guia de Configuração Passo a Passo

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.