多模態融合搜尋:為每個查詢挑選正確的檢索方式
> 像「parseConfig 定義在哪裡」這樣的查詢,需要的搜尋方式和「auth 是如何運作的」截然不同。Maguyva 會先分類查詢意圖,據此為四種檢索模式加權,再以加權版的 Reciprocal Rank Fusion(倒數排名融合)演算法整合結果。
歷史設計說明:這篇 2026 年 4 月的文章描述的是當時的路由設計,並非目前的預設行為。下方 9 月的更正僅針對一項測量聲明。關於目前的路由、預設組態與明確的檢索模態控制,請參閱運作原理。
搜尋查詢從來不是單一種東西。
「parseConfig 定義在哪裡」想要的是精確的符號——一個精準的位置,而且要快。「authentication 是如何運作的」想要的是意義——是能解釋一個概念的相關程式碼分佈全貌。「如果我修改這個函式會壞掉什麼」想要的是依賴關係圖。「找出字串 ECONNREFUSED」想要的是字面比對,不需要耍任何花招。
Grep 在字面比對上表現優異,對某些參照搜尋也很有用,但它不是依賴關係圖,也不理解意義。嵌入模型涵蓋了語意層面,但對精確字串比對與影響分析來說,卻是用錯了工具。多數程式碼搜尋工具只會選定一種引擎,讓每個查詢都得將就這個選擇。Maguyva 不做這種取捨,而是先判斷你提出的是哪一類問題,再依該問題應得的比例,混合四種檢索方式。
四種模式
在底層,有四種各自獨立的方式可以找到程式碼:
- 語意(semantic) — 對 Voyage 二元嵌入向量進行向量搜尋,依意義找出程式碼。
- 文字(text) — 三字元片段(trigram)比對,找出字面值、錯誤字串、精確識別碼。
- 結構(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)
每種意圖在四種模式上都有各自的權重設定,以下是實際數值:
| 意圖 | 語意 | 文字 | 結構(AST) | 圖譜 |
|---|---|---|---|---|
| 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);「auth 是如何運作的」會偏重語意向量(0.5);「什麼依賴這個」幾乎完全倚重圖譜(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,在 thorough 中則使用 60(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 年 12 月的提案列出的是估計基準與目標,並未提供支持此結果的查詢集或測量紀錄。我們撤回這項已實現改善的聲明;參見來源證據與更正(英文)。我們尚未以訓練過的模型取代這個分類器,因為低成本版本對於預定的路由用途而言夠快、也夠好,而且一個自信卻錯誤的分類器,比一個坦誠的備援方案更糟。這些權重是手動選定的先驗值,並非從我們沒有收集的點擊資料中學習而來。
問問題,而不是選工具
代理不該需要自己判斷該用 grep、嵌入模型還是呼叫圖——它應該用直白的方式提出問題,並得到正確的答案。多模態融合,正是讓 find_symbol、語意搜尋與依賴分析,能共同藏身於單一查詢介面之後的原因:系統會讀懂問題的形狀,靜靜地為它組出正確的檢索方式。負責為嵌入向量評分的模型固然重要,但知道何時不該使用它們同樣重要。為每個查詢挑選正確的工具,本身就是一種品質,而這正是我們寧可自己扛下、也不願丟給呼叫端處理的事。
// you bring the question. it brings the tools.
延伸閱讀
更多來自 Maguyva 開發日誌的內容
我們為何將程式碼搜尋升級至 voyage-4-large_
我們將程式碼嵌入模型換成了 voyage-4-large——目前在公開的 RTEB 程式碼檢索排行榜上排名第一。這是誠實的版本:我們做了什麼取捨、我們實際索引的是什麼,以及我們為何願意為高階嵌入模型付費。
代理可觀測性:Hooks、Alloy 與 Grafana_
我們將 Claude Code 與 Codex 接入同一套 Grafana 技術堆疊,搭配 OpenTelemetry 與 Alloy,再運用追蹤與日誌,從源頭找出並修正代理的行為問題。
挖掘迴圈:變更如何化為組織記憶_
Git 提交會轉化為結構化的變更日誌條目與架構決策紀錄,再回饋給 AI 代理,成為可查詢的組織記憶。