Voltar ao blog
21/07/2026Equipe de Produto CCT CRM

Query Rewriting + Hybrid Search + Reranking: levando a base de conhecimento de IA de 'consegue buscar' para 'busca com precisão'

A busca vetorial é apenas o ponto de partida. Colocamos em produção no CCTCRM três grandes técnicas de aprimoramento de RAG: Query Rewriting, Hybrid Search (fusão RRF) e Reranking, usando engenharia para elevar ainda mais a precisão de recuperação da base de conhecimento. Este artigo registra a escolha técnica, detalhes de implementação e as armadilhas que enfrentamos.

RAGQuery RewritingHybrid SearchRerankingRRFbusca vetorialCCT CRMbase de conhecimento de IA
Compartilhar este artigo

Nossa base de conhecimento RAG está em produção há seis meses. Usa busca vetorial com Embedding de 768 dimensões, ordenação por similaridade de cosseno, cobrindo 9 grandes domínios de negócio: clientes, pedidos, produtos, embarques, produção, estoque, finanças, entre outros. A funcionalidade funciona, os usuários estão usando.

Mas há um abismo entre "funciona" e "é bom de usar".

Quando um vendedor pergunta "quantos contêineres dos pedidos enviados aos Estados Unidos no mês passado ainda não chegaram ao porto", o primeiro resultado retornado pelo sistema é um documento sobre a política tarifária dos EUA. Semanticamente, há relação — ambos mencionam "Estados Unidos" e "pedidos". Mas o usuário quer dados de embarque, não política tarifária.

Esse tipo de desalinhamento é muito comum na busca vetorial. O modelo de Embedding compreende similaridade semântica, não relevância de negócio. Dois trechos de texto próximos no espaço vetorial não significam que sejam a mesma coisa no cenário de negócio.

Passamos três semanas adicionando uma camada de processamento a montante e a jusante da busca vetorial, elevando a precisão de recuperação. Três técnicas, um objetivo: que o que é encontrado seja o que o usuário quer.

Pipeline de aprimoramento RAG
Pipeline de aprimoramento RAG: Query Rewriting → Hybrid Search (fusão RRF) → Reranking

Onde está o problema

Antes de otimizar, precisamos entender primeiro as três deficiências estruturais do RAG ingênuo.

Primeiro, o usuário fala como gente, o motor de busca quer palavras-chave. O vendedor não vai digitar "Estados Unidos pedidos de exportação número de contêineres estatística de embarque". Ele vai dizer "quantos contêineres dos pedidos enviados aos Estados Unidos no mês passado ainda não chegaram ao porto". Quando essa frase entra no modelo de Embedding, termos coloquiais como "mês passado", "quantos", "ainda não chegaram ao porto" diluem o sinal das entidades centrais. No espaço vetorial, essa frase pode estar próxima de um documento sobre "processo de despacho aduaneiro nos EUA" — porque semanticamente são parecidos — mas está a uma camada de distância da verdadeira tabela de estatística de embarque.

Segundo, a busca vetorial é boa em "parece semanticamente", mas não em "correspondência exata". Suponha que exista na base de conhecimento um documento cujo título seja exatamente "Norma de estatística de embarque de pedidos dos EUA". A busca vetorial pode não colocá-lo em primeiro lugar — porque a distância semântica entre o título e a pergunta coloquial do usuário pode não ser a menor. Mas a busca por palavras-chave (MySQL LIKE ou BM25) consegue corresponder imediatamente. Por outro lado, a busca por palavras-chave não consegue entender sinônimos e associações semânticas. Os dois métodos têm pontos cegos diferentes.

Terceiro, nos resultados recuperados, alta similaridade vetorial não equivale a alta relevância de negócio. A similaridade de cosseno mede a consistência de direção de dois trechos de texto no espaço vetorial. Dois trechos com a mesma direção podem estar apenas discutindo o mesmo tópico, mas com posicionamento, cenário e significado de negócio completamente diferentes. O usuário pergunta "como lidar com reclamações de atraso na entrega", o sistema retorna um documento sobre "análise das causas de atraso na entrega" — similaridade 0,87, mas não responde à pergunta.

