Saltar al contenido
cd /blog

Búsqueda por fusión multimodal: eligiendo el recuperador correcto para cada consulta

[Búsqueda] [Arquitectura]

> Una consulta como 'dónde está definido parseConfig' necesita una búsqueda distinta a 'cómo funciona la autenticación'. Maguyva clasifica la intención, pondera en consecuencia cuatro modalidades de recuperación, y fusiona los resultados con Reciprocal Rank Fusion ponderada.

Nota sobre el diseño histórico: este artículo de abril de 2026 describe el diseño de enrutamiento de entonces, no el comportamiento predeterminado actual. La corrección de septiembre que figura más abajo solo trata una afirmación sobre mediciones. Para conocer el enrutamiento, los preajustes y los controles explícitos de modalidades actuales, consulte Cómo funciona.

Una consulta de búsqueda no es una sola cosa.

«dónde está definido parseConfig» quiere un símbolo exacto — una ubicación precisa, rápido. «cómo funciona la autenticación» quiere significado — el conjunto de código relacionado que explica un concepto. «qué se rompe si cambio esta función» quiere el grafo de dependencias. «encontrar la cadena ECONNREFUSED» quiere una coincidencia literal, nada elaborado.

Grep es excelente para coincidencias literales y útil para algunas búsquedas de referencias, pero no es un grafo de dependencias y no entiende el significado. Los embeddings cubren el lado semántico, pero son la herramienta equivocada para cadenas exactas y análisis de impacto. La mayoría de las herramientas de búsqueda de código eligen un solo motor y hacen que cada consulta viva con esa elección. Maguyva no elige. Determina qué tipo de pregunta hiciste y luego combina cuatro recuperadores en la proporción que esa pregunta merece.

Cuatro modalidades

Por debajo hay cuatro formas independientes de encontrar código:

  • semántica — búsqueda vectorial sobre embeddings binarios de Voyage; encuentra código por significado.
  • texto — coincidencia por trigramas; encuentra literales, cadenas de error, identificadores exactos.
  • estructural — consultas AST; encuentra definiciones, firmas y construcciones del lenguaje.
  • grafo — el grafo de dependencias; encuentra quién llama, a quién se llama, y el radio de impacto.

Cada una es fuerte en una clase distinta de pregunta. El truco está en decidir cuánto confiar en cada una para la consulta que tienes delante.

Clasificación de intención

Antes de que corra cualquier recuperación, un clasificador ligero ordena la consulta en una de seis intenciones, con un puntaje de confianza. Es deliberadamente barato — heurísticas ordenadas, gana la primera coincidencia — porque corre en la ruta crítica y solo agrega uno o dos milisegundos:

  • empieza con def , class , func , import … → find_definition (confianza 0.95)
  • «who calls» (quién llama), «usages of» (usos de), «references to» (referencias a) → find_references (0.90)
  • «impact» (impacto), «blast radius» (radio de impacto), «what depends on» (qué depende de) → impact_analysis (0.90)
  • un "string" entre comillas o un token de error como traceback → exact_match (0.85–0.90)
  • un identificador CamelCase o snake_case → find_definition (0.60–0.80)
  • «how» (cómo), «why» (por qué), «explain» (explica), «architecture» (arquitectura) → understand_code (0.75)
  • nada coincide → understand_code, confianza baja (0.40)

Cada intención lleva un perfil de ponderación entre las cuatro modalidades. Estos son los números reales:

Intención semántica texto estructural (AST) grafo
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

Así que «dónde está definido parseConfig» se apoya fuerte en AST (0.6). «cómo funciona la autenticación» se apoya en vectores semánticos (0.5). «qué depende de esto» es casi todo grafo (0.7). «encontrar ECONNREFUSED» es casi todo trigramas (0.9), con el modelo de embeddings completamente apagado — porque la similitud semántica es exactamente la herramienta equivocada para una cadena exacta.

La ruta rápida y la ruta fusionada

