Executando verificação de segurança...
7

RAG em Documentos Longos: Desequilíbrio entre Contexto Global e Precisão Local

Estou trabalhando na implementação de um sistema RAG (Retrieval-Augmented Generation) para análise de documentos técnicos longos e extremamente estruturados (pensem em contratos, manuais operacionais ou editais, cheios de seções, subseções, incisos, etc.).

Estou enfrentando um problema clássico de "cobertor curto" na arquitetura de busca híbrida e gostaria de compartilhar o cenário e ouvir se alguém já passou por isso.

Atualmente, meu pipeline de ingestão e busca funciona assim:

  •  Segmentação (Chunking) Hierárquica: Não uso apenas tamanho fixo. Eu parseio o documento respeitando a estrutura (Títulos, Capítulos, Seções).
    
  •  Enriquecimento: Para evitar que um parágrafo solto perca o sentido, eu injeto o "caminho" dele nos metadados e, às vezes, no próprio texto.
    
  •  Exemplo: Um chunk de texto que diz apenas "Cobre danos materiais" recebe o contexto Documento X > Seção Responsabilidade Civil > Danos a Terceiros.
    
  •  Busca Híbrida (Hybrid Search):
      -      Dense: Embeddings (usando modelos multilingues) para capturar o sentido semântico.
      -      Sparse (BM25): Para garantir que palavras-chave específicas e IDs técnicos não sejam perdidos.
    
    Reranking (RRF): Uso Reciprocal Rank Fusion para combinar as duas listas.

O "Envenenamento" por Keywords Genéricas

O problema surge quando o usuário faz uma pergunta que contém o nome da Entidade principal do documento (ex: o nome da empresa, do fornecedor ou da marca do produto).

Vamos supor que o usuário pergunte: "A empresa Acme oferece suporte técnico acima de para determinado produto?"

Intenção: O usuário quer saber sobre a regra de um produto específico do suporte técnico.

Resultado Esperado: Um chunk na seção de "Serviços de Assistência" que fala sobre esse produto específico.

Resultado Real (Fracasso): O sistema me retorna o chunk "CANAIS DE ATENDIMENTO ACME" (SAC/Telefone) ou outros.

Por que isso acontece? O BM25 (busca esparsa) vê a palavra "Acme" na query e na seção de cabeçalho ("Canais de Atendimento Acme"). O match é exato e muito forte. Já o chunk correto ("Assitência e manutenção para o produto específico...") muitas vezes não repete a palavra "Acme", pois está implícito no contexto do documento.

Na fusão (RRF), o score altíssimo do BM25 para o cabeçalho irrelevante acaba "ganhando" do score mediano do vetor denso para o parágrafo correto.

Estou sofrendo com uma espécie de "Cobertor Curto"

Aqui entra a dor de cabeça da engenharia:

  • Tentativa 1: Enriquecer todos os chunks com o nome da Entidade.
    • Coloquei "Manual Acme" no início de todo chunk de texto antes de vetorizar/indexar.
    • Agora a palavra "Acme" deixa de ser discriminatória (o IDF do BM25 cai drasticamente), mas eu poluo o contexto semântico e aumento o custo de tokens.
  • Tentativa 2: Busca Hierárquica (Drill Down).
    • Tentar primeiro achar o "Tópico" (ex: Assistência) e só depois buscar os detalhes.
    • Aumenta a latência e complexidade. Se o primeiro passo falha, o sistema inteiro falha.
  • Tentativa 3: Limpeza de Query (Query Pre-processing).
    • Usar um LLM para remover a entidade da query antes da busca esparsa (transformar "A Acme cobre X?" em "cobertura de X").
    • Às vezes a entidade é importante (ex: documentos comparativos onde eu tenho Acme e Beta no mesmo banco).

O que estou testando agora (SAC & HSEQ)

