1つのモデルに依存するリスク
AIチャットサービスを運用していると、避けられない問題がある。モデルが落ちることだ。
OpenAIのAPIが503を返す。Anthropicのレートリミットに引っかかる。Googleのエンドポイントが突然レスポンスを返さなくなる。どのプロバイダーも100%の稼働率は保証していない。
chatweb.aiでは、ユーザーがチャットを送るたびに1つのモデルだけに頼る設計をやめた。代わりに、複数のモデルを同時に呼び出して、最初に返ってきた回答を採用するという方式を取っている。マルチモデルレースと呼んでいる。
5つのモデルが同時に走る
ユーザーがメッセージを送ると、バックエンド(Rust + axum、AWS Lambda上で動作)が以下のモデルに同時にリクエストを投げる:
- Nemotron 9B — 自前のRunPodサーバーで動かしているNVIDIAのモデル。レイテンシが最も低い
- Groq (Llama 3) — Groqの推論チップ。トークン生成速度が異常に速い
- Gemini 2.0 Flash — Googleのモデル。コスパが良い
- Claude — Anthropic。品質が安定している
- GPT-4o — OpenAI。汎用性が高い
5つのリクエストが同時に飛ぶ。最初にレスポンスのストリーミングが始まったモデルの回答を、そのままユーザーにSSE(Server-Sent Events)で流す。残りの4つはキャンセルする。
サーキットブレーカーで障害を封じ込める
全モデルを常に5つ呼ぶわけではない。それだとAPIコストが5倍になる。
各モデルにサーキットブレーカーを実装している。過去10回のリクエストで3回以上失敗したモデルは、一時的にレースから除外する。30秒後に1リクエストだけ試して、成功したら復帰する。マイクロサービスでよく使われるパターンだ。
通常時は2〜3モデルが「健全」状態で、そのうち最速のものが採用される。全モデルが不調のときだけフォールバックチェーンが発動する:
- Nemotron(自前サーバー)
- Groq(最速)
- Gemini(コスパ最良)
- Claude(品質最良)
- GPT-4o(最も安定)
この順番でリトライする。全部ダメなら「現在サービスが混み合っています」を返す。実際にそうなったことは、過去2ヶ月で1回だけだ。
UIでレースを可視化する
chatweb.aiのフロントエンドでは、レースの様子をリアルタイムで見ることができる。各モデルのアイコンが並んでいて、リクエスト中はアニメーションする。最初に回答を返したモデルがハイライトされ、その回答がチャットに表示される。
ユーザーは「今回はGroqが勝った」「Nemotronが速かった」というのを視覚的に確認できる。これが意外と好評だった。AIの裏側が見えるという体験が、信頼感につながっているようだ。
コストの現実
OpenRouterを経由していたときは、5モデル並列でコストが膨れ上がり、$3,400のクレジットを使い切ってしまった。その反省から、今の構成に変えた:
- Nemotron — RunPodで月額固定(GPU時間課金)
- Groq — 無料枠 + 従量課金。レート制限が厳しいが速い
- Gemini — Googleの無料枠が大きい
- Claude / GPT — 本当に必要なときだけ使う
月間のAPI費用は$200前後に落ち着いている。5モデル並列だった頃の1/10以下だ。
結果: 体感レイテンシ400ms
マルチモデルレースの最大の恩恵は速さだ。単一モデルの平均レスポンス開始時間が800ms〜1,500msのところ、レースだと最速のモデルが400ms前後で返し始める。ユーザーにとっては「送った瞬間に返ってくる」感覚だ。
可用性も上がった。1つのモデルが落ちても、別のモデルが即座にカバーする。ユーザーが「AIが動かない」と感じる頻度はほぼゼロになった。
技術的な詳細(Rustでの並行リクエスト、SSEストリーミング、サーキットブレーカーの実装)はこちらにまとめている。