モデルルーティング:カスタムマッピング、ワイルドカード優先順位とプリセット戦略
クライアントで書いた model は、必ずしも Antigravity Tools がアップストリームにリクエストする際の「物理モデル」とは限りません。モデルルーティングのやることはシンプル:「対外的に安定したモデル名」を「内部的に実際に使うモデル」にマッピングし、結果をレスポンスヘッダ X-Mapped-Model に入れて、期待どおりのルートを通ったかを確認しやすくします。
このレッスンでできること
- UI で
proxy.custom_mappingを設定(正確マッピング + ワイルドカードマッピング) - 1 つのルールがどのようにマッチしたかを明確に説明(正確 > ワイルドカード > デフォルトマッピング)
- ワンクリックでプリセットルールを適用し、迅速に OpenAI/Claude クライアントに対応
curl -iでX-Mapped-Modelを検証し、「なぜ私が思ったルーティングにならなかったか」を特定
現在の悩み
- クライアントは常に
gpt-4oを書きたいが、アップストリームでは特定の Gemini モデルに安定して落としたい - 多くのバージョン付きモデル名(例:
gpt-4-xxxx)があり、毎回手動でマッピングを追加したくない - リクエストは成功したが、実際にはどの物理モデルが動いているか不明
この方法をいつ使うか
- チームに「固定された対外モデルセット」を提供し、アップストリームのモデル変動をシールドしたい
- 複数の OpenAI/Claude モデル名を少数のコストパフォーマンスの高いモデルに統一ルーティングしたい
- 401/429/0 token のトラブルシューティング中、マッピング後の実際のモデルを確認したい
🎒 始める前の準備
- ローカルリバースプロキシを起動でき、外部からのリクエストで正常に動作(まず ローカルリバースプロキシを起動して最初のクライアントを接続する(/healthz + SDK 設定) を完了することを推奨)
curl -iでレスポンスヘッダを見る方法を知っている(前のレッスンでX-Mapped-Modelを使用)
このレッスンで 2 つのキーワード
custom_mapping:あなたの「カスタムルールテーブル」。キーはクライアントから渡されるモデル名(またはワイルドカード pattern)、値は最終的に使用するモデル名(出典:src/types/config.ts)。- ワイルドカード
*:モデル名のバッチマッチに使用(例:gpt-4*)。マッチ実装は大文字小文字を区別する(出典:src-tauri/src/proxy/common/model_mapping.rs)。
コアコンセプト
バックエンドがリクエストを処理する際、まず mapped_model を計算します:
- まず
custom_mappingに正確一致があるか確認(key がmodelと完全一致) - 次にワイルドカード一致を試行:「非
*文字がより多い」ルールを選択(より具体的なルールが優先) - どちらもマッチしない場合、システムデフォルトマッピングに進む(例:一部の OpenAI/Claude モデルエイリアスから内部モデルへのマッピング)
この mapped_model はレスポンスヘッダ X-Mapped-Model に書き込まれます(少なくとも OpenAI handler はそうします)。これを使えば「私が書いた model が最終的に何になったか」を確認できます。
ホットリロードの意味論(再起動不要)
リバースプロキシサービスが実行中の場合、フロントエンドが update_model_mapping を呼び出すと、バックエンドはすぐに custom_mapping をメモリ内の RwLock に書き込み、同時に永続化設定にも保存(出典:src-tauri/src/commands/proxy.rs;src-tauri/src/proxy/server.rs)。
さあ、一緒にやってみよう
ステップ 1:API Proxy ページで「モデルルーティング」カードを見つける
なぜ モデルルーティングの設定エントリは UI 内にあります。設定ファイルを手動で編集する必要はありません。
Antigravity Tools を開く → API Proxy ページ → 下にスクロール。
期待される結果:タイトルが「モデルルーティングセンター」に似たカードが表示され、右上に 2 つのボタン:「プリセットマッピング適用」と「マッピングリセット」(出典:src/pages/ApiProxy.tsx)。
ステップ 2:「正確マッピング」を 1 つ追加(最も制御可能)
なぜ 正確マッピングの優先順位は最高で、「この 1 つのモデル名をこの 1 つの物理モデルに落としたい」場合に適しています。
「マッピング追加」エリアで:
- Original には対外的に公開するモデル名を入力、例:
gpt-4o - Target はドロップダウンからターゲットモデルを選択、例:
gemini-3-flash
Add をクリック。
期待される結果:マッピングリストに gpt-4o -> gemini-3-flash が表示され、保存成功のトーストがポップアップ。
ステップ 3:「ワイルドカードマッピング」を 1 つ追加(バッチ覆盖)
なぜ 多くのバージョン付きモデル名がある場合(例:gpt-4-turbo、gpt-4-1106-preview)、ワイルドカードを使うと重複設定を大幅に削減できます。
もう 1 つのマッピングを追加:
- Original:
gpt-4* - Target:
gemini-3-pro-high
期待される結果:リストに gpt-4* -> gemini-3-pro-high が表示される。
ルール優先順位の「罠」
gpt-4o が同時に正確ルール gpt-4o とワイルドカードルール gpt-4* の両方を満たす場合、バックエンドはまず正確一致を優先(出典:src-tauri/src/proxy/common/model_mapping.rs)。
ステップ 4:ワンクリックでプリセットルールを適用(迅速な互換性)
なぜ 主な目的が「一般的な OpenAI/Claude モデル名に迅速に対応」する場合、プリセットが一括のワイルドカードルールを直接入力できます。
「プリセットマッピング適用」をクリック。
期待される結果:リストに複数のルールが追加され、以下のような内容が含まれる(出典:src/pages/ApiProxy.tsx):
{
"gpt-4*": "gemini-3-pro-high",
"gpt-4o*": "gemini-3-flash",
"gpt-3.5*": "gemini-2.5-flash",
"o1-*": "gemini-3-pro-high",
"o3-*": "gemini-3-pro-high",
"claude-3-5-sonnet-*": "claude-sonnet-4-5",
"claude-3-opus-*": "claude-opus-4-5-thinking",
"claude-opus-4-*": "claude-opus-4-5-thinking",
"claude-haiku-*": "gemini-2.5-flash",
"claude-3-haiku-*": "gemini-2.5-flash"
}ステップ 5:X-Mapped-Model でルーティングが有効か確認
なぜ 「設定が書き込まれた」ことを確認したいだけでなく、「リクエストが本当にこのルールに従った」ことを確認したい。最も手間のかからない方法は X-Mapped-Model を見ることです。
curl -i http://127.0.0.1:8045/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "hi"}]
}'$resp = Invoke-WebRequest "http://127.0.0.1:8045/v1/chat/completions" -Method Post -ContentType "application/json" -Body '{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "hi"}]
}'
$resp.Headers["X-Mapped-Model"]期待される結果:レスポンスヘッダに X-Mapped-Model: ... がある。ステップ 2 で gpt-4o を gemini-3-flash に正確マッピングした場合、ここで対応する値が見えるはず(レスポンスヘッダ書き込みは src-tauri/src/proxy/handlers/openai.rs 参照)。
ステップ 6:「純粋なデフォルトマッピング」に戻る必要がある場合、custom_mapping をリセット
なぜ トラブルシューティング時、通常はまず「カスタムルールの影響」を除外したい。custom_mapping をクリアするのが最も直接的なロールバック手段。
「マッピングリセット」をクリック。
期待される結果:マッピングリストがクリアされる。その後リクエストすると、カスタムルールにマッチしない場合、システムデフォルトマッピングに進む(出典:src/pages/ApiProxy.tsx;src-tauri/src/proxy/common/model_mapping.rs)。
チェックポイント ✅
- [ ] UI で
custom_mappingルールを追加/削除できる - [ ] 正確ルールがワイルドカードルールより優先される理由を説明できる
- [ ]
curl -iまたは PowerShell でX-Mapped-Modelを読める
よくある落とし穴
| シナリオ | あなたがするかもしれないこと(❌) | 推奨される方法(✓) |
|---|---|---|
| ワイルドカードが有効にならない | GPT-4* を書いて gpt-4-turbo にマッチすることを期待 | 小文字で gpt-4* を使用;バックエンドのワイルドカードマッチは大文字小文字を区別する |
| 2 つのワイルドカードがどちらもマッチ | gpt-* と gpt-4* を同時に書き、どちらに進むかわからない | より具体的なルールをより「長く」し、非 * 文字がより多くなることを確認 |
| ルールは正しいように見えるが変わらない | レスポンス body しか見ず、レスポンスヘッダを見ない | curl -i で X-Mapped-Model を確認(これはバックエンドが明示的に返す結果) |
| 2 つのルールが「同じ具体性」 | 非 * 文字数が同じ 2 つのワイルドカードルールを書く | このような設定は避けること;ソースコードのコメントは、この場合の結果が HashMap の走査順序に依存し、不安定になる可能性があると説明(出典:src-tauri/src/proxy/common/model_mapping.rs) |
このレッスンのまとめ
proxy.custom_mappingは「対外モデル名 → 物理モデル」を制御するメインエントリ- バックエンドルーティング優先順位は:正確一致 > ワイルドカード一致(より具体的が優先)> システムデフォルトマッピング
X-Mapped-Modelは最も信頼性の高い検証手段であり、トラブルシューティング時はまずこれを見る
次のレッスン予告
次のレッスンでは クォータガバナンス:Quota Protection + Smart Warmup の組み合わせ戦術(対応章:
advanced-quota)を解説します。
付録:ソースコード参考
クリックしてソースコードの位置を展開
更新日時:2026-01-23
| 機能 | ファイルパス | 行番号 |
|---|---|---|
設定フィールド:proxy.custom_mapping(フロントエンド型) | src/types/config.ts | 6-20 |
UI:書き込み/リセット/プリセット(update_model_mapping 呼び出し) | src/pages/ApiProxy.tsx | 371-475 |
| UI:モデルルーティングカード(プリセットマッピング適用 / マッピングリセット / リストと追加フォーム) | src/pages/ApiProxy.tsx | 1762-1931 |
バックエンドコマンド:ホットリロードと custom_mapping の永続化 | src-tauri/src/commands/proxy.rs | 344-365 |
サーバー状態:custom_mapping を RwLock<HashMap<..>> で保存 | src-tauri/src/proxy/server.rs | 16-53 |
| ルーティングアルゴリズム:正確 > ワイルドカード(より具体的が優先)> デフォルトマッピング | src-tauri/src/proxy/common/model_mapping.rs | 180-228 |
ワイルドカードマッチ:複数 * をサポートし、大文字小文字を区別 | src-tauri/src/proxy/common/model_mapping.rs | 134-178 |
リクエスト内で mapped_model を計算(例:OpenAI handler) | src-tauri/src/proxy/handlers/openai.rs | 154-159 |
| --- | --- | --- |
キー関数:
resolve_model_route(original_model, custom_mapping):モデルルーティングメインエントリ(src-tauri/src/proxy/common/model_mapping.rs参照)