Esses três problemas não são deficiências de um modelo de Embedding específico, são limitações estruturais da arquitetura RAG ingênuo. A indústria já tem soluções maduras: Query Rewriting resolve o problema na entrada, Hybrid Search cobre os pontos cegos da recuperação, Reranking corrige o viés na ordenação. As três técnicas usadas em conjunto formam um pipeline de aprimoramento "reescrita → busca híbrida → reordenação" $TRAE_REF.

Primeira camada: Query Rewriting — deixe o LLM ajudar o usuário a se expressar claramente

A ideia é direta: antes de enviar a pergunta do usuário para a busca vetorial, um modelo leve (usamos o modelo do grupo lite, o de menor custo) reescreve a pergunta coloquial em uma combinação de palavras-chave mais adequada para a busca.

O usuário diz: "quantos contêineres dos pedidos enviados aos Estados Unidos no mês passado ainda não chegaram ao porto"

Após reescrita: "Estados Unidos pedidos de exportação número de contêineres estatística de embarque mês passado volume de exportação"

O texto reescrito é então enviado para gerar o vetor de Embedding. O efeito é duplo: por um lado, remove os modificadores coloquiais como "mês passado", "quantos", "ainda não chegaram ao porto" que não contribuem para a busca; por outro, adiciona sinônimos e termos relacionados como "estatística de embarque" e "volume de exportação", ampliando o recall semântico.

Na implementação há alguns pontos-chave de design.

O Prompt é o núcleo. A qualidade da reescrita depende inteiramente do design do system prompt. Nosso prompt contém cinco regras: extrair entidades centrais (nomes de pessoas, produtos, países, tipos de documento), adicionar sinônimos e termos relacionados, remover palavras de tom, produzir texto puro sem explicação, preservar o idioma original. Além das regras, fornecemos dois exemplos few-shot, cobrindo cenários em chinês e inglês. Sem few-shot, o modelo produz "consulta reescrita: XXX", um formato com prefixo que quebra a análise a jusante.

Consultas curtas não são reescritas. Entradas com menos de 6 caracteres pulam diretamente a etapa de reescrita. Essas consultas geralmente são palavras-chave em si, como "cliente" ou "pedido", e a reescrita não traz ganho, apenas aumenta a latência. Esse limiar é o ponto de inflexão que observamos nos testes: consultas com mais de 6 caracteres têm ganho positivo após a reescrita, abaixo disso o ganho não é significativo.

Cache de 5 minutos. A mesma consulta não invoca o modelo repetidamente dentro de 5 minutos. Usamos um ConcurrentHashMap para armazenar o mapeamento hash → resultado da reescrita, com limpeza automática ao expirar. O cache tem limite de 200 entradas; quando enche, os itens expirados são removidos. Esse design faz com que consultas repetidas de alta frequência (por exemplo, vários vendedores consultando o mesmo cliente simultaneamente) não disparem chamadas repetidas ao modelo, mantendo o custo sob controle.

Degradação em caso de falha. Falha na chamada do modelo, cota insuficiente, timeout de rede — qualquer exceção degrada silenciosamente, retornando a consulta original. A reescrita é um refinamento, não uma necessidade. Não podemos deixar todo o fluxo RAG quebrar porque o serviço de reescrita está indisponível.

Segunda camada: Hybrid Search — vetor + palavras-chave, fusão com RRF

Esta camada resolve o problema de que "busca vetorial e busca por palavras-chave têm pontos cegos diferentes".

A solução é executar as duas buscas em paralelo e depois fundir os resultados. A busca vetorial cuida do recall semântico — entendendo sinônimos, conceitos relacionados e correspondência multilíngue. A busca por palavras-chave cuida da correspondência exata — palavras brutas contidas em títulos e campos de palavras-chave. Os resultados das duas buscas são fundidos com o algoritmo Reciprocal Rank Fusion (RRF).

