Radar IA 19 de outubro de 2026
✨ IA MÁGICA Agentes · Modelos · Automação
ÚLTIMAS
Modelos de Linguagem

RAG híbrido: como combinar BM25 e busca vetorial densa em documentação técnica

Como unir BM25 e embeddings com RRF para achar códigos de erro, siglas e números de peça, com exemplos em cinco ferramentas, métricas recall@k e MRR e ajustes para português.

RAG híbrido: como combinar BM25 e busca vetorial densa em documentação técnica
Imagem: capa editorial — Modelos de Linguagem

RAG híbrido é rodar duas buscas para cada pergunta, uma lexical (BM25, que casa palavras exatas) e uma vetorial densa (embeddings, que casa significado), e fundir as duas listas antes de mandar os trechos ao modelo. Em documentação técnica isso costuma fazer diferença, porque as perguntas misturam linguagem natural (“a impressora parou de puxar papel”) com termos que precisam bater letra por letra: códigos de erro, siglas, números de peça e nomes de parâmetro.

A fusão mais usada é a Reciprocal Rank Fusion (RRF), que combina as listas pela posição de cada documento, sem precisar comparar notas de escalas diferentes. Elasticsearch, OpenSearch, Weaviate e Qdrant já trazem híbrido nativo; no PostgreSQL você monta com pgvector e a busca textual do próprio banco. O que decide a qualidade, porém, é a avaliação com perguntas reais e o cuidado com o português: stemming, acentos e stopwords.

Resumo rápido

  • BM25 acerta termos exatos (E-104, NBR 5410, SKU 7731-B); embeddings acertam paráfrases e sinônimos. Em manuais técnicos você precisa dos dois.
  • RRF soma 1/(k + posição) de cada lista; é simples, robusta e dispensa normalizar notas.
  • Elasticsearch tem o retriever rrf; OpenSearch usa query hybrid com pipeline; Weaviate tem hybrid com alpha; Qdrant usa prefetch com fusão; no Postgres você faz a fusão em SQL.
  • Meça recall@k e MRR com um conjunto de perguntas rotuladas antes e depois de ligar o híbrido.
  • Em português, configure analisador com stemming do idioma e trate acentos dos dois lados (indexação e consulta).

BM25 e embeddings densos: o que cada um enxerga

BM25 é uma função de ranqueamento lexical da família TF-IDF. Ela pontua um documento pela frequência dos termos da consulta nele, dá mais peso a termos raros no acervo e normaliza pelo tamanho do documento. Dois parâmetros controlam o comportamento: k1 (saturação da frequência, para que repetir uma palavra 50 vezes não valha 50 vezes mais) e b (quanto o tamanho do documento penaliza). No Elasticsearch, BM25 é a similaridade padrão, com k1 = 1.2 e b = 0.75.

Embeddings densos transformam cada trecho em um vetor de números que representa o sentido do texto. A busca encontra os vetores mais próximos do vetor da pergunta. Se você quer revisar o conceito, veja nosso guia sobre o que são embeddings.

Os pontos cegos são opostos. Um modelo de embeddings pode achar que “erro E-104” e “erro E-140” são quase a mesma coisa, porque o sentido geral é parecido. O BM25 não confunde os dois, mas não sabe que “não liga” e “sem energia” falam do mesmo sintoma.

Critério BM25 (lexical) Embeddings densos
Códigos de erro, SKUs, números de norma Forte: casa o token exato Fraco: códigos parecidos viram vizinhos
Siglas (CLP, IHM, NR-12) Forte, se a sigla estiver no texto Variável: depende do modelo conhecer a sigla
Paráfrase e sinônimo Fraco Forte
Pergunta longa em linguagem natural Médio: muitas palavras irrelevantes Forte
Dependência de idioma Alta: precisa de analisador do idioma Depende do modelo ser multilíngue
Explicabilidade Alta: dá para ver quais termos casaram Baixa

Como a fusão RRF funciona

