Pesquisa híbrida: BM25 + vectoriel
A pesquisa híbrida inicia em paralelo uma busca por palavras-chave (BM25) e uma busca vetorial sobre a mesma pergunta, depois combina as duas classificações, geralmente por Reciprocal Rank Fusion (RRF). Ela compensa os casos em que o embedding falha (identificadores, nomes próprios, termos raros) sem perder a compreensão de paráfrases. Qdrant, Weaviate e Elasticsearch a oferecem nativamente; com ChromaDB, ela é construída em trinta linhas de Python.
Uma base vetorial encontra o sentido, não as correspondências exatas: uma referência como «RG/2024-117» ou um número de ticket pode passar despercebido por ela. Por outro lado, a busca por palavras-chave não entende que «automóvel» e «carro» designam a mesma coisa. Este guia mostra como combinar as duas abordagens, qual método de fusão escolher, o que fazem Qdrant e Weaviate e uma armadilha de tokenização em francês que compromete silenciosamente a parte BM25.
#Por que a busca puramente vetorial falha em algumas perguntas
A busca vetorial transforma cada trecho em um vetor que resume seu significado geral e depois retorna os trechos cujo vetor é mais próximo do vetor da pergunta. Essa compressão funciona muito bem para paráfrases, mas mal para tudo que precisa ser encontrado exatamente: um identificador, um código de erro, um nome de pessoa, uma sigla interna. Para o embedding, "PROD-4817" e "PROD-4871" se parecem, e um ticket sem relação pode aparecer antes do correto. A busca híbrida corrige essa falha: ela adiciona uma segunda classificação baseada na presença exata das palavras e combina as duas para que cada método compense os pontos cegos do outro.
- Identificadores e referências
- Números de ticket, de processo, de contrato, SKU, códigos de erro: são strings que um embedding não conserva de forma confiável e que BM25 encontra assim que aparecem no trecho.
- Vocabulário especializado pouco frequente
- Termos médicos, jurídicos ou técnicos pouco comuns: o peso de uma palavra rara é alto no BM25, enquanto seu embedding pode ser vago.
- Consultas muito curtas
- Dois termos como 'fatura 2024' não fornecem muita base para um embedding; as palavras-chave, por outro lado, são comparadas exatamente como estão.
- Paráfrases e reformulações
- O caso inverso: 'contrato de duração determinada' e 'CDD' ou 'carro' e 'automóvel' não compartilham nenhuma palavra; apenas a busca vetorial os aproxima
#BM25: o que faz a pesquisa por palavras-chave
Seus documentos, sua IA: um RAG local confiável para seus PDFs, notas e e-mails — sem enviar nada para a nuvem.
- Espaço online vitalício
- PDF + arquivos
- Atualizações vitalícias
BM25 é a função de classificação lexical usada pelo Lucene, pelo Elasticsearch e pelo OpenSearch, e que o SQLite oferece no módulo FTS5 (a documentação descreve sua função bm25() como retornando um valor que indica o grau de correspondência da linha com a consulta). Ela se baseia em três ideias: uma palavra rara tem mais peso que uma palavra frequente, uma palavra repetida conta cada vez menos após um certo número de ocorrências, e um trecho longo é ligeiramente penalizado em relação a um curto. O parâmetro k1 regula essa saturação: segundo a descrição da Elastic, ele limita a influência que um único termo da consulta pode ter sobre a pontuação de um documento.
- Pontos fortes
- Termos raros, identificadores, consultas curtas, vocabulário especializado, nenhum modelo para carregar ou treinar, índice compacto, resultado explicável (sabemos qual palavra fez o trecho aparecer nos resultados).
- Fraquezas
- Sinônimos, reformulações, paráfrases, erros de digitação; sem lematização, 'assinado' e 'assinatura' são palavras diferentes.
- Requisitos prévios
- Uma tokenização cuidadosa: conversão para minúsculas, remoção dos acentos e, eventualmente, redução ao radical (stemming). É nesse ponto que a maioria das implementações próprias erra; veja abaixo.
#Busca híbrida: o princípio
Executamos as duas buscas com a mesma pergunta, cada uma retorna sua lista de candidatos (20 a 50 passagens), depois mesclamos as duas listas em um único ranking. O ganho vem de uma observação simples: os trechos que aparecem nas duas listas são quase sempre relevantes, e cada método traz também passagens que o outro deixou de recuperar. O Weaviate define a pesquisa híbrida assim: combina os resultados de uma pesquisa vetorial e de pesquisa por palavras-chave ao mesclar os dois conjuntos de resultados, com uma metodologia de fusão e pesos relativos configuráveis. O ganho em números depende do corpus e das perguntas: nenhum valor geral é confiável, e deve ser medido em seus próprios documentos (ver abaixo).
#Combinar sem normalizar: Reciprocal Rank Fusion
O erro comum é somar as pontuações brutas. Uma pontuação BM25 é um número positivo sem limite superior; uma pontuação de similaridade vetorial é uma distância ou um cosseno, em uma faixa limitada: as duas escalas são incomparáveis, e a menor mudança no corpus as desloca. A Reciprocal Rank Fusion contorna o problema ao usar apenas as posições nos rankings. A documentação do Elasticsearch a apresenta como um método que não exige ajustes e cujos indicadores de relevância não precisam estar relacionados entre si.
Um trecho classificado em primeiro lugar pelo BM25 e em quinto pela busca vetorial obtém 1/61 + 1/65, ou seja, aproximadamente 0,0318; um trecho classificado em décimo quinto nas duas listas obtém 2/75, ou seja, aproximadamente 0,0267. A constante k atenua a vantagem da primeira posição: quanto maior ela for, mais as posições distantes contam. O Elasticsearch documenta essa constante com o nome rank_constant, com valor padrão de 60, e um tamanho de janela (rank_window_size) que define o comprimento de cada lista antes da fusão. Uma janela maior melhora a relevância à custa do desempenho, segundo a documentação.
#E a fusão por pontuação?
Alguns mecanismos oferecem uma alternativa: normalizar as pontuações de cada lista e depois combiná-las usando um peso. O Weaviate documenta os dois métodos: uma classificação por posições e uma fusão por pontuações relativas, sendo esta última o método padrão desde a versão 1.24; ela é necessária para usar o autocut com o operador híbrido. O Qdrant oferece RRF e DBSF, sendo que esta última preserva as pontuações brutas, mas normaliza sua distribuição (média e desvio padrão) antes da combinação. A fusão por posições é mais robusta quando não se conhece a distribuição das pontuações; a fusão por pontuações permite um ajuste mais fino quando é possível medir.
#Qual ferramenta: mecanismos com suporte nativo à busca híbrida
| Ferramenta | Híbrido nativo | Fusão | Ajuste do peso |
|---|---|---|---|
| Qdrant | Sim, via API Query (disponível a partir da versão 1.10) | RRF ou DBSF | Peso por requisição e constante k ajustáveis nas versões recentes |
| Weaviate | Sim, operador hybrid | Posições no ranking ou pontuações relativas (padrão desde a versão 1.24) | Parâmetro alpha: 1 = puramente vetorial, 0 = apenas palavras-chave |
| Elasticsearch | Sim, recuperador rrf | RRF | rank_constant (60 por padrão) e rank_window_size |
| SQLite FTS5 + extensão vetorial | A ser montado | A ser escrito | A seu critério |
| ChromaDB + rank_bm25 | Para montar em Python | A ser escrito (RRF em 6 linhas) | A seu critério |
A diferença fundamental não está na fusão em si, que cabe em poucas linhas, mas no índice: um mecanismo nativo mantém os dois índices atualizados em conjunto, enquanto uma solução montada por conta própria mantém o índice BM25 na memória e precisa reconstruí-lo a cada adição de documento. Para um corpus de alguns milhares de trechos que muda raramente, essa solução é mais do que suficiente. Acima disso, ou assim que os documentos passam a mudar diariamente, um mecanismo nativo evita inconsistências entre os dois índices. O guia sobre o Weaviate apresenta essa ferramenta em detalhes.
#Implementação própria: ChromaDB, rank_bm25 e RRF
O código a seguir combina as três peças. Ele corrige um defeito comum em exemplos: a função de normalização deve remover os sinais diacríticos antes de filtrar; caso contrário, cada letra acentuada divide uma palavra em duas.
Duas precauções práticas. Primeiro, os identificadores devem ser iguais nos dois índices: aqui, o índice da lista, convertido em string, serve de identificador no Chroma. Em seguida, o índice BM25 em memória desaparece quando o programa é encerrado: reconstrua-o ao iniciar, o que leva alguns segundos para dezenas de milhares de passagens, ou salve a lista de documentos ao lado da base.
#Ajustar o equilíbrio entre BM25 e busca vetorial
Por padrão, RRF dá o mesmo peso às duas listas. Se o seu corpus for rico em referências (jurisprudência, tickets, catálogos), dê mais peso ao BM25; se as perguntas forem conversacionais, mantenha o equilíbrio ou favoreça a busca vetorial. Na função anterior, basta passar weights=[0.6, 0.4] para dar 60% de peso ao BM25. Qdrant permite o mesmo ajuste: sua documentação indica que o peso de cada consulta vale 1 por padrão, o que restaura a fórmula original do RRF, e que a constante k é ajustável nas versões recentes. No Weaviate, ajusta-se alpha: 1 corresponde à busca puramente vetorial, 0 à busca exclusivamente por palavras-chave.
| Corpus e perguntas | Pesos iniciais BM25 / vetorial | O que você está monitorando |
|---|---|---|
| Referências, números, nomes próprios (área jurídica, tickets, catálogos) | 60 / 40 | As perguntas por identificador aparecem primeiro? |
| Documentação redigida, perguntas em linguagem natural | 40 / 60 | As reformulações conseguem recuperar o trecho correto? |
| Corpus misto ou desconhecido | 50 / 50 | Recall@5 em 30 a 50 perguntas reais |
| Siglas e jargão profissional | 55 / 45, com um dicionário de sinônimos na busca BM25 | A sigla e sua forma por extenso encontram o mesmo trecho? |
#Após a fusão: adicionar um reranker
A fusão gera um conjunto mais diversificado de candidatos do que cada método isoladamente. Um reranker pode então ordenar esse conjunto lendo cada trecho junto com a pergunta: as duas técnicas podem ser combinadas. A ordem habitual é busca híbrida, seguida da fusão, depois a aplicação de um reranker aos 20 a 50 primeiros resultados e, por fim, a inclusão dos 3 a 5 melhores trechos no prompt. O guia sobre o reranker detalha essa última etapa, e o guia sobre chunking explica por que o tamanho dos trechos influencia tanto o BM25 quanto os embeddings.
#Perguntas frequentes sobre busca híbrida
O que é a pesquisa híbrida em um RAG?+
É necessário normalizar as pontuações BM25 e vetoriais antes de somá-las?+
Qual valor de k escolher em RRF?+
É possível fazer busca híbrida com ChromaDB?+
A busca híbrida torna as consultas muito mais lentas?+
Como saber se o híbrido vale a pena para meus documentos?+
- Adicionar um reranker ao seu pipeline
- Estratégias de chunking
- Weaviate: busca híbrida e multitenancy
- RAG local com ChromaDB e Ollama
- Os melhores modelos de embeddings para francês
- Fonte: Qdrant, consultas híbridas
- Fonte: Weaviate, pesquisa híbrida
- Fonte: Elasticsearch, Reciprocal Rank Fusion
- Fonte: SQLite FTS5, função bm25()
Um comentário, um erro ou uma observação? Avise-nos; isso ajuda a melhorar o guia para todos.