Lendo alguns papers recentes (Towards Reliable Retrieval in RAG Systems e Hierarchical Sequence Iteration), estou caminhando para uma solução de Summary-Augmented Chunking (SAC).

A abordagem que notei nos meus logs de teste (tenho um arquivo JSON gigante com testes de busca_simples e comparativas) é que, ironicamente, chunks menores com contexto injetado via metadados funcionam melhor na busca densa, mas a busca esparsa continua sendo "sequestrada" por cabeçalhos que repetem keywords da query.

Alguém já lidou com esse viés de "Headers Genéricos" vencendo "Conteúdo Específico" em buscas híbridas? Como vocês balanceiam o peso do BM25 quando os documentos são muito repetitivos em termos de entidades nomeadas?

Carregando publicação patrocinada...
4

Conheci uma ferramenta aqui no Tab chamada Skald (os devs fizeram pitch delas).

É muito bacana e atende o seu problema. É um RAG as a service, você pode lotar de dados e documentos e depois consultar eles via AI. É bem bacana, vale a pena conhecer!

https://useskald.com

3

Não conhecia o Skald, mas dei uma olhada e realmente parece uma solução bem alinhada com os problemas que estou enfrentando no meu pipeline de RAG. Preciso validar a viabilidade de usar em produção aqui na empresa, mas muito obrigado pela indicação!

1

Eles transformaram em Open Source e tem como usar tanto o plano Cloud pago deles, quanto com o seu próprio DB + Lhamma ou GPT (self-hosted) quanto o seu próprio DB + IA local, para casos que necessitam de mais privacidade.

Mas claro, nesse caso self-hosted DB e IA local, necessitaria de um bom plano de VPS para ter um resultado legal de desempenho com a IA

3

Meus 2 cents,

Obrigado por compartilhar - este eh um problema bem interessante no uso do RAG.

Para quem esta lendo este texto e eh novato em RAG e nao percebeu a nuance do problema - basicamente eh o seguinte: voce tem muitos documentos onde um termo aparece de forma constante (no caso do exemplo: nome da empresa) e a pergunta eh feita usando tambem este termo, sendo que ele eh irrelevante para o contexto geral da pergunta/resposta.

O que acontece: na hora que os trechos/documentos sao recuperados para analise, como o termo tambem eh usado nesta pesquisa (mesmo sendo irrelevante), acaba "contaminando" e trazendo dados que nao sao uteis.

Entao, fica a questao: como eliminar termos "contaminantes" em uma pesquisa para RAG ?

Uma sugestao: usar o modelo de chunks 'pai/filho' no embending (Parent-Child (Small-to-Big) Retrieval)

Explicando: na hora de criar os indices de pesquisa dos documentos, usar chunks curtos (aprox 128/256 tokens), mas armazenar junto o chunk do 'pai' (que pode ser o paragrafo inteiro). Pesquise pelo 'filho' (micro-chunk) e retorne o 'pai' (macro-chunk) para o LLM fazer a analise. Geralmente os chunks 'filhos' com material irrelevante acabam nao tendo peso (score) suficiente para contaminar os resultados mais uteis. (Particularmente tenho usado esta tecnica).

A parte ruim eh ter de criar o banco vetorial um tanto diferente do que voce esta acostumado (p.ex. preparacao de chunks 'pais' e campo extra para o chunk 'pai').

Alguns autores sugerem usar a busca apenas pelos metadados para evitar isso - mas depende muito de como tua solucao precisa trabalhar (gosto de usar metadados como fonte auxiliar ou como pre-filtro e nao como principal).

Uma outra sugestao eh complementar (ou substituir) o RRF com 'Cross-Encoder' apos a pesquisa para fazer re-rank (o que pode ser uma opcao bem interessante) e tentar eliminar falsos positivos (pois percebe que o texto nao responde aa pergunta, apesar de ter a palavra-chave).

Saude e Sucesso !

2