As notas do BM25 não têm teto, enquanto similaridade de cosseno fica em uma faixa limitada. Somar as duas diretamente não faz sentido. A Reciprocal Rank Fusion, proposta por Cormack, Clarke e Büttcher no SIGIR 2009, ignora as notas e olha só a posição:

rrf(d) = soma, para cada lista L, de 1 / (k + posição de d em L)

Um documento que aparece em 1º no BM25 e em 3º na busca vetorial ganha das duas listas; um que só aparece em uma delas ganha de uma. A constante k suaviza a diferença entre as primeiras posições. No artigo original ela foi fixada em 60, e esse é o padrão do Elasticsearch e do OpenSearch. O Qdrant documenta um padrão diferente para o seu k, então não assuma que todos os bancos usam o mesmo valor.

A alternativa é a fusão por nota normalizada (min-max, z-score ou similar), oferecida pelo OpenSearch no normalization-processor, pelo Weaviate na relativeScoreFusion e pelo Qdrant na DBSF. Ela preserva a informação de “quão melhor” um resultado é, mas fica mais sensível a distribuições estranhas de nota. Comece por RRF e só troque se a avaliação mostrar ganho.

Quando o híbrido ganha (e quando não compensa)

O híbrido costuma ajudar em acervos com muito identificador e pouca redundância de texto:

  • Códigos de erro e alarmes: “F0002”, “E-104”, “ALM 0x1F”.
  • Siglas e jargão interno: nomes de sistema, módulos, setores.
  • Números de peça e modelos: o técnico digita o código impresso na etiqueta.
  • Nomes de parâmetro e comandos: max_connections, systemctl restart.
  • Normas: NBR, NR, ISO com número e ano.

Em FAQ curto e bem escrito, com perguntas sempre em linguagem natural, a busca vetorial sozinha pode bastar, e o BM25 só acrescenta ruído. Por isso a decisão sai da avaliação, não da moda. Depois da fusão, um reranker cross-encoder pode reordenar os melhores candidatos; mostramos isso em RAG com reranker BGE e ColBERT para documentos técnicos.

Como implementar em cada ferramenta

Elasticsearch

O retriever rrf combina um retriever standard (BM25) com um knn (vetorial). Os padrões documentados são rank_constant 60 e rank_window_size 10. Confira na página de assinaturas da Elastic se o recurso está no seu plano.

GET manuais/_search
{
  "retriever": {
    "rrf": {
      "retrievers": [
        { "standard": { "query": { "match": { "texto": "erro E-104 bomba" } } } },
        { "knn": { "field": "vetor", "query_vector": [0.12, -0.03, 0.88],
                   "k": 20, "num_candidates": 100 } }
      ],
      "rank_window_size": 50
    }
  }
}

OpenSearch

Você cria um search pipeline e envia uma query hybrid com as subconsultas. Para RRF, o processador é o score-ranker-processor (introduzido na versão 2.19, com rank_constant padrão 60). Para fusão por nota, o normalization-processor (desde a 2.10).

PUT /_search/pipeline/rrf-pipeline
{ "phase_results_processors": [
    { "score-ranker-processor": { "combination": { "technique": "rrf" } } } ] }

GET /manuais/_search?search_pipeline=rrf-pipeline
{ "query": { "hybrid": { "queries": [
    { "match": { "texto": "erro E-104 bomba" } },
    { "knn": { "vetor": { "vector": [0.12, -0.03, 0.88], "k": 20 } } } ] } } }

Weaviate

A consulta hybrid junta busca por palavra-chave (BM25F) e vetorial. O parâmetro alpha controla o peso: 1 é vetorial pura, 0 é palavra-chave pura. A fusão padrão é a relativeScoreFusion desde a versão 1.24; a rankedFusion usa posições.

manuais = client.collections.use("Manual")
r = manuais.query.hybrid(query="erro E-104 bomba", alpha=0.5, limit=10)

Qdrant

