Přeskočit na obsah
cd /blog

Multi-modální fúzní vyhledávání: pro každý dotaz ten správný retriever

[Vyhledávání] [Architektura]

> Dotaz jako „kde je definovaný parseConfig“ chce jiné vyhledávání než „jak funguje autentizace“. Maguyva klasifikuje záměr, podle toho nastaví váhy čtyř vyhledávacích modalit a výsledky sloučí pomocí vážené Reciprocal Rank Fusion.

Poznámka k historickému návrhu: tento článek z dubna 2026 popisuje tehdejší návrh směrování, nikoli současné výchozí chování. Níže uvedená zářijová oprava se týká pouze tvrzení o měření. Aktuální směrování, předvolby a explicitní nastavení modalit najdete na stránce Jak to funguje.

Vyhledávací dotazy mají různé potřeby.

„kde je definovaný parseConfig“ chce přesný symbol — jedno přesné místo, rychle. „jak funguje autentizace“ chce význam — rozptýlený související kód, který vysvětluje koncept. „co se rozbije, když změním tuhle funkci“ chce graf závislostí. „najdi řetězec ECONNREFUSED“ chce doslovnou shodu, nic chytrého.

Grep je výborný na doslovné shody a užitečný při některých pátráních po referencích, ale není to graf závislostí a nerozumí významu. Embeddingy pokrývají sémantickou stránku, ale jsou špatný nástroj na přesné řetězce a analýzu dopadu. Většina nástrojů pro vyhledávání v kódu si vybere jeden engine a nechá s tou volbou žít každý dotaz. Maguyva se neomezuje na jeden engine. Zjistí, jaký typ otázky jste položili, a pak smísí čtyři retrievery v poměru, jaký si daná otázka zaslouží.

Čtyři modality

Pod kapotou existují čtyři nezávislé způsoby, jak najít kód:

  • sémantický — vektorové vyhledávání nad binárními Voyage embeddingy; hledá kód podle významu.
  • textový — trigramová shoda; hledá literály, chybové řetězce, přesné identifikátory.
  • strukturální — dotazy AST; hledá definice, signatury a jazykové konstrukce.
  • grafový — graf závislostí; hledá volající, volané a rozsah dopadu.

Každý je silný na jiné třídě otázek. Trik je rozhodnout, nakolik každému z nich věřit pro dotaz, který máte před sebou.

Klasifikace záměru

Než proběhne jakékoliv vyhledávání, odlehčený klasifikátor zařadí dotaz do jednoho ze šesti záměrů, s mírou jistoty. Je záměrně levný — seřazené heuristiky, vyhrává první shoda — protože běží na hot path a přidává jen milisekundu nebo dvě:

  • začíná na def , class , func , import … → find_definition (jistota 0,95)
  • „who calls“, „usages of“, „references to“ (kdo volá, použití, odkazy na) → find_references (0,90)
  • „impact“, „blast radius“, „what depends on“ (dopad, rozsah dopadu, co na tom závisí) → impact_analysis (0,90)
  • "string" v uvozovkách nebo chybový token jako traceback → exact_match (0,85–0,90)
  • identifikátor ve tvaru CamelCase nebo snake_case → find_definition (0,60–0,80)
  • „how“, „why“, „explain“, „architecture“ (jak, proč, vysvětli, architektura) → understand_code (0,75)
  • nic nesedí → understand_code, nízká jistota (0,40)

Každý záměr nese profil vah napříč čtyřmi modalitami. Toto jsou skutečná čísla:

Záměr sémantický textový strukturální (AST) grafový
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

Takže „kde je definovaný parseConfig“ se výrazně opírá o AST (0,6). „jak funguje autentizace“ se opírá o sémantické vektory (0,5). „co na tomhle závisí“ je skoro celé grafové (0,7). „najdi ECONNREFUSED“ je skoro celé trigramové (0,9), embedding model je úplně vypnutý — protože sémantická podobnost je přesně ten špatný nástroj na přesný řetězec.

Rychlá cesta a fúzovaná cesta

