Trilha recomendada

Use este insight em tres movimentos

Leia o enquadramento, conecte-o a prova de implementacao e depois mantenha vivo o loop semanal de sinais para que esta pagina vire uma relacao mais longa com o site.

01 · Insight atual

Por Que RAG e um Problema de Engenharia de Dados (E Como Construir Pipelines de Retriev...

A maioria das falhas de RAG sao falhas de pipeline de dados. Aprenda a construir pipelines de retrieval para producao com pgvector, hybrid search e validacao de citacoes que realmente funcionam em escala.

Voce esta aqui

02 · Prova de implementacao

Pipeline RAG de Base de Conhecimento

Use o caso correspondente para sair do enquadramento estrategico e entrar em arquitetura e tradeoffs de entrega.

Ver a prova

03 · Valor recorrente

Receba o pacote semanal de sinais

Fique conectado a proxima mudanca de mercado e ao proximo padrao de entrega sem precisar procurar tudo manualmente.

Entrar no loop semanal
Por Que RAG e um Problema de Engenharia de Dados (E Como Construir Pipelines de Retriev...
Engenharia de Dados

Por Que RAG e um Problema de Engenharia de Dados (E Como Construir Pipelines de Retriev...

A maioria das falhas de RAG sao falhas de pipeline de dados. Aprenda a construir pipelines de retrieval para producao com pgvector, hybrid search e validacao de citacoes que realmente funcionam em escala.

2026-04-06 • 11 min

Por Que RAG e um Problema de Engenharia de Dados (E Como Construir Pipelines de Retrieval para Producao)

Falhas de RAG Sao Falhas de Dados

Toda semana, mais um time anuncia que sua implementacao de RAG esta "alucinando" ou "retornando resultados irrelevantes." Eles culpam o LLM. Tentam um modelo maior. Adicionam mais prompt engineering. Nada melhora.

O problema quase nunca e o modelo. E o pipeline de retrieval.

RAG (Retrieval-Augmented Generation) e fundamentalmente um problema de engenharia de dados disfarçado de problema de IA. A qualidade do seu sistema RAG e limitada pela qualidade do seu pipeline de ingestao, chunking, embedding, indexacao e retrieval. Acerte a engenharia de dados e ate um modelo modesto produz resultados excelentes. Erre e nem o GPT-5 te salva.

Construi um pipeline RAG completo para demonstrar esses principios. O codigo esta em rag-knowledge-base-pipeline. Este artigo percorre cada camada do pipeline e as decisoes de engenharia que determinam sucesso ou fracasso.

Arquitetura: Um Pipeline de Dados Que Alimenta um LLM

A arquitetura deveria parecer familiar para qualquer engenheiro de dados. E um pipeline ETL com um consumidor diferente:

[Sources]        [Ingestion]       [Processing]       [Indexing]        [Retrieval]
 PDF, HTML   -->  Extract    -->   Chunk + Clean  -->  Embed + Store -->  Hybrid Search
 Markdown        Parse             Enrich              pgvector          RRF Fusion
 APIs            Validate          Deduplicate         BM25 Index        Re-rank
    |               |                  |                  |                  |
    v               v                  v                  v                  v
                    [PostgreSQL + pgvector]

Repare que nao tem nenhum vector-database-as-a-service nesse diagrama. PostgreSQL com pgvector cuida tanto dos metadados relacionais quanto dos embeddings vetoriais. Mais sobre essa decisao adiante.

Estrategia de Chunking: Onde a Maioria dos Pipelines RAG Falha

Chunking e a decisao de maior impacto em um pipeline RAG, e e puramente uma preocupacao de engenharia de dados. O LLM nunca ve sua logica de chunking. Ele so ve as consequencias.

Por Que Chunking Ingenuos Falham

A abordagem mais comum e chunking de tamanho fixo: dividir texto em blocos de 512 tokens com algum overlap. E rapido de implementar e pessimo na pratica porque:

  • Divide sentencas no meio do pensamento, destruindo coerencia semantica
  • Separa contexto das afirmacoes que dependem dele
  • Cria chunks onde a primeira metade e sobre topico A e a segunda sobre topico B
  • Perde estrutura do documento (headers, secoes, listas)

Chunking Semanticamente Consciente

O pipeline implementa uma estrategia de chunking hierarquico que respeita a estrutura do documento:

def chunk_document(
    document: ParsedDocument,
    max_tokens: int = 512,
    overlap_tokens: int = 50,
) -> list[Chunk]:
    sections = split_by_structure(document)
    chunks = []
    for section in sections:
        if count_tokens(section.text) <= max_tokens:
            chunks.append(create_chunk(
                text=section.text,
                metadata=section.metadata,
            ))
        else:
            sub_chunks = split_by_sentences(
                section.text,
                max_tokens=max_tokens,
                overlap_tokens=overlap_tokens,
            )
            for sub in sub_chunks:
                sub.metadata.update(section.metadata)
                chunks.append(sub)
    return chunks

Os principios chave:

  1. Respeitar estrutura do documento primeiro. Dividir por headers, secoes e paragrafos antes de recorrer a divisao por sentencas.
  2. Preservar metadados. Cada chunk carrega seu documento de origem, hierarquia de secoes, numero da pagina e data de criacao. Esses metadados sao criticos para citacao e freshness.
  3. Divisao por limite de sentenca. Quando uma secao excede o limite de tokens, dividir nos limites de sentencas, nunca no meio.
  4. Overlap contextual. O overlap entre chunks inclui as ultimas 1-2 sentencas do chunk anterior, mantendo continuidade.

Enriquecimento de Chunks

Antes de gerar embeddings, cada chunk e enriquecido com informacao contextual que melhora o retrieval:

  • Titulo da secao prepended: Se um chunk e de uma secao intitulada "Politica de Devolucao," esse titulo e adicionado ao texto do chunk antes do embedding
  • Titulo do documento incluido: O titulo do documento fonte fornece contexto global
  • Extracao de entidades: Entidades chave (nomes de produtos, datas, numeros de politica) sao extraidas e armazenadas como metadados filtraveis

Esse enriquecimento significa que o embedding captura nao apenas o que o chunk diz, mas onde ele se encaixa no contexto mais amplo do documento.

pgvector vs Bancos de Dados Vetoriais Dedicados

A decisao arquitetural mais controversa neste pipeline e usar PostgreSQL com pgvector ao inves de um banco vetorial dedicado como Pinecone, Weaviate ou Qdrant.

O raciocinio e pragmatico:

Simplicidade operacional. Todo time ja roda PostgreSQL. Adicionar pgvector e instalar uma extensao, nao provisionar, monitorar, securizar e pagar por um novo servico. Suas estrategias existentes de backup, replicacao e failover simplesmente funcionam.

Consistencia transacional. Com pgvector, seus embeddings vetoriais e metadados relacionais vivem no mesmo banco. Quando voce atualiza um documento, pode atualizar seus chunks, embeddings e metadados em uma unica transacao. Bancos vetoriais dedicados exigem que voce coordene atualizacoes entre dois sistemas.

Performance de filtragem. Queries RAG quase sempre incluem filtros de metadados (por tipo de documento, range de data, permissoes de acesso). No PostgreSQL, sao clausulas WHERE padrao em colunas indexadas. Em bancos vetoriais dedicados, filtragem de metadados e adicionada depois e frequentemente limitada.

Checagem de escala na realidade. pgvector com indexacao HNSW lida com milhoes de vetores com tempo de query abaixo de 100ms. A menos que voce esteja construindo um motor de busca sobre bilhoes de documentos, pgvector e suficiente. A maioria dos deployments RAG empresariais tem milhares a poucos milhoes de chunks.

O tradeoff e que pgvector nao iguala o throughput bruto de bancos vetoriais construidos para proposito especifico em escala extrema. Mas para os 95% de deployments RAG que nao estao em escala extrema, a simplicidade operacional vale muito mais.

class VectorStore:
    def __init__(self, connection_pool: AsyncConnectionPool) -> None:
        self._pool = connection_pool

    async def upsert_chunks(
        self,
        chunks: list[EmbeddedChunk],
    ) -> int:
        async with self._pool.connection() as conn:
            async with conn.transaction():
                for chunk in chunks:
                    await conn.execute(
                        """
                        INSERT INTO chunks (
                            chunk_id, document_id, content,
                            embedding, metadata, updated_at
                        ) VALUES (%s, %s, %s, %s, %s, NOW())
                        ON CONFLICT (chunk_id)
                        DO UPDATE SET
                            content = EXCLUDED.content,
                            embedding = EXCLUDED.embedding,
                            metadata = EXCLUDED.metadata,
                            updated_at = NOW()
                        """,
                        (
                            chunk.chunk_id,
                            chunk.document_id,
                            chunk.content,
                            chunk.embedding,
                            Json(chunk.metadata),
                        ),
                    )
        return len(chunks)

Repare no padrao de upsert. Isso e idempotente by design: re-executar o pipeline com os mesmos documentos produz o mesmo resultado sem duplicatas. Pratica padrao de engenharia de dados.

Hybrid Search: Vector + Keyword com RRF

Busca vetorial pura tem uma fraqueza bem conhecida: ela tem dificuldade com matches exatos. Se um usuario pergunta "Qual e a politica HR-2024-047?" uma busca vetorial pode retornar chunks sobre politicas de HR em geral ao inves da politica especifica.

A solucao e hybrid search, combinando similaridade vetorial com matching por keyword (BM25) e fundindo os resultados usando Reciprocal Rank Fusion (RRF).

async def hybrid_search(
    query: str,
    query_embedding: list[float],
    top_k: int = 10,
    vector_weight: float = 0.6,
    keyword_weight: float = 0.4,
) -> list[SearchResult]:
    vector_results = await vector_search(
        query_embedding, top_k=top_k * 2
    )
    keyword_results = await keyword_search(
        query, top_k=top_k * 2
    )
    fused = reciprocal_rank_fusion(
        result_lists=[vector_results, keyword_results],
        weights=[vector_weight, keyword_weight],
        k=60,
    )
    return fused[:top_k]

RRF funciona convertendo posicoes no ranking em scores: score = weight / (k + rank). Isso normaliza entre os dois metodos de busca independente das escalas nativas de pontuacao.

PostgreSQL torna isso particularmente limpo porque ambos os tipos de busca vivem no mesmo banco. A busca vetorial usa o operador <=> do pgvector (distancia cosseno), e a busca por keyword usa o full-text search nativo do PostgreSQL com tsvector. Nenhum servico de busca externo necessario.

Ajuste Dinamico de Pesos

O pipeline inclui classificacao de queries que ajusta os pesos vector/keyword baseado nas caracteristicas da query:

  • Queries contendo identificadores, codigos ou frases exatas recebem peso maior de keyword (0.3/0.7)
  • Queries conceituais ou semanticas recebem peso maior de vetor (0.7/0.3)
  • Peso balanceado padrao (0.6/0.4) para queries ambiguas

Validacao de Citacoes: A Camada de Confianca

RAG sem citacao e so um chatbot que parece confiante. O pipeline implementa validacao de citacoes para garantir que cada afirmacao gerada pode ser rastreada ate um chunk fonte especifico.

A abordagem funciona em dois estagios:

  1. Atribuicao de chunks: O LLM e instruido a marcar cada afirmacao com o(s) chunk ID(s) de onde ela veio
  2. Validacao pos-geracao: Um passo de validacao verifica que cada chunk citado realmente suporta a afirmacao feita
def validate_citations(
    response: GeneratedResponse,
    retrieved_chunks: list[Chunk],
) -> ValidationReport:
    chunk_map = {c.chunk_id: c for c in retrieved_chunks}
    validations = []
    for citation in response.citations:
        chunk = chunk_map.get(citation.chunk_id)
        if chunk is None:
            validations.append(CitationCheck(
                status="INVALID",
                reason="Referenced chunk not in retrieval set",
            ))
            continue
        similarity = compute_similarity(
            citation.claim, chunk.content
        )
        validations.append(CitationCheck(
            status="VALID" if similarity > 0.75 else "WEAK",
            similarity=similarity,
            source_document=chunk.metadata["source"],
        ))
    return ValidationReport(checks=validations)

Citacoes marcadas como WEAK ou INVALID sao removidas da resposta ou sinalizadas para o usuario. Nao e perfeito, mas pega as alucinacoes mais graves onde o modelo fabrica uma fonte.

Freshness de Embeddings: O Problema de Manutencao Esquecido

Uma vez que seu pipeline RAG esta em producao, voce enfrenta um problema de manutencao que a maioria dos tutoriais ignora: freshness de embeddings.

Documentos mudam. Politicas sao atualizadas. Bases de conhecimento evoluem. Seus embeddings precisam se manter atuais. O pipeline implementa um workflow de deteccao de mudancas e re-embedding:

  1. Hash de conteudo: Cada documento e chunk tem um hash de conteudo. Quando o documento fonte muda, o hash muda.
  2. Re-embedding incremental: Apenas chunks cujo hash de conteudo difere da versao armazenada sao re-embedded. Isso evita o custo de re-embeddar todo seu corpus a cada atualizacao.
  3. Deteccao de stale: Um job agendado identifica chunks cujos documentos fonte nao foram re-crawled dentro de uma janela de freshness configuravel e os sinaliza para revisao.
  4. Historico de versoes: Versoes anteriores de chunks sao soft-deleted, mantendo uma trilha de auditoria de como a base de conhecimento evoluiu.

Isso e pensamento padrao de pipeline de dados aplicado a embeddings: atualizacoes idempotentes, deteccao de mudancas, processamento incremental e auditabilidade.

Performance: O Que Realmente Importa

Apos construir e testar este pipeline, aqui esta o que realmente move a agulha na qualidade de RAG, em ordem de impacto:

  1. Qualidade do chunking - Chunking semanticamente consciente com enriquecimento de metadados melhorou a relevancia de retrieval em aproximadamente 35% comparado a chunking de tamanho fixo nas nossas avaliacoes
  2. Hybrid search - Adicionar busca por keyword BM25 junto com busca vetorial melhorou queries de match exato de 45% para 89% de acuracia
  3. Enriquecimento de chunks - Adicionar titulos de secao e contexto do documento aos chunks antes do embedding melhorou retrieval em aproximadamente 20%
  4. Escolha do modelo de embedding - Trocar entre modelos de embedding teve impacto mensuravel mas menor que os fatores acima
  5. Escolha do LLM - O modelo de geracao teve o menor impacto na qualidade geral do sistema, desde que o retrieval fosse bom

Essa ordenacao reforca a tese: RAG e um problema de engenharia de dados. As decisoes de pipeline de dados (chunking, indexacao, estrategia de busca) importam mais que as decisoes de IA (qual modelo de embedding, qual LLM).

O Ponto Pratico

Se seu sistema RAG esta com desempenho abaixo do esperado, nao busque um modelo melhor. Conserte seu pipeline de dados:

  • Audite sua estrategia de chunking. Os chunks sao semanticamente coerentes? Carregam contexto suficiente?
  • Implemente hybrid search. Busca vetorial pura sempre vai falhar em queries de match exato.
  • Use pgvector a menos que tenha um requisito especifico de escala que demande um banco vetorial dedicado. A simplicidade operacional se paga sozinha.
  • Construa validacao de citacoes no seu pipeline. Confianca e um feature, nao um nice-to-have.
  • Trate freshness de embeddings como voce trata freshness de dados em qualquer outro pipeline. Embeddings stale sao dados stale.

O repositorio rag-knowledge-base-pipeline e uma implementacao funcional desses principios. Clone, aponte para seus documentos e veja a diferenca que engenharia de dados bem feita faz na qualidade de RAG.

RAG nao e um problema de IA. E um problema de dados. E problemas de dados sao o que engenheiros de dados resolvem.

Cluster do tema

Explore este tema entre prova e sinais vivos

Permaneça no mesmo tema mudando apenas o formato: saia do enquadramento estrategico e avance para prova de implementacao ou para um sinal fresco de mercado que mantenha a sessao em movimento.

Continue reading

Transforme esta ideia em um caminho de execucao

Use o proximo passo abaixo para sair da estrategia e chegar a prova, depois assine para continuar recebendo os sinais por tras de futuras decisoes.

Newsletter

Receba o proximo sinal estrategico antes do mercado assimilar.

Cada nota semanal conecta uma mudanca de mercado, um padrao de execucao e uma prova pratica que vale estudar.

Um email por semana. Sem spam. Apenas conteudo de alto sinal para tomadores de decisao.