Cuando el clasificador tiene confianza — puntaje ≥ 0.85 — y la consulta es normal, Maguyva se salta la fusión por completo y enruta directo a la única modalidad dominante. «dónde está definido X» no necesita cuatro recuperadores; necesita el índice AST, ya. Esa ruta directa se reporta como fusion_strategy: "direct".

Todo lo ambiguo pasa por la fusión. Las cuatro modalidades (o tres, en el preajuste predeterminado) corren en paralelo, cada una devolviendo su propia lista clasificada, y las combinamos.

Reciprocal Rank Fusion ponderada

Fusionar recuperadores heterogéneos es más difícil de lo que suena: una similitud coseno de 0.82, un puntaje de trigramas de 137 y una centralidad de grafo de 0.004 no están en la misma escala, así que no puedes simplemente sumarlos. Reciprocal Rank Fusion evita el problema descartando los puntajes crudos y conservando solo la posición que cada motor asignó. La contribución de un resultado desde una modalidad es:

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

donde rank es su posición en la lista de esa modalidad y k es una constante de suavizado. Las contribuciones se suman entre modalidades para cualquier resultado que más de un motor encontró — el acuerdo entre recuperadores flota naturalmente hacia arriba. Usamos k = 40 en el preajuste predeterminado y 60 en thorough (quick corre solo en modo semántico, así que la fusión nunca entra en juego ahí). El trabajo original de RRF llegó a k = 60 para recuperación de propósito general; nuestro valor predeterminado acentúa un poco más las primeras posiciones, lo que le da al acuerdo entre modalidades sobre los resultados mejor clasificados un poco más de peso — y no recomendamos ajustarlo a mano.

Además de eso, los resultados llevan un impulso de importancia de grafo. Un hub — una función de la que depende toda la base de código — debería superar a un nodo hoja poco conocido incluso con la misma relevancia textual, así que multiplicamos cada contribución por:

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

La centralidad viene de las métricas precalculadas de PageRank/grado del pipeline, y el impulso está limitado a 1.5× para que una función popular no pueda enterrar por completo a una más relevante pero poco conocida. Finalmente degradamos los resultados de rutas de vendor, build y archivo, y deduplicamos al mejor fragmento por archivo.

Lo que todavía es imperfecto

El clasificador de intención es un conjunto de expresiones regulares, no un modelo entrenado. Maneja las formas habituales de consulta mediante heurísticas, y una consulta ambigua recurre a understand_code y a una combinación con mayor peso semántico. Una versión anterior de este artículo describía como conseguida una reducción de la tasa de consultas sin resultados de aproximadamente el 15% a menos del 5%. En realidad, la propuesta de diciembre de 2025 indicaba una tasa inicial estimada y un objetivo; no se proporciona un conjunto de consultas ni un registro de medición que lo respalde. Retiramos esa afirmación de mejora conseguida; consulte las evidencias de origen y la corrección. No hemos sustituido el clasificador por un modelo entrenado porque la versión económica es rápida y suficiente para la función de enrutamiento prevista, y porque un clasificador equivocado pero seguro de sí mismo es peor que una alternativa predeterminada honesta. Los pesos son supuestos previos elegidos a mano, no aprendidos de datos de clics que no recopilamos.

Pregunta lo que necesitas, no la herramienta

Un agente no debería tener que saber si recurrir a grep, a embeddings o al grafo de llamadas — debería hacer su pregunta en términos simples y obtener la respuesta correcta. La fusión multimodal es lo que permite que find_symbol, la búsqueda semántica y el análisis de dependencias convivan detrás de una sola interfaz de consulta: el sistema lee la forma de la pregunta y ensambla en silencio el recuperador correcto para ella. El modelo que puntúa los embeddings importa, pero también importa saber cuándo no usarlos. Elegir la herramienta correcta para cada consulta es su propio tipo de calidad, y es una que preferimos asumir nosotros en lugar de delegarla a quien hace la llamada.

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

Lectura relacionada

Más del registro de build de Maguyva