Przejdź do treści
cd /blog

Wielomodalne wyszukiwanie z fuzją: dobór właściwego retrievera do każdego zapytania

[Wyszukiwanie] [Architektura]

> Zapytanie w stylu „gdzie zdefiniowano parseConfig” potrzebuje innego wyszukiwania niż „jak działa uwierzytelnianie”. Maguyva klasyfikuje intencję, odpowiednio waży cztery tryby wyszukiwania i łączy wyniki za pomocą ważonej Reciprocal Rank Fusion.

Uwaga o historycznym projekcie: ten artykuł z kwietnia 2026 r. opisuje ówczesny projekt routingu, a nie obecne zachowanie domyślne. Poniższa korekta z września dotyczy wyłącznie twierdzenia pomiarowego. Aktualny routing, presety i jawne sterowanie modalnościami opisano na stronie Jak to działa.

Zapytanie wyszukiwania to nie jedna rzecz.

„gdzie zdefiniowano parseConfig” chce dokładnego symbolu — jednej precyzyjnej lokalizacji, szybko. „jak działa uwierzytelnianie” chce znaczenia — rozproszenia powiązanego kodu, które wyjaśnia koncept. „co się zepsuje, jeśli zmienię tę funkcję” chce grafu zależności. „znajdź ciąg ECONNREFUSED” chce dosłownego dopasowania, niczego sprytnego.

Grep jest świetny do dosłownych dopasowań i przydatny do części poszukiwań referencji, ale to nie graf zależności i nie rozumie znaczenia. Embeddingi pokrywają stronę semantyczną, ale są niewłaściwym narzędziem do dokładnych ciągów i analizy wpływu. Większość narzędzi do wyszukiwania kodu wybiera jeden silnik i zmusza każde zapytanie, by żyło z tym wyborem. Maguyva nie wybiera. Ustala, jakiego rodzaju pytanie zadałeś, a następnie miesza cztery retrievery w proporcji, na jaką to pytanie zasługuje.

Cztery tryby

Pod maską istnieją cztery niezależne sposoby na znalezienie kodu:

  • semantyczny — wyszukiwanie wektorowe na binarnych embeddingach Voyage; znajduje kod według znaczenia.
  • tekstowy — dopasowywanie trigramowe; znajduje literały, ciągi błędów, dokładne identyfikatory.
  • strukturalny — zapytania AST; znajduje definicje, sygnatury i konstrukty językowe.
  • grafowy — graf zależności; znajduje wywołujących, wywoływanych i zasięg wpływu.

Każdy jest silny w innej klasie pytań. Sztuka polega na tym, by zdecydować, jak bardzo ufać każdemu z nich dla zapytania, które masz przed sobą.

Klasyfikacja intencji

Zanim uruchomi się jakiekolwiek wyszukiwanie, lekki klasyfikator sortuje zapytanie do jednej z sześciu intencji, z wynikiem pewności. Jest celowo tani — uporządkowane heurystyki, pierwsze dopasowanie wygrywa — ponieważ działa na ścieżce krytycznej i dodaje tylko milisekundę lub dwie:

  • zaczyna się od def , class , func , import … → find_definition (pewność 0,95)
  • „who calls”, „usages of”, „references to” (pytania o wywołania, użycia i referencje) → find_references (0,90)
  • „impact”, „blast radius”, „what depends on” (wpływ, zasięg wpływu, co od tego zależy) → impact_analysis (0,90)
  • cytowany "string" lub token błędu jak traceback → exact_match (0,85–0,90)
  • identyfikator CamelCase lub snake_case → find_definition (0,60–0,80)
  • „how”, „why”, „explain”, „architecture” (pytania o sposób działania, przyczyny i architekturę) → understand_code (0,75)
  • nic nie pasuje → understand_code, niska pewność (0,40)

Każda intencja niesie profil wag rozłożony na cztery tryby. Oto prawdziwe liczby:

Intencja semantyczny tekstowy strukturalny (AST) grafowy
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

Więc „gdzie zdefiniowano parseConfig” mocno opiera się na AST (0,6). „jak działa uwierzytelnianie” opiera się na wektorach semantycznych (0,5). „co od tego zależy” to niemal wyłącznie graf (0,7). „znajdź ECONNREFUSED” to niemal wyłącznie trigram (0,9), z modelem embeddingów całkowicie wyłączonym — ponieważ podobieństwo semantyczne jest dokładnie niewłaściwym narzędziem dla dokładnego ciągu.

Szybka ścieżka i ścieżka fuzji

