← Resources
TUTORIAL · 2026-02-12
Construa um pipeline RAG em produção sem LangChain (2026)
Você consegue lançar um pipeline RAG em nível de produção em poucas centenas de linhas de código compondo SDKs de provedores, pgvector e um reranker diretamente. Pule as abstrações do LangChain até ter uma necessidade concreta que elas realmente resolvam.
Por que times estão desempacotando o LangChain em 2026
Em 2026, remover LangChain de produção virou um padrão de engenharia reconhecível, com postmortems públicos de times que antes o evangelizavam. As queixas são consistentes: abstrações em camadas que escondem o que de fato é enviado ao modelo, breaking changes frequentes entre versões minor e sessões de debug que viram expedições de espeleologia por classes wrapper.
A mudança subjacente é que os SDKs de provedor ficaram bons. Os SDKs da OpenAI, Anthropic e Google hoje trazem streaming, structured outputs, tool calls e batching de primeira classe. Voyage, Cohere e Jina expõem endpoints REST limpos para embeddings e reranking. Postgres com pgvector dá conta de busca ANN até aproximadamente 10M de vetores sem um banco vetorial dedicado.
Para a maioria dos workloads de RAG, o framework que você queria em 2023 hoje são quatro chamadas de função e uma query SQL. O default razoável em 2026 é começar com SDKs crus, adicionar uma abstração fina de pipeline quando sentir dor real e tratar frameworks pesados como opt-in.
Os cinco estágios que todo pipeline RAG precisa
Todo sistema RAG em produção, independente de framework, se decompõe nos mesmos cinco estágios. Nomeá-los explicitamente torna o código mais fácil de testar e substituir por partes.
- Ingest: carregar documentos de origem, normalizar encoding, remover boilerplate.
- Chunk: dividir em unidades de retrieval com IDs estáveis e metadados de origem.
- Embed e index: codificar chunks em um vector store, junto com um índice lexical para busca híbrida.
- Retrieve e rerank: puxar um conjunto amplo de candidatos e estreitar com um reranker cross-encoder.
- Generate e cite: montar um prompt com contexto recuperado e retornar respostas com atribuição de fonte.
Mantenha cada estágio como uma função pura com inputs e outputs tipados. O estágio de retrieval não deve saber qual LLM vai gerar; o de generation não deve saber qual modelo de embedding foi usado. Essa separação é o que frameworks prometem e raramente entregam, porque acoplam estágios através de objetos chain opacos. Escrever na mão leva uma tarde e remove uma categoria de risco de upgrade.
Estratégias de chunking: semântico, recursivo e agentic
Chunking é onde a maior parte da qualidade RAG é ganha ou perdida. Três padrões dominam em 2026.
Divisão recursiva por caracteres em uma hierarquia de separadores (parágrafos, frases, depois caracteres) é o baseline. É rápido, determinístico e bom o suficiente para prosa. Chunking semântico embeda candidatos a split e mescla chunks adjacentes cujos embeddings são próximos, produzindo unidades topicamente coerentes a um custo de ingest mais alto. Chunking agentic pede a um LLM pequeno para propor pontos de divisão em documentos estruturados como contratos ou transcrições, onde cabeçalhos e fronteiras de turno importam mais do que contagem de caracteres.
def recursive_chunk(text, max_chars=1200, overlap=150):
seps = ["\n\n", "\n", ". ", " "]
def split(s, depth=0):
if len(s) <= max_chars or depth == len(seps):
return [s]
parts, sep = [], seps[depth]
for p in s.split(sep):
parts.extend(split(p, depth + 1))
return parts
raw = split(text)
return [raw[i] + raw[i+1][:overlap] for i in range(len(raw)-1)] + [raw[-1]]
Comece pelo recursivo, meça e gradue para o semântico só nas classes de documento em que a avaliação mostrar que vale a pena.
Embeddings e rerankers: Voyage, BGE e Cohere
O cenário de 2026 para retrievers é mais claro do que era um ano atrás. Voyage, agora parte da MongoDB, entrega voyage-3-large como um forte modelo dense de uso geral e lançou a família voyage-4 no início de 2026, com uma variante mixture-of-experts mirando o topo da RTEB leaderboard. embed-v4 da Cohere é o outro favorito de produção. Para self-hosting open-weight, o bge-m3 do BAAI segue como default: um único modelo suportando retrieval dense, sparse e multi-vector em mais de 100 idiomas, com contexto de 8192 tokens.
Para reranking, o rerank-v3.5 da Cohere é o cavalo de batalha: um modelo multilíngue, chunks de 4096 tokens e cerca de 80-150 ms de latência p50 em payloads típicos. O voyage rerank-2 é competitivo e integra de forma limpa se você já usa embeddings Voyage.
A regra prática: escolha um embedder dense, um reranker e congele o par atrás de uma interface. Trocar depois custa um reindex, não uma reescrita.
Conectando retrieval, generation e citações
Com pgvector você obtém busca híbrida e citações em SQL direto. Armazene chunks com seu document ID, embedding e um tsvector para recall lexical. Recupere um conjunto amplo de candidatos, faça rerank e passe os top N para o LLM com IDs de fonte explícitos que o modelo é instruído a citar.
import psycopg, voyageai, cohere
vo, co = voyageai.Client(), cohere.Client()
def retrieve(query, k=40, top_n=8):
qvec = vo.embed([query], model="voyage-3-large").embeddings[0]
with psycopg.connect(DSN) as conn:
rows = conn.execute(
"SELECT id, doc_id, text FROM chunks ORDER BY embedding <=> %s LIMIT %s",
(qvec, k)).fetchall()
docs = [r[2] for r in rows]
ranked = co.rerank(model="rerank-v3.5", query=query, documents=docs, top_n=top_n)
return [rows[r.index] for r in ranked.results]
```
Para pgvector, use por padrão um índice HNSW com m=16 e ef_construction=64, adicione um prefiltro de tenant ou recência para que o scan ANN comece estreito e sempre pareie `ORDER BY embedding <=> $1` com um `LIMIT`. Passe os chunks recuperados ao LLM com seus IDs e instrua o modelo a emitir marcadores de citação; resolva esses marcadores de volta para URLs de origem em um passo de pós-processamento.
Avaliação: hit rate, MRR e faithfulness
Um pipeline RAG sem um harness de avaliação é um chute. Construa o harness antes de afinar qualquer coisa. O kit mínimo é um conjunto rotulado de queries com 100 a 500 exemplos cobrindo os tipos de pergunta que você de fato espera, mais três métricas.
Hit rate em K responde se o chunk correto entrou no conjunto de candidatos, o que isola a qualidade do retrieval. Mean reciprocal rank captura quão alto o chunk certo ranqueou, que é exatamente o que o reranker é pago para melhorar. Faithfulness, pontuada por um juiz LLM com prompt para comparar cada afirmação gerada contra os chunks citados, captura se o modelo alucinou além do contexto.
Rode o harness em toda mudança: um novo tamanho de chunk, um embedder diferente, uma edição de prompt. Plote as três métricas no mesmo dashboard ao longo do tempo. Quando uma mudança melhora MRR mas afunda faithfulness, o reranker está trazendo distratores e o prompt de generation precisa de guardrails, não de mais tuning de retrieval.
Quando graduar para um orquestrador gerenciado
Pipelines feitos à mão se mantêm sustentáveis enquanto um time é dono deles e a contagem de estágios é pequena. O ponto em que um orquestrador gerenciado compensa é quando não-engenheiros precisam ajustar retrieval, quando você roda muitos pipelines em paralelo para diferentes classes de documento ou quando quer configurações versionadas e roteamento A/B sem redeploy.
Nesse ponto, a escolha é entre frameworks pesados como LlamaIndex ou Haystack e plataformas configuration-driven que expõem estágios de retrieval como unidades declarativas. osStudio, o editor de orquestração no-code do osFoundry, toma a segunda abordagem: os cinco estágios acima são objetos de configuração de primeira classe com embeddings e reranking Voyage gerenciados atrás de um único proxy, então você mantém BYOK do lado do LLM e evita lock-in de framework do lado do retrieval.
A pergunta útil não é framework versus sem framework. É se a configuração do seu pipeline merece ser código, configuração ou UI, e essa resposta muda conforme o time cresce.
Frequently asked questions
- Eu realmente preciso de um banco vetorial para RAG?
- Provavelmente não até cruzar vários milhões de vetores. Postgres com pgvector dá conta de até aproximadamente 10 milhões de vetores confortavelmente com um índice HNSW, busca híbrida via tsvector e filtros SQL padrão para tenancy e recência. Você herda backups, replicação e controle de acesso do banco que já opera. Bancos vetoriais dedicados como Qdrant, Milvus ou Weaviate passam a valer seu custo operacional quando você precisa de índices shardados em escala de bilhões, filtragem especializada em QPS muito alto ou features como multi-vector retrieval que pgvector ainda não iguala. Comece com pgvector e migre só quando um gargalo medido forçar.
- Um reranker realmente vale a latência?
- Para a maioria dos workloads pesados em retrieval, sim. Um reranker cross-encoder como Cohere rerank-v3.5 ou Voyage rerank-2 normalmente adiciona 80 a 200 milissegundos no p50 sobre um conjunto de 40 a 100 chunks candidatos, e consistentemente eleva o mean reciprocal rank em 10 a 30 por cento sobre retrieval dense puro. Essa latência se esconde atrás da chamada de LLM seguinte, que costuma dominar o orçamento visível ao usuário. Pule o reranker só para fluxos críticos de latência tipo autocomplete abaixo de 200 milissegundos fim a fim, ou quando seu conjunto de candidatos já é pequeno o bastante para o ranking dense ser confiável.
- Como lidar com overlap de chunks sem inflar o storage?
- Use overlaps pequenos, de 10 a 15 por cento do tamanho do chunk, armazenados como offsets de caractere no documento de origem em vez de texto duplicado. Na hora do retrieval você pode opcionalmente buscar o chunk vizinho para expansão de contexto. Isso mantém o índice enxuto e evita pagar pelos mesmos tokens duas vezes durante a embedding. Se precisar de contexto mais rico para generation, um padrão parent-document funciona bem: indexe chunks pequenos para precisão de retrieval e depois resolva os hits de volta para sua seção parent antes de passar ao LLM. O lookup do parent é uma única query indexada e adiciona latência desprezível.
- Qual o jeito mais simples de avaliar qualidade de RAG?
- Monte um conjunto rotulado de 100 a 200 queries representativas com os IDs de chunk que deveriam ser recuperados. Compute hit rate em K e mean reciprocal rank só do estágio de retrieval, o que isola a qualidade do retriever do ruído de generation. Para faithfulness, use um juiz LLM com prompt para comparar cada afirmação gerada contra os chunks citados e pontuar como grounded versus não suportada. Rode os três números em toda mudança significativa e trate regressões como bloqueadoras. Esse setup de três métricas pega a maioria das regressões de RAG na prática e evita a armadilha de otimizar um número enquanto silenciosamente piora outro.
Sources