Multi-modální fúzní vyhledávání: pro každý dotaz ten správný retriever
> 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 jakotraceback→ exact_match (0,85–0,90)- identifikátor ve tvaru
CamelCasenebosnake_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
Proč jsme upgradovali vyhledávání v kódu na voyage-4-large_
Přesunuli jsme naše embeddingy kódu na voyage-4-large — aktuálně na špici veřejného žebříčku RTEB pro retrieval kódu. Upřímná verze: kompromis, který děláme, co skutečně indexujeme a proč platíme za prémiové embeddingy.
Observabilita agentů: hooks, Alloy a Grafana_
Zapojili jsme Claude Code a Codex do jednoho Grafana stacku pomocí OpenTelemetry a Alloy a pak jsme pomocí trace a logů dohledávali a opravovali problémy v chování agentů přímo u zdroje.
Mining smyčky: jak se ze změn stává institucionální paměť_
Git commity se mění na strukturované záznamy changelogu a architektonická rozhodnutí, a ty se pak vrací zpátky do AI agentů jako dotazovatelná institucionální paměť.