A Query API (desde a 1.10) usa prefetch para rodar a busca esparsa e a densa e depois funde com rrf ou dbsf. O BM25 entra como vetor esparso: crie o vetor com "modifier": "idf" e gere os pesos no servidor com o modelo qdrant/bm25 ou no cliente com FastEmbed. Atenção: a documentação diz que o BM25 do Qdrant usa por padrão configurações de inglês para tokenização, stemming e stopwords. Ajuste o parâmetro language e confira se o português está entre as opções da sua versão.

PostgreSQL com pgvector

O README do pgvector recomenda combinar com a busca textual nativa do Postgres e fundir por RRF ou cross-encoder. Um detalhe importante: ts_rank e ts_rank_cd não são BM25. A documentação do Postgres avisa que essas funções não usam informação global do acervo, ou seja, não há IDF. Funciona bem como sinal lexical, mas não espere o mesmo comportamento do Elasticsearch.

WITH lex AS (
  SELECT id, row_number() OVER (ORDER BY ts_rank_cd(tsv, q) DESC) AS pos
  FROM trechos, websearch_to_tsquery('pt_unaccent', 'erro E-104 bomba') q
  WHERE tsv @@ q ORDER BY pos LIMIT 50),
vet AS (
  SELECT id, row_number() OVER (ORDER BY embedding <=> $1) AS pos
  FROM trechos ORDER BY embedding <=> $1 LIMIT 50)
SELECT id, SUM(1.0 / (60 + pos)) AS rrf
FROM (SELECT * FROM lex UNION ALL SELECT * FROM vet) t
GROUP BY id ORDER BY rrf DESC LIMIT 10;

Para a parte vetorial, crie o índice com CREATE INDEX ON trechos USING hnsw (embedding vector_cosine_ops); e, para a textual, um índice GIN sobre a coluna tsv.

Pegadinhas do português: stemming, acentos e stopwords

O BM25 só é tão bom quanto o analisador que quebra o texto em termos. Em português, três cuidados resolvem a maior parte dos problemas:

  • Stemming: reduz “bombas”, “bombeamento” e “bombear” a radicais. No Elasticsearch, o analisador portuguese usa o stemmer light_portuguese; no Postgres, a configuração portuguese usa o dicionário Snowball do idioma. Analisador em inglês num acervo em português faz o BM25 perder recall sem dar erro.
  • Acentos: o técnico digita “manutencao” e o manual diz “manutenção”. O analisador portuguese do Elasticsearch não remove acentos sozinho; acrescente o filtro asciifolding num analisador próprio. No Postgres, a extensão unaccent pode ser encadeada antes do stemmer numa configuração copiada da portuguese.
  • Códigos não podem ser “stemizados”: o tokenizador pode quebrar “E-104” em “e” e “104”. Indexe o mesmo texto também num campo keyword ou com um analisador simples, e consulte os dois campos.
CREATE EXTENSION IF NOT EXISTS unaccent;
CREATE TEXT SEARCH CONFIGURATION pt_unaccent (COPY = portuguese);
ALTER TEXT SEARCH CONFIGURATION pt_unaccent
  ALTER MAPPING FOR hword, hword_part, word WITH unaccent, portuguese_stem;

A regra de ouro: o mesmo tratamento na indexação e na consulta. A documentação do Qdrant repete esse alerta para as opções de BM25, e ele vale para qualquer ferramenta.

Como avaliar: recall@k e MRR

Monte de 50 a 200 perguntas reais (de chamados, chat de suporte, e-mails) e marque, para cada uma, qual trecho ou trechos contêm a resposta. Inclua de propósito perguntas com códigos e siglas, que são onde o híbrido deve mostrar valor.

  • recall@k: fração das perguntas em que pelo menos um trecho correto aparece entre os k primeiros (ou, na versão estrita, fração dos trechos corretos recuperados). Use o k que você realmente envia ao modelo.
  • MRR (Mean Reciprocal Rank): média de 1/posição do primeiro trecho correto. Acertar em 1º vale 1; em 2º, 0,5; fora da lista, 0. Mostra se o correto está no topo ou escondido.