Obrigado pelo tempo gasto me ajudando, você explicou exatamente o tipo de nuance que costuma passar despercebida.

No meu caso, o sistema que está em produção já usa uma arquitetura híbrida bem mais profunda do que apenas RRF: o Qdrant faz o prefetch combinando dense + BM25, aplica late interaction (ColBERT) dentro do próprio banco e, depois disso, ainda passo os candidatos por um cross-encoder na aplicação para tentar eliminar falsos positivos. Isso resolve muitos casos práticos, mas ainda não é suficiente quando o problema acontece na fase de prefetch, onde os cabeçalhos com termos recorrentes preenchem todas as vagas antes mesmo do reranker ter chance de ver os chunks relevantes.

Achei interessante a sua sugestão do modelo small-to-big com relação pai/filho. Eu já fiz alguns testes nessa direção, mas seguindo um fluxo um pouco diferente. Do jeito que você descreveu, micro-chunks para buscar, macro-chunks para entregar contexto, faz bastante sentido como estratégia para evitar que headers “fortes” matematicamente coloquem os trechos específicos para fora do top-K inicial.

Agradeço pela explicação detalhada e pela sugestão prática. Vou testar essa lógica de parent-child retrieval de forma mais sistemática nos próximos ciclos. Excelente contribuição, obrigado mesmo!

2

Meus 2 cents extendidos,

Fico contente se agregou algo.

Espero que voce consiga achar uma solucao que adequada para tua situacao.

E, se nao for segredo industrial - por favor, nao esqueca de compartilhar o caminho seguido (este tipo de problema eh instigante).

Saude e Sucesso !

2

Me parece que seu problema está no "sparse embedding". Dado que você já realiza enriquecimento nos dados e a segmentação por contexto, a sua necessidade por palavras-chave poderia ser substituída apenas pelo "dense embedding". Ou seja, Tentative zero: Remover o sparse embedding da lógica e testar sua performace empiricamente.

Ademais, se você tem recurso computacional para investir no "dense embedding", faça como tal: injete mais contexto nos metadados e documentos; teste embeddings de tamanhos diferente, e modelos diferentes; teste funções de similaridade distintas.

Me parece ser um projeto interessante. Te desejo uma boa "ciência" de dados! 😁

2

Valeu pelo insight!

Faz sentido testar a busca só com dense para ver o impacto real do sparse no ruído. Vou investir mais no lado denso, enriquecer melhor metadados, experimentar modelos maiores e diferentes funções de similaridade pode ajudar a ter uma recuperação mais estável, sem o viés das keywords.

Agradeço demais pelas sugestões, vou fazer os testes com essas ideias. E obrigado pela boa “ciência” de dados! 😄

2

Os trade offs das diversas técnicas de rag na prática é complicado.

Seu model embedding é SOTA? Talvez trocar seja uma das mudanças mais simples e com mais ganho.

Melhorar o query pre-processing, mas n para retirar termos/jargões, mas sim para expandir a query com conhecimento útil já vai naturalmente diminuir um pouco a importância destes termos q estão enviesando a retrieval no cálculo de cosseno, claro, é um chute meu.

Tem como fazer um agente mais elaborado q muda a técnica de rag e flows (graphrag, ou reranking, etc) de acordo com o input inicial do user, mas n sei... Pode ser muito complexo, eu mesmo nunca tentei.

Enfim, muito massa o caso seu. Quando tiver resultado compartilhe aqui no tab, flw

1

Percebo que muitos dos problemas atribuídos ao RAG, na verdade, surgem de uma visão equivocada sobre o que ele pode, ou deveria, fazer.

Essa ideia de que você vai despejar um monte de documentos e, milagrosamente, extrair respostas corretas para cenários diferentes… não parece meio exagerada?

Já parou pra pensar que o problema pode não estar no RAG, e sim na qualidade, estrutura ou até no formato da base de conhecimento que você está entregando para ele trabalhar?