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

Canonical source: https://maguyva.ai/cs/blog/multi-modal-fusion-search

License: text under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/); code samples under [MIT-0](https://opensource.org/license/mit-0); the Maguyva name, logos, brand assets and other code are not covered. Details: [maguyva.ai/license](https://maguyva.ai/license).

Date: 2026-04-15 · Author: Maguyva Team

> 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](https://maguyva.ai/cs/docs/how-it-works).

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:

```text
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:

```text
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](https://maguyva.ai/evidence/search-quality.md). 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.`
