【ITニュース解説】Retry, Backoff, and Circuit Breakers for LLM API Calls
2026年09月26日に「Dev.to」が公開したITニュース「Retry, Backoff, and Circuit Breakers for LLM API Calls」について初心者にもわかりやすく解説しています。
ITニュース概要
LLM APIは多様なエラーを起こすため、安定稼働には工夫が必要だ。レート制限など一時的な障害には、指数バックオフとジッターで再試行し、無駄な呼び出しは避ける。プロバイダー全体の障害にはサーキットブレーカーでシステムを守り、キューでリクエストを保持。さらに代替モデルも用意し、信頼性の高いシステムを構築することが重要だ。
ITニュース解説
システムエンジニアを目指す皆さんにとって、大規模言語モデル(LLM)のAPIは非常に魅力的な技術だ。しかし、これらのAPIを実際のシステムに組み込む際には、単に呼び出すだけでなく、その信頼性を確保するための工夫が必要となる。外部サービスとの連携では常に失敗の可能性があり、LLM APIも例外ではない。安定したシステムを構築するためには、「リトライ」「バックオフ」「サーキットブレーカー」といった設計パターンを理解し、適用することが不可欠である。
まず、LLM APIがどのような状況で失敗するのかを知ることは重要だ。主な失敗モードはいくつかある。一つ目は「レート制限(HTTPステータスコード429)」だ。これは、短時間にAPIを呼び出しすぎた際に、プロバイダ側から「少し間隔を空けてください」と指示される状態だ。これはあなたのコードのエラーではなく、利用頻度が高すぎることを意味する。二つ目は「過負荷(5xx系のエラー)」だ。これはLLMプロバイダ側のサーバーが混雑している状況で、多くの場合、プロバイダ側の問題なので、こちらでできることは限られる。三つ目は「タイムアウト」だ。大規模なモデルでの生成やプロバイダのインフラの負荷が高い場合、応答に時間がかかりすぎ、クライアント側が待機を諦めてしまうことがある。ここで注意すべきは、タイムアウトになったからといって、必ずしもAPIリクエストが失敗したとは限らない点だ。プロバイダ側では処理が完了している可能性があり、特にデータの書き込みなど「副作用」を伴う処理ではこの点が重要になる。四つ目は「品質低下」だ。これはAPIがHTTPステータスコード200(成功)を返しても、内容が不適切、途中で切れている、あるいはフォーマットが壊れているといったケースだ。この場合、通常の再試行ロジックでは検知できないため、アプリケーション側での応答内容の検証が必要となる。
次に、API呼び出しが失敗した際、再試行すべきかどうかを適切に判断することが大切だ。どのようなエラーであれば再試行してよいのか、どのようなエラーは再試行すべきでないのか、明確な基準を持つ必要がある。一時的な問題で解決できるエラーは自由に再試行してよい。例えば、前述のレート制限(429)、プロバイダ側の過負荷(5xx)、ネットワークエラー、そして読み取り専用の処理でのタイムアウトなどがこれにあたる。これらは一時的な通信状況やサーバー負荷の問題で、時間をおけば解決する可能性が高い。しかし、結果がデータベースの更新など「副作用」を伴う処理でタイムアウトが発生した場合は、慎重な再試行が求められる。リクエストが成功していたにもかかわらず、もう一度同じ処理を実行してしまうと、データが重複したり、不整合が生じたりする可能性がある。これを防ぐためには「冪等性(べきとうせい)」という考え方が必要だ。これは、同じ操作を何回実行しても結果が常に同じになるように保証する仕組みを指す。例えば、ECサイトで「注文する」ボタンを誤って二度押しても、注文が二重に作成されないように、リクエストにユニークなIDを付与し、プロバイダ側でそのIDが既に処理済みであれば再度実行しないようにする、といった方法がある。
一方で、絶対に再試行すべきではないエラーも存在する。代表的なのは、HTTPステータスコード400番台のエラーだ。これは、クライアントが送信したリクエストの内容自体が間違っていることを意味する。例えば、必須パラメータが不足していたり、認証情報(APIキーなど)が間違っていたりするケース(401 Unauthorized)などだ。このようなエラーを繰り返し再試行しても、リクエスト内容を修正しない限り成功することはなく、無駄なリソースを消費するだけでなく、アカウントロックなどのさらなる問題を引き起こす可能性もある。
再試行する際に重要なのが「バックオフ」と「ジッター」という手法だ。APIが一時的に過負荷状態にあるとき、失敗したクライアントが同時にすぐに再試行してしまうと、APIにさらなる負荷がかかり、いわゆる「殺到(スタンプディ)」状態になってしまう。これを避けるために、再試行の間隔を徐々に長くしていく「指数バックオフ」を用いる。例えば、初回は1秒待機し、次は2秒、その次は4秒といった具合に、待機時間を指数関数的に増やしていく方法だ。さらに、この待機時間にランダムな要素を加えるのが「ジッター」だ。例えば、2秒待つ場合でも、1秒から3秒の間でランダムに待機することで、多数のクライアントの再試行タイミングが分散され、殺到を防ぐ効果がある。また、APIプロバイダが応答ヘッダーに「Retry-After」という情報を含めて「X秒後に再試行してください」と明示的に指示してきた場合は、その指示に優先して従うべきだ。再試行には、無駄に時間をかけすぎないための「デッドライン(期限)」も設定することが重要だ。ユーザーが待っている間や、システムの処理キューが詰まるのを防ぐため、再試行の総時間には上限を設ける。また、バックオフの待機時間も、たとえば最大30秒など、現実的な上限値を設定することで、不必要に長い時間待機し続けることを防ぐ。
個々のリクエストの失敗を処理するリトライとは別に、プロバイダ全体が継続的に機能不全に陥っている場合にシステムを守るのが「サーキットブレーカー」という設計パターンだ。例えば、あるプロバイダが10分間サービス停止しているのに、リトライロジックが組み込まれた何万ものリクエストが次々にAPIを叩き続けてしまうと、無駄なリソースを消費し、かえってプロバイダの回復を妨げることにもなりかねない。サーキットブレーカーは、APIへの呼び出しが連続して失敗する割合を監視し、その失敗率が一定の閾値を超えると「回路を開く(オープン状態)」状態になる。オープン状態では、APIへの実際の呼び出しをせず、即座にエラーを返すようになる。これにより、システムは無駄なAPI呼び出しを停止し、プロバイダ側への負荷も軽減される。一定のクールダウン期間が過ぎると、サーキットブレーカーは「半開状態(ハーフオープン)」に移行し、少数のリクエストだけを許可して、プロバイダが回復したかどうかを試しに確認する。これらのテストリクエストが成功すれば「回路が閉じる(クローズ状態)」に戻り、通常のAPI呼び出しが再開される。もし失敗すれば、再びオープン状態に戻る。このメカニズムにより、プロバイダの障害が自システム全体に波及するのを防ぎ、システム全体の安定性を保つことができる。
システムの安定性をさらに高めるためには「キュー」の活用も重要だ。APIプロバイダがダウンしている間にも、あなたのシステムには新たな処理リクエストが次々と送られてくる可能性がある。これらのリクエストを「永続キュー」に一時的に格納しておくことで、APIプロバイダがダウンしている間も、作業が失われることなく蓄積される。プロバイダが回復すると、キューに貯まっていたリクエストが順番に処理されていく。これにより、プロバイダの障害期間中に発生した作業が失われることなく、遅延はするものの確実に処理され、システム全体の「衝撃吸収材」として機能する。
最後に、これらリトライやサーキットブレーカーでも対応できない、より深刻な事態、例えば特定のLLMモデルが市場から完全に消滅したり、長期間利用できなくなったりするようなケースに備えるための「フォールバックモデル」の準備だ。これは、メインで利用しているLLMモデルやプロバイダが利用不可能になった場合に備えて、別のプロバイダのモデルや、性能は少し劣るが確実に利用できる別のモデルを予備として用意しておくことだ。事前にこのフォールバックモデルを既存のワークロードでテストしておき、いざという時にはシステムの設定を変更するだけで、すぐに切り替えられるようにしておくことが重要だ。これにより、最悪のシナリオでもサービスを完全に停止させることなく、機能が限定的になったとしてもサービス提供を継続できる可能性が高まる。
これらの「リトライ」「バックオフ」「サーキットブレーカー」「キュー」「フォールバックモデル」といったパターンは、LLMの登場よりもずっと以前から、信頼性の高い分散システムを構築するために使われてきた基本的な技術だ。LLM APIを、まるで魔法のように常に完璧に動くと過信せず、他の外部サービスと同様に不安定な要素を持つものとして捉え、これらの古典的だが強力な設計パターンを適用していくことが、安定して運用できるシステムを構築するための鍵となる。これらの技術を適切に組み込むことで、問題が発生してもサービス全体が停止することなく、回復力のあるシステムを実現できる。