メインコンテンツへスキップ

Bifrostのフォールバックをやってみた:Langfuseトレースで何が見える?

著者
Tomoyuki Kurosawa

こんにちは。ガオ株式会社の黒澤です。前回 の記事では、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.jsonproviders にプライマリとバックアップの両方を定義します。

{
  "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トレース
フォールバック発動時のトレース:fallback.vertex.gemini-2.5-flashスパンでフォールバック先が明示される

読み方のポイント:

  • プライマリ失敗の痕跡(これらはBifrostが各リクエストに付与する処理フックのスパンです。詳細は前回 参照):
    • ツリー上部の plugin.telemetry.prehookplugin.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 で改善予定です。

llm.callスパンのInput/Output
llm.callスパンを開いた状態:Input/Outputが記録されている


運用観点でのまとめ
#

フォールバック発動時のLangfuseトレースから読み取れる情報をまとめます。

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

フォールバックの発動と切り替え先は、Langfuseのスパン名を見れば一目で確認できます。プライマリ失敗の詳細理由はBifrostのサーバーログに記録されるため、Langfuseで発生を検知してからログで詳細を確認する、という手順が現実的です。

フォールバック先のプロバイダーやモデルが変わると、出力品質・応答形式・tool callingの互換性・コストも変わります。フォールバック先は事前に評価・承認したうえで設定してください。