Мультимодальний пошук зі злиттям: обираємо правильний ретрівер для кожного запиту
> Запит на кшталт «де визначено parseConfig» потребує іншого пошуку, ніж «як працює автентифікація». Maguyva класифікує намір, відповідно зважує чотири режими пошуку і зливає результати за допомогою зваженого Reciprocal Rank Fusion.
Примітка про історичну архітектуру: ця стаття від квітня 2026 року описує тогочасну архітектуру маршрутизації, а не поточну поведінку за замовчуванням. Вересневе виправлення нижче стосується лише твердження про вимірювання. Про поточну маршрутизацію, попередньо задані налаштування та явне керування модальностями див. Як це працює.
Пошуковий запит — це не одна річ.
«де визначено parseConfig» хоче точний символ — одне точне місце, швидко. «як працює автентифікація» хоче сенс — розкидані пов’язані фрагменти коду, що пояснюють концепцію. «що зламається, якщо я зміню цю функцію» хоче граф залежностей. «знайди рядок ECONNREFUSED» хоче буквальний збіг, нічого хитрого.
Grep чудовий для буквальних збігів і корисний для деяких пошуків посилань, але це не граф залежностей, і він не розуміє сенсу. Ембеддинги покривають семантичний бік, але вони — неправильний інструмент для точних рядків та аналізу впливу. Більшість інструментів пошуку коду обирають один рушій і змушують кожен запит жити з цим вибором. Maguyva не обирає. Він з’ясовує, яке саме запитання ви поставили, а потім змішує чотири ретрівери в пропорції, якої заслуговує це запитання.
Чотири режими
Під капотом є чотири незалежні способи знайти код:
- semantic — векторний пошук за бінарними ембеддингами Voyage; знаходить код за сенсом.
- text — триграмне зіставлення; знаходить літерали, рядки помилок, точні ідентифікатори.
- structural — запити AST; знаходить визначення, сигнатури та мовні конструкції.
- graph — граф залежностей; знаходить викликачів, викликаних та радіус впливу.
Кожен сильний у своєму класі запитань. Хитрість у тому, щоб вирішити, наскільки довіряти кожному для конкретного запиту перед вами.
Класифікація наміру
Перш ніж запуститься будь-який пошук, легкий класифікатор сортує запит в один з шести намірів, з оцінкою впевненості. Він навмисно дешевий — упорядковані евристики, перший збіг перемагає — бо працює на гарячому шляху й додає лише мілісекунду-дві:
- починається з
def,class,func,import… → find_definition (впевненість 0.95) - «who calls», «usages of», «references to» (хто викликає, використання, посилання) → find_references (0.90)
- «impact», «blast radius», «what depends on» (вплив, радіус впливу, що від цього залежить) → impact_analysis (0.90)
- рядок у лапках
"string"чи токен помилки на кшталтtraceback→ exact_match (0.85–0.90) - ідентифікатор
CamelCaseчиsnake_case→ find_definition (0.60–0.80) - «how», «why», «explain», «architecture» (як, чому, пояснення, архітектура) → understand_code (0.75)
- нічого не збігається → understand_code, низька впевненість (0.40)
Кожен намір несе профіль ваг серед чотирьох режимів. Ось реальні цифри:
| Намір | semantic | text | structural (AST) | graph |
|---|---|---|---|---|
| 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 |
Тож «де визначено parseConfig» сильно спирається на AST (0.6). «як працює автентифікація» спирається на семантичні вектори (0.5). «що залежить від цього» майже повністю graph (0.7). «знайди ECONNREFUSED» майже повністю триграма (0.9), а модель ембеддингів повністю вимкнена — бо семантична подібність це саме неправильний інструмент для точного рядка.
Швидкий шлях і шлях зі злиттям
Коли класифікатор впевнений — оцінка ≥ 0.85 — і запит звичайний, Maguyva повністю пропускає злиття й спрямовує запит прямо в єдиний домінантний режим. «де визначено X» не потребує чотирьох ретріверів; йому потрібен індекс AST, зараз. Цей прямий шлях повідомляється назад як fusion_strategy: "direct".
Усе неоднозначне проходить через злиття. Чотири (або три, у пресеті за замовчуванням) режими запускаються паралельно, кожен повертає свій ранжований список, і ми їх об’єднуємо.
Зважене Reciprocal Rank Fusion
Злиття різнорідних ретріверів складніше, ніж здається: косинусна подібність 0.82, триграмна оцінка 137 і графова центральність 0.004 — не в одній шкалі, тож просто скласти їх не можна. Reciprocal Rank Fusion обходить проблему, відкидаючи сирі оцінки й залишаючи лише ранг, який присвоїв кожен рушій. Внесок результату від одного режиму:
contribution = weight × 1 / (k + rank + 1)
де rank — його позиція в списку цього режиму, а k — константа згладжування. Внески підсумовуються серед режимів для будь-якого результату, який знайшов більш ніж один рушій — узгодженість між ретріверами природно спливає нагору. Ми використовуємо k = 40 у пресеті за замовчуванням і 60 на thorough (quick працює лише семантично, тож злиття там ніколи не задіюється). Оригінальна робота з RRF зупинилася на k = 60 для загального пошуку; наше налаштування за замовчуванням дещо сильніше виділяє верхні позиції, надаючи трохи більшу вагу результатам, які кілька режимів одночасно ранжують високо — і ми не рекомендуємо налаштовувати це вручну.
Окрім цього, результати несуть посилення за важливістю графа. Хаб — функція, на яку спирається вся кодова база — має обходити за рангом малопомітний листовий вузол, навіть за однакової текстової релевантності, тож ми множимо кожен внесок на:
boost = min(1 + 0.3 × ln(1 + centrality), 1.5)
Центральність береться з попередньо обчислених метрик PageRank/ступеня конвеєра, а посилення обмежене 1.5×, щоб популярна функція не могла повністю поховати релевантнішу, але малопомітну. Насамкінець ми знижуємо ранг результатів зі шляхів vendor, build та archive, і усуваємо дублікати, залишаючи найкращий фрагмент на файл.
Що досі недосконале
Класифікатор наміру — це набір регулярних виразів, а не навчена модель. Він обробляє поширені форми запитів за допомогою евристик, а неоднозначний запит переходить до understand_code і суміші з перевагою семантики. У попередній версії цієї статті зниження частки запитів без результатів приблизно з 15% до менш ніж 5% було описано як досягнуте. Насправді пропозиція від грудня 2025 року містила оцінку початкового рівня та цільове значення; підтвердного набору запитів або протоколу вимірювань не надано. Ми відкликаємо це твердження про досягнуте поліпшення; див. вихідні підтвердні матеріали та виправлення (англійською). Ми не замінили класифікатор навченою моделлю, бо недорога версія досить швидка й придатна для своєї задачі маршрутизації, а хибний, але впевнений класифікатор гірший за чесний запасний варіант. Самі ваги — це вручну обрані апріорні значення, а не значення, вивчені з даних про кліки, яких ми не збираємо.
Ставте запитання, а вибір інструмента залиште системі
Агенту не повинно бути потрібно знати, чи тягнутися до grep, чи до ембеддингів, чи до графа викликів — він має ставити своє запитання простими словами й отримувати правильну відповідь. Мультимодальне злиття — це те, що дозволяє find_symbol, семантичному пошуку та аналізу залежностей працювати через єдиний інтерфейс запитів: система читає форму запитання й тихо збирає для нього правильний ретрівер. Модель, що оцінює ембеддинги, важлива, але так само важливо знати, коли не використовувати їх. Обрати правильний інструмент для кожного запиту — це свій особливий вид якості, і ми радше візьмемо його на себе, ніж перекладемо на того, хто викликає.
// you bring the question. it brings the tools.
Читайте також
Ще з журналу розробки Maguyva
Чому ми оновили пошук коду до voyage-4-large_
Ми перевели наші ембеддинги коду на voyage-4-large — модель, що наразі очолює публічний рейтинг RTEB для пошуку коду. Чесна версія: компроміс, на який ми йдемо, що ми насправді індексуємо, і чому ми платимо за преміум-ембеддинги.
Спостережуваність агентів: хуки, Alloy та Grafana_
Ми під'єднали Claude Code та Codex до єдиного стеку Grafana за допомогою OpenTelemetry та Alloy, а потім використали трейси й логи, щоб знаходити та виправляти проблеми в поведінці агентів у джерелі.
Видобування знань з історії змін: як зміни стають інституційною пам'яттю_
Git-коміти перетворюються на структуровані записи журналу змін та архітектурні рішення, а потім повертаються до ШІ-агентів як інституційна пам'ять, придатна для запитів.