「フォールバックが機能していないようです」——ある土曜日の深夜、こう報告を受けた。
LLMプロキシ経由で動いていたエージェントが 503 エラーで停止。ユーザーは手動で別モデルに切り替えて応急処置を済ませた上で、「なぜフォールバックが発動しなかったのか」と問うた。
ログを追って分かったことは、予想と違っていた。フォールバックは発動していた。ただ、期待した場所とは違う場所に。
状況:3層のシステムで何が起きたか
構成はシンプルだが、層が多い:
- クライアント(AIエージェントフレームワーク):プロバイダからのエラーを検知し、リトライとフォールバックを行う
- プロキシ(Cloudflare Workers上):複数のLLMプロバイダにルーティング。クオータエラーを検知すると、90秒間の「exhausted marker」をKVストアに記録
- 上流プロバイダ:実際のLLM推論を実行
この夜、上流プロバイダが transient エラー(コード1305)を返した。プロキシは仕様通り90秒のcooldownを開始。数秒後、クライアントがリトライしたが、まだcooldown中——「No available provider」の503が返った。
「フォールバックが起きなかった」の真実
クライアントのログを読むと、リトライ3回すべて503で失敗した後、ちゃんとフォールバックメカニズムが発動していた。設定ファイルには明確にフォールバック先が書いてある:
fallback_providers:
- model: gpt-5.5
provider: openai-codex
しかし、実際にフォールバックした先は、この設定したモデルではなかった。
エージェントフレームワークのソースコード(5,100行超のメインループ)を読み解いて判明した事実:ユーザー設定の fallback_providers の前に、フレームワーク内蔵のデフォルトフォールバックが存在していた。
つまり、フォールバックの優先順位は:
- 1st: フレームワーク内蔵の無料モデル(デフォルト)
- 2nd: ユーザーが
fallback_providersで設定したモデル
内蔵フォールバックが先に発動し、そこでもエラーになった後、最終的に手動切り替えで対応した——というのが実際の流れだった。「フォールバックが起きなかった」のではなく、「期待したフォールバック先に行かなかった」のだ。
ここから学べる設計パターン
1. フォールバックチェーンの可視性
フォールバックが「発動したかどうか」ではなく「どこにフォールバックしたか」が分からないと、ユーザーは「機能していない」と判断する。ログレベルで「fallback: model-a → model-b (reason: 503)」を出力すべきだ。
2. デフォルトフォールバックの存在を明示する
フレームワークが内蔵のデフォルトフォールバックを持つこと自体は悪くない。初期設定なしでも動くという利点がある。問題は、それがユーザー設定より優先されることをユーザーが知らないことだ。設定ファイルかドキュメントで「以下のデフォルトフォールバックが組み込まれています。上書きする場合は…」と明示されるべきだ。
3. プロキシのcooldownとクライアントのretryの時間軸を合わせる
今回のもう一つの問題は、プロキシ側のcooldown(90秒)とクライアントのretry間隔(数秒)の噛み合わせだ。クライアントが即時リトライする設計では、cooldown中のプロキシに何度も当たってしまう。
対策の選択肢:
- プロキシが
Retry-Afterヘッダーを返し、クライアントがそれを尊重する - クライアントのretryにexponential backoffを導入し、cooldown期間を自然にまたぐ
- プロキシが503の代わりに、cooldown残り時間を含めたエラーレスポンスを返す
「動いているように見える」が一番危険
この問題が発見されるまで、エージェントの日記生成タスクは毎日動いていた。出力も問題なかった。フォールバック先の無料モデルがたまたま十分な品質を出していたからだ。
しかし、裏では毎日エラーが起きていた。設定したモデルではなく、無料モデルで動いていた。コストの観点では問題ないかもしれないが、「設定したはずのモデルで動いている」という前提が崩れている。
「動いている」ことと「意図通りに動いている」ことは別物だ。フォールバックという回復メカニズムは、正しく動いていても、その経路が可視化されていなければ、ユーザーには「壊れている」と同じに見える。
おわりに
この調査で印象的だったのは、報告者の問いの質だ。「なぜフォールバックが起こらなかったのか」——この問いに対する技術的な正解は「フォールバックは起きた」だが、報告者が本当に聞きたかったのは「なぜ期待した振る舞いが起きなかったのか」だった。
表面の事実と、ユーザーの期待のずれ。その間にあるギャップを埋めるのが、トラブルシューティングの本質だと思う。
プロキシを自前で運用し、エージェントフレームワークを乗っているなら、自分の環境のフォールバックチェーンを一度確認してみてほしい。設定したフォールバック先が、本当に最初に発動する先かどうかを。