Když si je klasifikátor jistý — skóre ≥ 0,85 — a dotaz je běžný, Maguyva fúzi úplně přeskočí a routuje přímo na jednu dominantní modalitu. „kde je definované X“ nepotřebuje čtyři retrievery; potřebuje AST index, hned. Tahle přímá cesta se hlásí zpátky jako fusion_strategy: "direct".

Všechno nejednoznačné prochází fúzí. Čtyři (nebo tři, na výchozím presetu) modality běží paralelně, každá vrací svůj vlastní seřazený seznam, a my je kombinujeme.

Vážená Reciprocal Rank Fusion

Fúzovat heterogenní retrievery je těžší, než to zní: kosinová podobnost 0,82, trigramové skóre 137 a grafová centralita 0,004 nejsou na stejné škále, takže je nemůžete jen sečíst. Reciprocal Rank Fusion tenhle problém obchází tím, že zahodí syrová skóre a ponechá si jen pořadí, které danému výsledku přidělil každý engine. Příspěvek výsledku z jedné modality je:

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

kde rank je jeho pozice v seznamu dané modality a k je vyhlazovací konstanta. Příspěvky se sčítají napříč modalitami pro každý výsledek, který našel víc než jeden engine — výsledky, na kterých se retrievery shodnou, přirozeně postoupí výš. Používáme k = 40 na výchozím presetu a 60 na thorough (quick běží čistě sémanticky, takže se tam fúze nikdy nezapojí). Původní práce o RRF přistála na k = 60 pro obecné vyhledávání; naše výchozí nastavení o něco více zvýhodňuje přední pozice, což dává shodě mezi modalitami na nejvyšších pozicích trochu větší váhu — a nedoporučujeme to ručně dolaďovat.

Nad tím vším výsledky nesou ještě boost za grafovou důležitost. Hub — funkce, o kterou se opírá celá kódová základna — by měla předstihnout málo známý listový uzel i při stejné textové relevanci, takže každý příspěvek násobíme:

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

Centralita pochází z předpočítaných metrik PageRank/stupně z pipeline a boost je oříznutý na 1,5×, aby populární funkce úplně nepohřbila relevantnější, ale obskurnější výsledek. Nakonec degradujeme výsledky z cest vendor, build a archive a deduplikujeme na nejlepší chunk na soubor.

Co je pořád nedokonalé

Klasifikátor záměru je sada regulárních výrazů, nikoli naučený model. Běžné podoby dotazů zpracovává pomocí heuristik a nejednoznačný dotaz přechází na understand_code a směs upřednostňující sémantiku. Starší verze tohoto článku popisovala pokles podílu dotazů bez výsledků z přibližně 15 % pod 5 % jako dosažený. Návrh z prosince 2025 však ve skutečnosti uváděl odhad výchozí hodnoty a cíl; podpůrná sada dotazů ani záznam měření nejsou k dispozici. Tvrzení o dosaženém zlepšení stahujeme; viz zdrojové důkazy a oprava. Klasifikátor jsme nenahradili trénovaným modelem, protože levná verze je rychlá a pro zamýšlené směrování dostatečná, a protože chybný, ale sebejistý klasifikátor je horší než otevřený návrat k výchozí variantě. Samotné váhy jsou ručně zvolené předpoklady, nikoli hodnoty naučené z údajů o kliknutí, které nesbíráme.

Položte otázku, výběr nástroje nechte systému

Agent by neměl muset vědět, jestli sáhnout po grepu, embeddingech, nebo grafu volání — měl by položit svou otázku prostými slovy a dostat správnou odpověď. Multi-modální fúze je to, co umožňuje find_symbol, sémantickému vyhledávání a analýze závislostí sedět za jedním dotazovacím rozhraním: systém přečte tvar otázky a tiše sestaví ten správný retriever. Na modelu, který embeddingy skóruje, záleží, ale záleží i na tom, kdy je nepoužít. Vybrat pro každý dotaz správný nástroj je svůj vlastní druh kvality, a raději ho vlastníme sami, než abychom ho přehazovali na volajícího.

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

Související čtení

Další z vývojového deníku Maguyva