Gdy klasyfikator jest pewny — wynik ≥ 0,85 — a zapytanie jest zwyczajne, Maguyva całkowicie pomija fuzję i kieruje bezpośrednio do jednego dominującego trybu. „gdzie zdefiniowano X” nie potrzebuje czterech retrieverów; potrzebuje indeksu AST, natychmiast. Ta bezpośrednia ścieżka jest raportowana z powrotem jako fusion_strategy: "direct".

Wszystko niejednoznaczne przechodzi przez fuzję. Cztery (lub trzy, w domyślnym presecie) tryby uruchamiają się równolegle, każdy zwracając własną uszeregowaną listę, a my je łączymy.

Ważona Reciprocal Rank Fusion

Fuzja niejednorodnych retrieverów jest trudniejsza, niż się wydaje: podobieństwo kosinusowe 0,82, wynik trigramowy 137 i centralność grafu 0,004 nie są na tej samej skali, więc nie można ich po prostu dodać. Reciprocal Rank Fusion omija ten problem, odrzucając surowe wyniki i zachowując tylko rangę, jaką przypisał każdy silnik. Wkład wyniku z jednego trybu to:

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

gdzie rank to jego pozycja na liście danego trybu, a k to stała wygładzająca. Wkłady są sumowane po trybach dla każdego wyniku, który znalazł więcej niż jeden silnik — zgodność między retrieverami naturalnie unosi się na szczyt. Używamy k = 40 w domyślnym presecie i 60 w thorough (quick działa wyłącznie semantycznie, więc fuzja nigdy się tam nie włącza). Oryginalna praca o RRF wylądowała na k = 60 dla wyszukiwania ogólnego przeznaczenia; nasze ustawienie domyślne nadaje nieco większą wagę wynikom zajmującym wysokie pozycje w kilku trybach — i nie polecamy ręcznego dostrajania tego.

Ponadto wyniki niosą boost związany z ważnością w grafie. Hub — funkcja, na której opiera się cała baza kodu — powinien wyprzedzać mało znany węzeł liściowy nawet przy tej samej trafności tekstowej, więc mnożymy każdy wkład przez:

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

Centralność pochodzi z wstępnie obliczonych metryk PageRank/stopnia w pipeline, a boost jest ograniczony do 1,5×, żeby popularna funkcja nie mogła całkowicie zagłuszyć bardziej trafnej, mniej znanej funkcji. Na koniec degradujemy wyniki ze ścieżek vendor, build i archiwalnych oraz deduplikujemy do najlepszego fragmentu na plik.

Co wciąż jest niedoskonałe

Klasyfikator intencji to zbiór wyrażeń regularnych, nie wytrenowany model. Obsługuje typowe formy zapytań za pomocą heurystyk, a niejednoznaczne zapytanie wraca do understand_code i mieszanki z przewagą semantyki. Wcześniejsza wersja tego wpisu przedstawiała spadek odsetka wyszukiwań bez wyników z około 15% do poniżej 5% jako osiągnięty. Propozycja z grudnia 2025 r. zawierała w rzeczywistości szacunkowy punkt wyjścia i cel; nie dostarczono wspierającego zbioru zapytań ani raportu pomiarowego. Wycofujemy twierdzenie o osiągnięciu tej poprawy; zobacz dowody źródłowe i korektę. Nie zastąpiliśmy klasyfikatora wytrenowanym modelem, ponieważ tania wersja jest szybka i wystarczająco dobra do zamierzonej roli routingu, a klasyfikator, który myli się z pełnym przekonaniem, jest gorszy niż uczciwy fallback. Same wagi są ręcznie dobranymi wartościami a priori, a nie wynikiem uczenia na danych o kliknięciach, których nie zbieramy.

Zadawaj pytania zamiast wybierać narzędzia

Agent nie powinien musieć wiedzieć, czy sięgnąć po grep, embeddingi, czy graf wywołań — powinien zadać swoje pytanie prostymi słowami i uzyskać właściwą odpowiedź. Fuzja wielomodalna jest tym, co pozwala, by find_symbol, wyszukiwanie semantyczne i analiza zależności były dostępne przez jeden interfejs zapytań: system odczytuje kształt pytania i po cichu składa dla niego właściwy retriever. Model, który ocenia embeddingi, ma znaczenie, ale tak samo ważne jest, by wiedzieć, kiedy nie ich używać. Dobór właściwego narzędzia do każdego zapytania to odrębny wymiar jakości i wolelibyśmy być za niego odpowiedzialni, niż przerzucać go na wywołującego.

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

Powiązane treści

Więcej z dziennika budowy Maguyva