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モデルが「健全」状態で、そのうち最速のものが採用される。全モデルが不調のときだけフォールバックチェーンが発動する:

  1. Nemotron(自前サーバー)
  2. Groq(最速)
  3. Gemini(コスパ最良)
  4. Claude(品質最良)
  5. 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ストリーミング、サーキットブレーカーの実装)はこちらにまとめている。