Algoritmo RRF

RRF é um método de rank fusion proposto em 2009 por Cormack et al. $TRAE_REF. A ideia central é extremamente simples: não importa a pontuação original de cada busca (similaridade vetorial vs. pontuação BM25 não são comparáveis), importa apenas o ranking que cada busca produz.

Fórmula:

RRF_score(d) = Σ  1 / (k + rank_i(d))
             i∈lists

Onde rank_i(d) é a posição do documento d nos resultados da i-ésima busca (a partir de 0), e k é uma constante de suavização (usamos 60).

Suponha que o documento A esteja em 1º lugar na busca vetorial e em 5º na busca por palavras-chave:

RRF_score(A) = 1/(60+1) + 1/(60+6) = 0.0164 + 0.0152 = 0.0316

O documento B está em 3º lugar na busca vetorial e em 2º na busca por palavras-chave:

RRF_score(B) = 1/(60+4) + 1/(60+3) = 0.0156 + 0.0159 = 0.0315

As pontuações RRF de A e B são quase iguais — mesmo que A esteja muito acima de B na busca vetorial. Essa é a característica do RRF: ele não favorece a diferença absoluta de pontuação de nenhuma das buscas, olha apenas o desempenho combinado de ranking. Um documento que aparece bem colocado nas duas buscas terá uma pontuação RRF alta.

Diagrama de fusão RRF
Fusão RRF: resultados de busca vetorial e por palavras-chave fundidos por ranking

Implementação

Nossa classe RagEnhancementService implementa a lógica de fusão RRF. O fluxo é:

  1. A busca vetorial retorna os top 20 resultados (ordenados por similaridade de cosseno decrescente)
  2. A busca por palavras-chave retorna os top 20 resultados (MySQL LIKE nos campos title/content/keywords)
  3. Os resultados das duas buscas entram no método reciprocalRankFusion, com k=60
  4. Após a fusão RRF, ordena-se por pontuação decrescente e pega-se o top K

A implementação da busca por palavras-chave é simples: tokenização por espaços e pontuação, palavras com comprimento ≥ 2, e consulta OR com a condição LIKE do MyBatis-Plus. Não usamos o índice FULLTEXT do MySQL porque nossa base de conhecimento é pequena (alguns milhares de registros), e o desempenho do LIKE é suficiente. Se no futuro a base crescer para dezenas de milhares de registros, consideraremos migrar para BM25 ou Elasticsearch.

Escolha do k no RRF. Quanto maior o k, mais suave é o impacto da diferença de ranking na pontuação; quanto menor o k, mais vantajosos são os documentos melhor colocados. Usamos 60, que é o valor padrão do paper original do RRF e do Elasticsearch $TRAE_REF. Nos testes, k=60 teve desempenho estável, sem necessidade de ajustes excessivos.

Um documento que aparece nas duas buscas terá pontuação RRF maior do que um que aparece em apenas uma. Essa é uma característica natural do RRF, e também o efeito que queremos — documentos considerados relevantes por ambas as buscas são, muito provavelmente, o que o usuário procura.

Terceira camada: Reranking — deixe o LLM fazer a última filtragem

Hybrid Search resolveu o problema de "encontrar". Mas a ordem em que os resultados encontrados são exibidos ainda é determinada pela pontuação RRF — e a pontuação RRF só reflete ranking, não relevância de negócio.

Voltando ao exemplo anterior. O usuário pergunta "como lidar com reclamações de atraso na entrega". Os resultados podem incluir:

  • Documento A: "fluxo de tratamento de reclamações por atraso na entrega" (realmente relevante)
  • Documento B: "análise das causas de atraso na entrega" (tópico relacionado, mas não responde à pergunta)
  • Documento C: "estatística de taxa de pontualidade de entrega de 2024" (dados relacionados, mas cenário errado)