Compare três configurações com as mesmas perguntas: só BM25, só vetorial e híbrido. Separe os resultados por tipo de pergunta, porque a média geral esconde que o híbrido pode ganhar nas perguntas com código e empatar nas demais. A geração (fidelidade da resposta) se avalia depois, como mostramos em esteiras de avaliação de alucinação com Ragas.

Exemplo: suporte técnico de uma fabricante de bombas em Joinville

Imagine uma fabricante de bombas hidráulicas em Joinville (SC) com manuais em PDF, boletins técnicos e uma tabela de códigos de alarme dos inversores. Os técnicos de campo perguntam coisas como “bomba centrífuga com E-104 depois da troca do selo” ou “como resetar o inversor depois de queda de energia”.

Na primeira versão, só com busca vetorial, a equipe percebe na revisão que perguntas com código traziam boletins de alarmes vizinhos. O caminho seria: separar a tabela de códigos em um trecho por código, indexar os textos no Postgres com a configuração pt_unaccent e um campo extra só com os códigos, manter os embeddings no pgvector e fundir por RRF. Em seguida, rodar a mesma planilha de perguntas rotuladas nas três configurações e decidir pelo recall@k e MRR medidos, separando perguntas com código das demais. Nenhuma ferramenta nova precisaria entrar na stack, já que o banco era o mesmo da aplicação.

Erros comuns

  • Analisador errado. Usar o padrão em inglês num acervo em português. O BM25 funciona, mas pior, e ninguém percebe.
  • Acento tratado só de um lado. Remover acentos na indexação e não na consulta (ou o contrário) quebra o casamento exato.
  • Somar notas cruas. Adicionar nota BM25 a similaridade de cosseno sem normalizar. Use RRF ou um normalizador documentado.
  • Janela pequena demais. Fundir só os 5 primeiros de cada lista. Busque mais candidatos (dezenas) antes da fusão e corte depois.
  • Tratar ts_rank como BM25. No Postgres não há IDF; termos comuns pesam como raros.
  • Avaliar só pela média. Sem separar perguntas com código, o ganho do híbrido some na média.
  • Esquecer a citação. Busca melhor não dispensa mostrar ao técnico de qual manual e página veio a resposta, como explicamos em RAG na prática.

Perguntas frequentes

Preciso de um banco diferente para ter busca híbrida?

Não necessariamente. Elasticsearch, OpenSearch, Weaviate e Qdrant fazem os dois tipos de busca no mesmo lugar, e no Postgres o pgvector convive com a busca textual nativa. Use o que a equipe já opera.

Qual valor de k usar na RRF?

Comece pelo padrão da ferramenta (60 no Elasticsearch e no OpenSearch) e só mude se a avaliação mostrar ganho. Valores menores dão mais peso aos primeiros colocados de cada lista.

Vetores esparsos aprendidos (como SPLADE) substituem o BM25?

São outra opção de sinal lexical e alguns bancos aceitam vetores esparsos de qualquer origem. Mas exigem um modelo, e a qualidade em português depende de como ele foi treinado. BM25 com bom analisador é o ponto de partida mais simples.

O híbrido deixa a busca mais lenta?

Ele roda duas consultas e uma fusão, então há custo extra. Em acervos de documentação técnica de porte médio, isso costuma ser pequeno perto da chamada ao modelo, mas meça na sua infraestrutura.

Ainda preciso de reranker?

O reranker é uma etapa posterior e independente. A fusão melhora o conjunto de candidatos; o cross-encoder reordena esse conjunto com mais precisão. Avalie cada etapa separadamente.

Fontes e leitura recomendada

Sobre

A Redação IA Mágica é formada por especialistas e pesquisadores em inteligência artificial aplicada, agentes autônomos, automações no-code/pro-code e grandes modelos de linguagem (LLMs). Nossos conteúdos cobrem implementações reais, análises e tutoriais aprofundados para profissionais e empresas.