Pular para o conteúdo
cd /blog

Busca com Fusão Multimodal: Escolhendo o Retriever Certo Para Cada Consulta

[Busca][Arquitetura]

> Uma consulta como 'onde parseConfig é definido' quer um tipo de busca diferente de 'como funciona a autenticação'. O Maguyva classifica a intenção, pondera quatro modalidades de retrieval de acordo, e funde os resultados com Reciprocal Rank Fusion ponderada.

Uma consulta de busca não é uma coisa só.

“onde parseConfig é definido” quer um símbolo exato — um local preciso, rápido. “como funciona a autenticação” quer significado — o conjunto espalhado de código relacionado que explica um conceito. “o que quebra se eu mudar esta função” quer o grafo de dependências. “encontre a string ECONNREFUSED” quer uma correspondência literal, nada sofisticado.

O grep é excelente para correspondências literais e útil para algumas caças a referências, mas não é um grafo de dependências e não entende significado. Embeddings cobrem o lado semântico, mas são a ferramenta errada para strings exatas e análise de impacto. A maioria das ferramentas de busca de código escolhe um único motor e faz toda consulta conviver com essa escolha. O Maguyva não escolhe. Ele descobre que tipo de pergunta você fez, e então combina quatro retrievers na proporção que essa pergunta merece.

Quatro modalidades

Por baixo dos panos, existem quatro formas independentes de encontrar código:

  • semantic — busca vetorial sobre embeddings binários da Voyage; encontra código por significado.
  • text — correspondência de trigramas; encontra literais, strings de erro, identificadores exatos.
  • structural — queries de AST; encontra definições, assinaturas e construções da linguagem.
  • graph — o grafo de dependências; encontra chamadores, chamados e raio de impacto.

Cada um é forte em uma classe diferente de pergunta. O truque é decidir o quanto confiar em cada um para a consulta que está na sua frente.

Classificação de intenção

Antes de qualquer retrieval rodar, um classificador leve ordena a consulta em uma de seis intenções, com uma pontuação de confiança. É deliberadamente barato — heurísticas ordenadas, a primeira correspondência vence — porque roda no caminho crítico e adiciona apenas um ou dois milissegundos:

  • começa com def , class , func , import … → find_definition (confiança 0,95)
  • “quem chama”, “usos de”, “referências a” → find_references (0,90)
  • “impacto”, “raio de impacto”, “o que depende de” → impact_analysis (0,90)
  • um "string" entre aspas ou um token de erro como tracebackexact_match (0,85–0,90)
  • um identificador CamelCase ou snake_casefind_definition (0,60–0,80)
  • “como”, “por que”, “explique”, “arquitetura” → understand_code (0,75)
  • nada corresponde → understand_code, baixa confiança (0,40)

Cada intenção carrega um perfil de peso entre as quatro modalidades. Estes são os números reais:

Intenção semantic text structural (AST) graph
find_definition 0,2 0,1 0,6 0,1
find_references 0,1 0,2 0,2 0,5
understand_code 0,5 0,2 0,2 0,1
find_similar 0,4 0,3 0,2 0,1
impact_analysis 0,1 0,1 0,1 0,7
exact_match 0,0 0,9 0,1 0,0

Então “onde parseConfig é definido” se apoia fortemente em AST (0,6). “como funciona a autenticação” se apoia em vetores semânticos (0,5). “o que depende disso” é quase todo graph (0,7). “encontre ECONNREFUSED” é quase todo trigrama (0,9), com o modelo de embedding completamente desligado — porque similaridade semântica é exatamente a ferramenta errada para uma string exata.

O caminho rápido, e o caminho fundido

Quando o classificador está confiante — pontuação ≥ 0,85 — e a consulta é normal, o Maguyva pula a fusão por completo e roteia direto para a única modalidade dominante. “onde X é definido” não precisa de quatro retrievers; precisa do índice de AST, agora. Esse caminho direto é reportado de volta como fusion_strategy: "direct".

Tudo que é ambíguo passa pela fusão. As quatro (ou três, no preset padrão) modalidades rodam em paralelo, cada uma retornando sua própria lista ranqueada, e nós as combinamos.

Reciprocal Rank Fusion Ponderada

Fundir retrievers heterogêneos é mais difícil do que parece: uma similaridade de cosseno de 0,82, uma pontuação de trigrama de 137 e uma centralidade de grafo de 0,004 não estão na mesma escala, então você não pode simplesmente somá-las. O Reciprocal Rank Fusion contorna o problema descartando as pontuações brutas e mantendo apenas o rank que cada motor atribuiu. A contribuição de um resultado vinda de uma modalidade é:

contribution = weight × 1 / (k + rank + 1)

onde rank é a posição dele na lista daquela modalidade e k é uma constante de suavização. As contribuições são somadas entre modalidades para qualquer resultado que mais de um motor encontrou — a concordância entre retrievers naturalmente sobe ao topo. Usamos k = 40 no preset padrão e 60 em thorough (quick roda apenas com semantic, então a fusão nunca entra em ação ali). O trabalho original de RRF chegou a k = 60 para retrieval de propósito geral; nosso padrão é ligeiramente mais afiado, o que dá um pouco mais de peso à concordância entre modalidades bem ranqueadas — e não recomendamos ajustá-lo manualmente.

Além disso, os resultados carregam um boost de importância de grafo. Um hub — uma função em que todo o codebase se apoia — deve superar em ranking uma folha obscura mesmo com a mesma relevância textual, então multiplicamos cada contribuição por:

boost = min(1 + 0.3 × ln(1 + centrality), 1.5)

A centralidade vem das métricas pré-computadas de PageRank/grau do pipeline, e o boost é limitado a 1,5× para que uma função popular não consiga sepultar completamente uma obscura mais relevante. Por fim, rebaixamos resultados de caminhos de vendor, build e arquivo, e removemos duplicatas mantendo o melhor chunk por arquivo.

O que ainda é imperfeito

O classificador de intenção é uma pilha de regexes, não um modelo aprendido. Ele cobre bem os formatos comuns de consulta — a decisão que o introduziu registrou a taxa de resultado zero caindo de aproximadamente 15% para menos de 5% — mas é heurístico, e uma consulta genuinamente ambígua cai em understand_code e uma combinação inclinada ao semantic. Esse é um padrão seguro, não um esperto. Não o substituímos por um classificador treinado porque a versão barata é rápida e boa o suficiente, e porque um classificador errado-mas-confiante é pior do que um fallback honesto. Os próprios pesos são priors escolhidos à mão, não aprendidos a partir de dados de clique que não coletamos.

Faça a Pergunta, Não a Ferramenta

Um agente não deveria precisar saber se deve recorrer ao grep, a embeddings ou ao call graph — ele deveria fazer a sua pergunta em termos simples e obter a resposta certa. A fusão multimodal é o que permite que find_symbol, busca semântica e análise de dependências fiquem por trás de uma única superfície de consulta: o sistema lê o formato da pergunta e silenciosamente monta o retriever certo para ela. O modelo que pontua os embeddings importa, mas também importa saber quando não usá-los. Escolher a ferramenta certa para cada consulta é um tipo de qualidade em si, e é algo que preferimos assumir a empurrar para quem chama.

// you bring the question. it brings the tools.

Leituras relacionadas

Mais do log de build do Maguyva