A busca vetorial pode colocar B à frente de A (porque a redação de B é mais próxima da pergunta do usuário), a busca por palavras-chave pode colocar C à frente (porque a palavra "entrega" aparece mais vezes). Após a fusão RRF, a ordem ainda pode ser B > A > C.

Reranking é adicionar uma reordenação por LLM antes de retornar os resultados fundidos. A consulta e os documentos candidatos são enviados juntos ao modelo lite, que julga qual documento é o mais relevante.

Como implementamos

Pedimos ao LLM que faça uma versão simplificada de ordenação pointwise. A prática:

Os documentos candidatos (10 por padrão) são numerados e enviados junto com a consulta do usuário ao modelo lite; o prompt exige que o modelo retorne a sequência de números ordenada por relevância, do maior para o menor. Por exemplo, dados 10 documentos como entrada, o modelo retorna "2,0,5,1,3,8,4,7,6,9", indicando que o documento nº 2 é o mais relevante e o nº 9 o menos relevante.

Consideramos usar um modelo Cross-Encoder para o reranking — como o BGE-Reranker-v2-m3 do Instituto de Inteligência de Zhongyuan $TRAE_REF. O Cross-Encoder concatena a consulta e o documento em uma sequência de entrada que é enviada ao modelo, e após uma modelagem conjunta, retorna uma pontuação de relevância entre 0 e 1. A precisão é de fato maior do que a ordenação por prompt de LLM.

Mas acabamos optando pela solução com LLM, pela razão de custo de implantação. O Cross-Encoder exige a implantação de um serviço de modelo adicional (BGE-Reranker-v2-m3 tem cerca de 2,8GB $TRAE_REF), enquanto já estamos usando o modelo lite para Query Rewriting, e o Reranking reutiliza a mesma API de modelo, com custo de implantação adicional zero. Para a escala da nossa base de conhecimento (alguns milhares de documentos), a precisão do reranking com LLM é suficiente. Se no futuro a base de conhecimento se expandir para dezenas de milhares ou mais, ou se houver requisitos maiores de precisão, podemos migrar para Cross-Encoder — a interface já está abstraída, basta trocar a classe de implementação.

Controle do número de candidatos. O Reranking por padrão processa apenas os 10 primeiros candidatos. Enviar muitos documentos ao modelo torna o prompt mais longo, aumenta a latência e também degrada a precisão (a atenção do modelo é diluída). 10 é o ponto de equilíbrio entre latência e cobertura.

Estratégia de degradação. Assim como no Query Rewriting, em caso de falha na chamada do modelo, há degradação silenciosa, retornando a ordenação original após a fusão RRF. Reranking é uma otimização de precisão, não uma dependência funcional.

Design de arquitetura: camada SDK + interface SPI

A implementação das três técnicas de aprimoramento não foi colocada no sistema de negócio cct-crm-backend, mas foi movida para a nossa biblioteca central ai-sdk. O motivo é que essas capacidades não são específicas do negócio de comércio exterior — qualquer sistema que use RAG pode reutilizá-las.

A arquitetura tem três camadas:

┌─────────────────────────────────────────┐
│  cct-crm-backend (宿主系统)              │
│  RagEnhancementProviderImpl              │
│  → callLiteModel (HTTP 调用 LLM API)     │
│  → keywordSearch (MySQL LIKE 检索)        │
│  → getConfig (读取云端配置)               │
└──────────────┬──────────────────────────┘
               │ implements SPI
┌──────────────▼──────────────────────────┐
│  ai-sdk-core (SDK 核心层)               │
│  RagEnhancementService                  │
│  → rewriteQuery (Prompt 构建 + 缓存)     │
│  → reciprocalRankFusion (RRF 算法)      │
│  → hybridSearch (编排: 调 Provider + RRF)│
│  → rerankResults (Prompt 构建 + 解析)     │
│  → RagSearchResult (数据类)              │
└──────────────┬──────────────────────────┘
               │ uses
