こんにちは。ガオ株式会社の黒澤です。前回 の記事では、AI Gatewayの製品を3つ紹介しました。この記事では、その中からBifrostを使用して、フォールバック機能がどのように動作して、Langfuseで可視化されるかを解説します。
結論から言うと、Bifrostのフォールバック発動はLangfuse上で fallback.* スパンとして確認できます。どのプロバイダー・モデルへ切り替わったかもスパン名とメタデータから追えます。一方、v1.4.24時点では内部プラグインスパンが多く、プライマリ失敗理由の詳細確認にはBifrostログやPrometheusメトリクスとの併用が必要です。
想定読者・この記事でわかること#
想定読者:
- AI Gatewayのフォールバック機能に興味がある方
- 前回 を読んで「フォールバック時のトレースはどう見えるの?」と思った方
この記事でわかること:
- BifrostでLLMプロバイダーのフォールバックを設定する方法
- フォールバック発動時にLangfuseのトレースがどう見えるか
- 運用観点でフォールバックトレースをどう活用するか
フォールバックとは#
LLM本番運用でよくある困りごとがあります。OpenAIがメンテナンスに入ってサービスが止まった、レートリミットにかかってリクエストが通らない、といった状況です。
AI Gatewayのフォールバック機能は、プライマリのLLMプロバイダーへの接続が失敗したとき、自動でバックアッププロバイダーへ切り替える機能です。アプリ側のコードを変えることなく、ゲートウェイ層で透過的にリカバリします。
大規模システムやエンタープライズ向けには特に重要な機能です。「障害が起きてもサービス継続できる」という安心感は、本番導入の判断材料になります。
Bifrostはリトライとフォールバックの2層でレジリエンスを実現しています。
graph LR Client[クライアント] --> GW[Bifrost
AI Gateway] GW -->|①プライマリ失敗| OAI[OpenAI
401エラー] GW -->|②フォールバック| VTX[Vertex AI
成功] GW -->|トレース送信| LF[Langfuse]
| 機能 | 動作 |
|---|---|
| リトライ | 同一プロバイダー内でエラー時に再試行(指数バックオフ)。レートリミット(429)では、max_retries > 0 かつ複数のAPIキーが設定されている場合にキーをローテーションします(v1.5.0-prerelease4 以降) |
| フォールバック | リトライを使い切ったら次のプロバイダーへ切り替え。各フォールバック先も独自のリトライ予算を持つ |
Bifrostでフォールバックを設定する#
1. プロバイダーを複数登録する#
config.json の providers にプライマリとバックアップの両方を定義します。
{
"providers": {
"openai": {
"keys": [
{
"name": "openai-key",
"value": "env.OPENAI_API_KEY",
"models": ["gpt-4o-mini"],
"weight": 1.0
}
]
},
"vertex": {
"keys": [
{
"name": "vertex-key",
"value": "",
"models": ["gemini-2.5-flash"],
"weight": 1.0,
"vertex_key_config": {
"project_id": "your-gcp-project",
"region": "us-central1"
}
}
]
}
}
}2. リクエストに fallbacks を指定する#
フォールバック先はリクエスト時に fallbacks 配列で指定します。provider/model の形式です。
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o-mini",
"messages": [{"role": "user", "content": "日本の首都は?"}],
"fallbacks": ["vertex/gemini-2.5-flash"]
}'フォールバックが複数ある場合はリストで並べるだけです。
"fallbacks": [
"vertex/gemini-2.5-flash",
"anthropic/claude-3-5-sonnet-20241022"
]意図的に障害を起こしてトレースを確認する#
検証構成#
今回は以下の構成でフォールバックを検証しました。
- プライマリ:OpenAI(意図的に無効なAPIキーを設定)
- フォールバック:Vertex AI(gemini-2.5-flash)
- 検証環境:Bifrost
v1.4.24(検証日: 2026年5月1日)。なお、v1.5.0 が2026年5月6日にリリースされており、観測性まわりに変更が入っているため、バージョンによってトレースの見え方が異なる可能性があります
認証エラー(401)は一時的な障害ではないため、今回の検証ではリトライされず即座にフォールバックへ切り替わりました。
検証の限界について: 本記事では意図的に無効なAPIキー(401エラー)を使ってフォールバックを発動させていますが、実運用で発生しやすい障害は 429(レートリミット)や 503(過負荷)、ネットワークタイムアウトです。これらのケースではBifrost側のリトライ動作も挟まるため、トレースの見え方が異なる可能性があります。本記事は「フォールバック発動時にLangfuseで何が見えるか」の把握を目的とした検証として参照してください。
レスポンスとLangfuseトレースで確認する#
レスポンスの extra_fields.provider を見れば、1リクエスト単位でどのプロバイダーが応答したかは確認できます。ただし、大量リクエスト処理中の監視・インシデント後の遡及確認・フォールバック発動頻度の時系列把握にはLangfuseのトレースが有効です。
{
"choices": [...],
"extra_fields": {
"provider": "vertex"
}
}フォールバックが発動したリクエストのLangfuseトレースです。

読み方のポイント:
- プライマリ失敗の痕跡(これらはBifrostが各リクエストに付与する処理フックのスパンです。詳細は前回
参照):
- ツリー上部の
plugin.telemetry.prehook→plugin.governance.prehook→ posthook の流れに注目 - 本来あるはずの
llm.callがこの間に存在しない llm.callがない=成功したLLM生成スパンとして記録されていない=OpenAIへの試みが失敗した部分と推測できます(OpenAIへのリクエスト試行自体は発生しています)
- ツリー上部の
fallback.vertex.gemini-2.5-flashスパン:フォールバック先のプロバイダーとモデル名がスパン名に入ります。どこへ切り替わったかが一目でわかりますfallback.index: "1":メタデータにフォールバック試行インデックスが記録されます(プライマリを0として、1は最初のフォールバックで成功したことを示します)。複数のフォールバックを設定した場合でも、どの段階で回復したかが追えます
フォールバック時も、llm.call スパンを開くとInput/Outputは記録されています。ただし多数のプラグインスパンの深い階層にあるため、見つけるには手動で辿る必要があります。このスパンの深さ自体はIssue #1561
で改善予定です。

運用観点でのまとめ#
フォールバック発動時のLangfuseトレースから読み取れる情報をまとめます。
| 確認したいこと | トレースで見える? |
|---|---|
| フォールバックが発動したか | ✅ fallback.* スパンの有無で判断可能 |
| どのプロバイダーに切り替わったか | ✅ スパン名(例:fallback.vertex.gemini-2.5-flash)に明示 |
| フォールバックチェーンの何番目か | ✅ メタデータの fallback.index |
| プライマリが失敗した理由 | △ llm.call が存在しないことは確認できるが詳細なエラー理由は不明。Bifrostのサーバーログには401エラーが記録されるため、Langfuseで発生を検知→ログで詳細確認という手順が現実的 |
| 入力・出力の内容 | △ llm.call スパンに記録されるが、深い階層のため確認に手間がかかる |
フォールバックの発動と切り替え先は、Langfuseのスパン名を見れば一目で確認できます。プライマリ失敗の詳細理由はBifrostのサーバーログに記録されるため、Langfuseで発生を検知してからログで詳細を確認する、という手順が現実的です。