マルチモーダル・フュージョン検索: あらゆるクエリに最適な検索エンジンを選ぶ
> 「parseConfigはどこで定義されているか」のようなクエリと「認証はどう動いているか」のようなクエリでは、求められる検索の種類が異なります。Maguyvaは意図を分類し、それに応じて4つの検索モダリティに重みを付け、重み付き相互順位融合で結果を統合します。
過去の設計について: この2026年4月の記事は、当時のルーティング設計を説明するものであり、現在のデフォルト動作を説明するものではありません。以下の9月の訂正は、測定に関する主張のみを対象としています。現在のルーティング、プリセット、明示的なモダリティ制御については、仕組みをご覧ください。
検索クエリは、一枚岩ではありません。
「parseConfigはどこで定義されているか」は、正確なシンボル(素早く得られる1つの正確な場所)を求めています。「認証はどう動いているか」は意味を求めています。つまり、ある概念を説明する、関連コードの広がりです。「この関数を変更したら何が壊れるか」は依存関係グラフを求めています。「文字列ECONNREFUSEDを見つけて」はリテラルな一致を求めているのであって、気の利いたことは何もいりません。
Grepはリテラルな一致には優れており、一部の参照探しにも有用ですが、依存関係グラフではありませんし、意味を理解することもありません。埋め込み(embedding)は意味的な側面をカバーしますが、正確な文字列や影響分析には向いていないツールです。ほとんどのコード検索ツールは1つのエンジンを選び、あらゆるクエリをそのエンジンで処理します。Maguyvaはエンジンを固定しません。あなたがどんな種類の問いを立てたのかを見極め、その問いにふさわしい比率で4つの検索エンジンをブレンドします。
4つのモダリティ
内部には、コードを見つけるための4つの独立した方法があります:
- semantic(意味検索) — Voyageのバイナリ埋め込みによるベクトル検索。意味でコードを見つける。
- text(テキスト検索) — トライグラムマッチング。リテラル、エラー文字列、正確な識別子を見つける。
- structural(構造検索) — ASTクエリ。定義、シグネチャ、言語構文を見つける。
- graph(グラフ検索) — 依存関係グラフ。呼び出し元、呼び出し先、影響範囲を見つける。
それぞれが異なる種類の問いに強みを持っています。肝心なのは、目の前のクエリに対してそれぞれをどれだけ信頼するかを見極めることです。
意図分類
検索を実行する前に、軽量な分類器がクエリを6つの意図のいずれかに振り分け、確信度スコアを付けます。これはホットパス上で動作し、加わる遅延はわずか1〜2ミリ秒程度であるべきなので、意図的に軽量に作られています。順序付きのヒューリスティクスで、最初に一致したものが採用されます:
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)
それぞれの意図は、4つのモダリティにまたがる重みプロファイルを持っています。これが実際の数値です:
| 意図 | 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)。「これに依存しているのは何か」はほぼグラフだけです(0.7)。「ECONNREFUSEDを見つけて」はほぼトライグラムだけで(0.9)、埋め込みモデルは完全にオフになります。正確な文字列に対して、意味的類似度はまさに誤ったツールだからです。
高速経路と、統合された経路
分類器の確信度が高く(スコア0.85以上)、クエリが通常のものであれば、Maguyvaは統合(フュージョン)を完全にスキップし、単一の支配的なモダリティへ直接ルーティングします。「Xはどこで定義されているか」には4つの検索エンジンは不要で、今すぐASTインデックスが必要なだけです。この直接経路はfusion_strategy: "direct"として返されます。
あいまいなクエリはすべて統合を経由します。4つ(デフォルトのプリセットでは3つ)のモダリティが並列に実行され、それぞれが独自のランク付けされたリストを返し、私たちはそれらを結合します。
重み付き相互順位融合
性質の異なる検索エンジンを統合するのは、見た目以上に難しい作業です。コサイン類似度0.82と、トライグラムスコア137と、グラフ中心性0.004は同じスケール上にないため、単純に足し合わせることはできません。相互順位融合は、生のスコアを捨て、各エンジンが割り当てた順位だけを残すことで、この問題を回避します。あるモダリティからの結果の寄与度は次の通りです:
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、セマンティック検索、依存関係分析を1つのクエリ入口の裏側に置くことを可能にしています。システムが問いの形を読み取り、それにふさわしい検索エンジンを静かに組み立てます。埋め込みをスコアリングするモデルも重要ですが、それを使わないべきタイミングを知っていることも同じくらい重要です。クエリごとに正しいツールを選ぶこと自体が1つの品質であり、私たちはそれを呼び出し側に押し付けるのではなく、自分たちで引き受けたいと考えています。
// you bring the question. it brings the tools.
関連記事
Maguyva開発ログのその他の記事
コード検索をvoyage-4-largeへアップグレードした理由_
私たちはコード埋め込みをvoyage-4-largeへ移行しました。現在、公開RTEBコード検索リーダーボードのトップに立つモデルです。正直に言うと: 私たちが受け入れているトレードオフ、実際に何をインデックス化しているか、そしてなぜプレミアムな埋め込みにお金を払うのか。
エージェントオブザーバビリティ: フック、Alloy、Grafana_
Claude CodeとCodexを1つのGrafanaスタックにOpenTelemetryとAlloyで配線し、トレースとログを使ってエージェントの挙動の問題を根源から見つけて直す。
ループを掘り起こす: 変更はいかにして組織の記憶になるか_
Gitのコミットは構造化された変更履歴とアーキテクチャ上の意思決定記録になり、クエリ可能な組織の記憶としてAIエージェントへフィードバックされます。