┌──────────────▼──────────────────────────┐
│  RagEnhancementProvider (SPI 接口)      │
│  → callLiteModel                        │
│  → keywordSearch                        │
│  → getConfig                            │
└─────────────────────────────────────────┘

O algoritmo central (RRF, construção de Prompt, análise de resultados) fica na camada SDK, sem nenhuma dependência do Spring. O sistema hospedeiro só precisa implementar a interface SPI, fornecendo três capacidades: chamada de LLM, busca por palavras-chave e leitura de configuração. A vantagem desse design é: no futuro, se outros sistemas se conectarem ao ai-sdk, basta implementar a interface Provider para obter a capacidade completa de aprimoramento RAG, sem desenvolvimento duplicado.

Os switches de configuração estão todos no banco de dados. Cinco itens de configuração ficam na tabela pb_ai_config na nuvem, com model_group = 'rag_enhancement':

Chave de configuração Valor padrão Descrição
rag_query_rewrite_enabled true Switch do Query Rewriting
rag_hybrid_search_enabled true Switch do Hybrid Search
rag_reranking_enabled true Switch do Reranking
rag_hybrid_candidate_count 20 Quantidade de recall da busca por palavras-chave
rag_rerank_candidate_count 10 Quantidade de candidatos para Reranking

A configuração é atualizada a cada 5 minutos; alterada no banco, entra em vigor imediatamente (no máximo 5 minutos de espera). Cada recurso de aprimoramento tem um switch independente, podendo ser desativado isoladamente. Se um recurso de aprimoramento tiver mau desempenho em um cenário específico, ou se for necessário controlar custos, pode-se desligar apenas ele sem afetar os outros dois.

Resultados e custos

Após os três recursos de aprimoramento entrarem em produção, observamos as seguintes mudanças em testes internos:

Precisão de recuperação. Preparamos 50 conjuntos de consultas de teste (cobrindo cinco cenários: consulta de clientes, consulta de pedidos, consulta de produtos, consulta de embarques, consulta de políticas), comparando a taxa de acerto top-1 e top-3 antes e depois do aprimoramento. Antes do aprimoramento, a taxa de acerto top-1 era de cerca de 68%; depois, cerca de 82%, um ganho de 14 pontos percentuais. A taxa de acerto top-3 subiu de 85% para 94%. Esses dados são de testes internos, não uma avaliação acadêmica rigorosa, mas a tendência é clara.

Comparação da precisão de recuperação
Precisão de recuperação antes vs depois do aprimoramento (50 consultas de teste internas)

Aumento de latência. Com as três camadas de aprimoramento totalmente ativadas, a latência de uma única busca subiu de ~200ms para ~800ms-1,2s (principalmente devido a duas chamadas de LLM). Para o cenário de busca em base de conhecimento, essa latência é aceitável — o usuário esperando 1 segundo por um resultado mais preciso é uma experiência muito melhor do que esperar 200ms por um resultado irrelevante. Se a latência for crítica, pode-se desativar o Reranking (que contribui com cerca de 60% da latência adicional), mantendo apenas Query Rewriting + Hybrid Search, com aumento de latência de cerca de 300ms.

Custo. Query Rewriting e Reranking usam ambos o modelo lite, com cada chamada consumindo cerca de 200-500 tokens. Pela nossa precificação de API, uma única busca com aprimoramento completo custa cerca de 0,001-0,002 yuan. Com o cache de 5 minutos, consultas repetidas de alta frequência não disparam chamadas repetidas do modelo, e o custo real é ainda menor.

Direções futuras

Depois que as três técnicas de aprimoramento foram implementadas, a precisão do RAG de fato melhorou. Mas o teto do RAG ingênuo não para por aí. Ao planejar o próximo passo, identificamos algumas direções que merecem atenção.

