# Monimodaalinen fuusiohaku: oikean hakukoneen valinta jokaiselle kyselylle

Canonical source: https://maguyva.ai/fi/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

> Kysely kuten "missä parseConfig on määritelty" haluaa erilaisen haun kuin "miten todennus toimii". Maguyva luokittelee tarkoituksen, painottaa neljää hakumodaliteettia sen mukaisesti ja yhdistää tulokset painotetulla Reciprocal Rank Fusionilla.

> Huomautus historiallisesta suunnittelusta: tämä huhtikuun 2026 artikkeli kuvaa silloista reitityssuunnitelmaa, ei nykyistä oletustoimintaa. Alla oleva syyskuun korjaus koskee vain mittausväitettä. Nykyinen reititys, esiasetukset ja hakutapojen suorat valinnat esitellään sivulla [Näin se toimii](https://maguyva.ai/fi/docs/how-it-works).

Hakukysely ei ole yksi asia.

"missä `parseConfig` on määritelty" haluaa tarkan symbolin — yhden täsmällisen sijainnin, nopeasti. "miten todennus toimii" haluaa merkityksen — liittyvän koodin levittäytymän, joka selittää käsitteen. "mitä hajoaa, jos muutan tätä funktiota" haluaa riippuvuusgraafin. "etsi merkkijono `ECONNREFUSED`" haluaa kirjaimellisen osuman, ei mitään nokkelaa.

Grep on erinomainen kirjaimellisiin osumiin ja hyödyllinen joissakin viittausmetsästyksissä, mutta se ei ole riippuvuusgraafi eikä ymmärrä merkitystä. Upotukset kattavat semanttisen puolen, mutta ne ovat väärä työkalu tarkoille merkkijonoille ja vaikutusanalyysille. Useimmat koodihakutyökalut valitsevat yhden moottorin ja pakottavat jokaisen kyselyn elämään sen valinnan kanssa. Maguyva ei sitoudu yhteen moottoriin. Se selvittää, minkälainen kysymys esitit, ja sekoittaa sitten neljä hakukonetta suhteessa, jonka kysymys ansaitsee.

## Neljä modaliteettia

Konepellin alla on neljä riippumatonta tapaa löytää koodia:

- **semanttinen** — vektorihaku Voyage-binääriupotusten yli; löytää koodia merkityksen perusteella.
- **teksti** — trigrammivastaavuus; löytää literaalit, virhemerkkijonot, tarkat tunnisteet.
- **rakenteellinen** — AST-kyselyt; löytää määrittelyt, allekirjoitukset ja kielirakenteet.
- **graafi** — riippuvuusgraafi; löytää kutsujat, kutsuttavat ja vaikutusalueen.

Jokainen on vahva erilaisessa kysymysluokassa. Temppu on päättää, kuinka paljon kuhunkin hakutapaan luotetaan käsiteltävän kyselyn kohdalla.

## Tarkoituksen luokittelu

Ennen minkään haun ajamista kevyt luokitin lajittelee kyselyn yhteen kuudesta tarkoituksesta, luottamuspisteellä. Se on tarkoituksella halpa — järjestettyjä heuristiikkoja, ensimmäinen osuma voittaa — koska se ajetaan usein käytetyllä suorituspolulla ja lisää vain millisekunnin tai pari:

- alkaa sanoilla `def `, `class `, `func `, `import `… → **find_definition** (luottamus 0.95)
- "who calls", "usages of", "references to" → **find_references** (0.90)
- "impact", "blast radius", "what depends on" → **impact_analysis** (0.90)
- lainausmerkeissä oleva `"string"` tai virhetunniste kuten `traceback` → **exact_match** (0.85–0.90)
- `CamelCase`- tai `snake_case`-tunniste → **find_definition** (0.60–0.80)
- "how", "why", "explain", "architecture" → **understand_code** (0.75)
- mikään ei täsmää → **understand_code**, matala luottamus (0.40)

Jokaisella tarkoituksella on painoprofiili neljän modaliteetin yli. Nämä ovat todelliset luvut:

| Tarkoitus | semanttinen | teksti | rakenteellinen (AST) | graafi |
|---|---|---|---|---|
| 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 |

Joten "missä `parseConfig` on määritelty" nojaa vahvasti ASTiin (0.6). "miten todennus toimii" nojaa semanttisiin vektoreihin (0.5). "mikä on riippuvainen tästä" on lähes kokonaan graafia (0.7). "etsi `ECONNREFUSED`" on lähes kokonaan trigrammia (0.9), upotusmallin ollessa kokonaan pois päältä — koska semanttinen samankaltaisuus on juuri väärä työkalu tarkalle merkkijonolle.

## Nopea polku ja yhdistetty polku

Kun luokitin on varma — pisteet ≥ 0.85 — ja kysely on tavallinen, Maguyva ohittaa fuusion kokonaan ja reitittää suoraan yhteen hallitsevaan modaliteettiin. "missä X on määritelty" ei tarvitse neljää hakukonetta; se tarvitsee AST-indeksin, heti. Tuo suora polku raportoidaan takaisin nimellä `fusion_strategy: "direct"`.

Kaikki epäselvä kulkee fuusion läpi. Neljä (tai kolme, oletusesiasetuksella) modaliteettia ajetaan rinnakkain, kukin palauttaen oman järjestetyn listansa, ja yhdistämme ne.

## Painotettu Reciprocal Rank Fusion

Heterogeenisten hakukoneiden yhdistäminen on vaikeampaa kuin miltä kuulostaa: kosinisamankaltaisuus 0.82 ja trigrammipisteet 137 ja graafin keskeisyys 0.004 eivät ole samalla asteikolla, joten niitä ei voi vain laskea yhteen. Reciprocal Rank Fusion kiertää ongelman heittämällä pois raakapisteet ja säilyttämällä vain kunkin moottorin antaman **sijoituksen**. Tuloksen panos yhdestä modaliteetista on:

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

jossa `rank` on sen sijainti kyseisen modaliteetin listalla ja `k` on tasoituskonstantti. Panokset summataan yli modaliteettien mille tahansa tulokselle, jonka useampi kuin yksi moottori löysi — hakukoneiden välinen yksimielisyys nousee luonnollisesti pintaan. Käytämme **k = 40** oletusesiasetuksella ja 60 `thorough`:ssä (`quick` ajaa vain semanttisen haun, joten fuusio ei koskaan käynnisty siellä). Alkuperäinen RRF-työ päätyi arvoon k = 60 yleiskäyttöiselle haulle; oletusasetuksemme painottaa hieman enemmän tuloksia, jotka sijoittuvat korkealle useassa modaliteetissa — emmekä suosittele sen käsivaraista säätämistä.

Tämän lisäksi tulokset kantavat **graafin tärkeyden korotusta**. Solmupisteen — funktion, johon koko koodikanta nojaa — pitäisi sijoittua vähemmän tunnetun lehtisolmun edelle jopa samalla tekstuaalisella relevanssilla, joten kerromme jokaisen panoksen luvulla:

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

Keskeisyys tulee putken esilasketuista PageRank/aste-metriikoista, ja korotus rajataan 1.5×:ään, jotta suosittu funktio ei voi täysin peittää alleen relevantimpaa, vähemmän tunnettua funktiota. Lopuksi alennamme tuloksia vendor-, build- ja arkistopoluista ja poistamme duplikaatit siten, että kustakin tiedostosta jää paras katkelma.

## Mikä on yhä epätäydellistä

Aikeen luokittelija on joukko säännöllisiä lausekkeita, ei koulutettu malli. Se käsittelee tavallisia kyselymuotoja heuristiikoilla, ja monitulkintainen kysely ohjautuu vaihtoehtoon `understand_code` sekä semantiikkaa painottavaan yhdistelmään. Tämän kirjoituksen aiempi versio kuvasi tuloksettomien hakujen osuuden laskun noin 15 prosentista alle 5 prosenttiin saavutetuksi. Joulukuun 2025 ehdotuksessa esitettiin todellisuudessa arvioitu lähtötaso ja tavoite; tueksi ei ole toimitettu kyselyjoukkoa tai mittausraporttia. Perumme väitteen saavutetusta parannuksesta; katso [lähdeaineisto ja korjaus](https://maguyva.ai/evidence/search-quality.md). Emme ole korvanneet luokittelijaa koulutetulla mallilla, koska edullinen versio on nopea ja riittävä sille tarkoitettuun reititystehtävään ja koska virheellinen mutta itsevarma luokittelija on huonompi kuin rehellinen oletusvaihtoehto. Painot ovat käsin valittuja ennakko-oletuksia, eivät opittuja klikkausdatasta, jota emme kerää.

## Esitä kysymys ilman työkalun valintaa

Agentin ei pitäisi joutua tietämään, tarttuuko grepiin, upotuksiin vai kutsugraafiin — sen pitäisi esittää kysymyksensä yksinkertaisin sanoin ja saada oikea vastaus. Monimodaalinen fuusio on se, mikä antaa `find_symbol`:n, semanttisen haun ja riippuvuusanalyysin istua yhden kyselyrajapinnan takana: järjestelmä lukee kysymyksen muodon ja kokoaa hiljaa oikean hakukoneen sitä varten. Malli, joka pisteyttää upotukset, merkitsee, mutta niin merkitsee myös tietäminen, milloin *ei* käyttää niitä. Oikean työkalun valitseminen jokaiselle kyselylle on omanlaistaan laatua, ja se on sellaista, jonka mieluummin omistamme kuin työnnämme kutsujalle.

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