Cross-Encoder substituindo o Reranking por LLM. Usar o modelo lite para Reranking hoje é uma concessão orientada a custo. Se implantarmos um modelo de reordenação dedicado como o BGE-Reranker-v2-m3, a precisão pode aumentar mais um pouco $TRAE_REF. A vantagem do Cross-Encoder está em fazer codificação conjunta da consulta e do documento, compreendendo relações de granularidade fina entre os dois textos, enquanto o LLM apenas faz ordenação por prompt. A interface já está abstraída; a troca é uma questão de esforço de engenharia, não de arquitetura.

Context Engineering. Em 2025, a indústria começou a evoluir de RAG para Context Engineering $TRAE_REF. RAG se preocupa com "o que foi recuperado", Context Engineering se preocupa com "como construir o contexto enviado ao modelo". Além dos resultados de recuperação, também deve integrar informações multidimensionais como papel do usuário, dados em tempo real, histórico de conversa, fronteiras de permissão, etc., para que o modelo receba não uma lista de documentos, mas uma instrução de trabalho estruturada e contextualizada. Nosso protótipo de modelo causal (aprendizado de experiência + roteamento de modelo) já está fazendo Context Engineering — injetar experiência no system prompt é construção de contexto. O próximo passo é integrar mais profundamente os resultados de recuperação RAG com a injeção de experiência e o roteamento de modelo.

Multimodal RAG. No comércio exterior há muito conhecimento em formato visual — fotos de produtos, digitalizações de relatórios de inspeção de qualidade, fotos de listas de embalagem $TRAE_REF. O RAG atual só processa texto; essas informações visuais ou são transcritas manualmente em descrições textuais (com perda de informação) ou não conseguem ser recuperadas pela IA. O Multimodal RAG usa modelos de linguagem visual para gerar Embedding diretamente das imagens, permitindo que a IA "compreenda" fotos de produtos e as recupere. Isso tem grande valor para a nossa base de conhecimento de produtos e o módulo de inspeção de qualidade.

Agentic RAG. O RAG atual é de turno único — o usuário pergunta uma vez, o sistema busca uma vez. O Agentic RAG permite que a IA decida autonomamente se precisa de múltiplas buscas, buscas entre domínios, ou buscas de aprofundamento baseadas em resultados preliminares $TRAE_REF. Por exemplo, quando o usuário pergunta "como é a tendência de compras deste cliente nos últimos três anos comparada à média do setor", a IA pode precisar primeiro consultar os dados de pedidos do cliente, depois os dados de referência do setor, e em seguida fazer ela mesma a análise comparativa. Isso exige suporte de arquitetura de Agent, que ainda não temos, mas é uma direção clara — quando a busca de turno único não consegue atender a consultas complexas, o Agentic RAG é o caminho natural de evolução.

Conclusão

Três técnicas, um objetivo: levar a busca vetorial de "consegue buscar" para "busca com precisão".

Query Rewriting resolve o problema na entrada — o abismo entre a pergunta coloquial do usuário e a entrada de palavras-chave esperada pelo motor de busca. Hybrid Search resolve os pontos cegos da recuperação — a busca vetorial e a busca por palavras-chave têm cada uma suas limitações, e a fusão RRF faz com que os resultados das duas se complementem. Reranking resolve o viés na ordenação — alta similaridade vetorial não equivale a alta relevância de negócio, e o LLM faz a última filtragem semântica.

Com as três camadas empilhadas, a precisão de recuperação subiu de 68% para 82% (taxa de acerto top-1), com custo de cerca de 0,001-0,002 yuan por busca, e aumento de latência controlável. As três funcionalidades têm switches independentes, podendo ser ativadas ou desativadas conforme necessário.

Esse pipeline de aprimoramento não é um ponto final. O próximo estágio do RAG é Context Engineering — de "recuperar documentos" para "construir contexto", de "retornar resultados" para "entregar respostas". Já estamos a caminho.

Compartilhar este artigo

Comments

No comments yet. Be the first!