LLM APIのレート制限:429エラー、リトライ、同時実行を安全に処理する
執筆:Nicho
本番環境のLLMアプリケーションには、リトライループだけでは不十分です。リクエストが拒否された理由、受け入れ可能な処理量、試行を停止すべきタイミングを把握する必要があります。
実践的な出発点はシンプルです。エラーを分類し、リクエストの受け入れを制御し、操作の期限内で回復が見込める失敗のみをリトライします。こうした制御なしにリトライを増やすと、小さなトラフィックスパイクがより長い障害につながる可能性があります。
このガイドでは、プロバイダーに依存しないアプリケーション設計を扱います。正確なクォータ、エラーコード、ヘッダー、課金ルールは、プロバイダー、モデル、アカウント、ゲートウェイによって異なります。
どの制限に達したかを理解する
これらの制御は、それぞれ異なる問いに答えます。
| 制御 | 測定対象 | アプリケーションの対応 |
|---|---|---|
| リクエストレート | 一定時間内に受け入れたリクエスト数 | 開始ペースを整え、バーストを平準化する |
| トークンレート | トークン使用量または推定トークン需要 | トークン容量を確保し、リクエストサイズを制限する |
| 同時実行数 | 現在処理中のリクエスト数 | ワーカーを制限するか、セマフォを使用する |
| 利用額または残高 | 支払い能力 | 支払いまたは利用上限の制御を確認する |
たとえばOpenAIは、リクエストとトークンの制限を別々に文書化しており、そのスコープにはプロジェクトや共有モデルファミリーが含まれる場合があります。したがって、新しいAPIキーが必ずしも新しい容量を意味するわけではありません。また同社のドキュメントでは、一時的なレート制限エラーと厳格な利用上限を区別しており、どちらも429を使用する場合があります。ステータスコードだけで判断せず、エラーボディを確認してください。OpenAIのレート制限ドキュメント
HTTP標準は429を定義していますが、サービスが呼び出し元を識別する方法やリクエストをカウントする方法は規定していません。またRetry-Afterはオプションとされています。OpenAI互換のすべてのendpointが同一のスロットリング動作をするとは想定しないでください。HTTP 429仕様
より厳しい制約を基準にトラフィックを設計する
1分あたり60リクエスト、1分あたり120,000トークンという簡略化された仮定の許容量を考えます。各リクエストが4,000カウントトークンを消費する場合、トークン容量が支えられるのは1分あたり30リクエストのみです。
120,000 tokens/minute ÷ 4,000 tokens/request = 30 requests/minute
これは計画上の例であり、プロバイダーのクォータや正確なスケジューラーではありません。サービスによっては、推定出力を予約したり、より短い適用ウィンドウを使用したり、トークンカテゴリごとに異なる計算をしたりする場合があります。
自身のリクエストサイズ分布を測定してください。平均値だけでは、大きなドキュメントのアップロードや長い生成が隠れてしまいます。数学的な最大値を狙うのではなく、こうした外れ値のために余裕を確保してください。
開始と処理中の処理には別々の制御を使用します。同時実行数の上限だけでは、1分あたりのリクエスト数は強制できません。高速なレスポンスはスロットを素早く解放し、過剰な開始を生み出す可能性があります。逆に、リクエストレートリミッターは、遅いstreamingが蓄積して接続を使い果たすのを防ぎません。
リトライの前に受け入れ制御を置く
有用なリクエストパスは次のとおりです。
Authenticated request → bounded queue → rate/token admission → worker → provider
キューは意図的に設計してください。
- キューの最大長と最大待機時間を設定します。
- 対話型リクエストには、バックグラウンドジョブより短い期限を設定します。
- 超過した処理は、明確なアプリケーションレベルのレスポンスで拒否または延期します。
- キャンセル済みおよび期限切れのジョブは、ディスパッチ前に削除します。
- 同じアップストリームのクォータを消費するレプリカ間で、受付状態を共有します。
そうしない場合、アプリケーションサーバーを追加するとトラフィックが増加する一方で、アップストリームの容量は変わりません。混在ワークロードでは、ユーザー向けリクエスト用に容量を確保し、ドキュメントインポートジョブがすべてのスロットを占有しないようにします。
これらはアーキテクチャ上の推奨事項であり、特定のゲートウェイがキューや調整可能な同時実行制御を公開することを保証するものではありません。
単一の上限付きリトライポリシーを使用する
リトライには責任者が必要です。別のループを追加する前に、SDKの動作を確認します。仮に、3回のアプリケーション試行が3回のSDK試行を包む構成では、1つの論理操作に対して最大9回のアップストリーム試行が発生します。
実用的なポリシーは次のとおりです。
- プロバイダーが文書化したエラー情報を使用して、失敗を分類します。
- 認証情報、権限、支払い、またはリクエスト内容の変更が必要なエラーの場合は、直ちに停止します。
- 再試行可能な一時的失敗は、試行回数と時間の両方の予算が残っている場合にのみ再試行します。
- 有効なサーバーの再試行指示に従います。それ以外の場合は、上限付きの指数バックオフとジッターを使用します。
- 最終的な失敗は、安全に調査できる十分なコンテキストとともに返します。
Retry-Afterでは、遅延または日付を指定できます。該当するサーバーの遅延は最小値として扱い、短縮する提案とはみなしません。操作の残り期限を超える場合は、早まって再試行するのではなく、処理を延期するか明確に失敗させます。HTTP Retry-Afterのセマンティクス
ランダム化された待機は、同期した再試行の波を減らします。タイムアウトと上限付きの試行により、再試行がリソースを無期限に保持するのを防ぎます。AWSのエンジニアリングガイダンスでは、再試行が過負荷を増幅させる理由と、タイムアウトが操作の無効を証明しない理由が説明されています。AWSのタイムアウトと再試行に関するガイダンス
ストリームやエージェントのアクションを盲目的に再生しない
テキストを表示した後に停止したストリームは、処理が始まる前に拒否されたリクエストとは異なります。インターフェースには、明示的な不完全状態が必要です。自動的に再開すると、テキストが重複したり、追加のtokenを消費したり、異なる回答が生成されたりする可能性があります。
エージェントワークフローには、追加の境界が必要です。モデル生成の再試行によって、完了したツールアクションを自動的に再生してはなりません。アクションの結果を記録し、アクションサービスが対応している場合は冪等性の仕組みを使用します。失敗したレスポンスは、同じメールを再送したり、同じ注文を二重に作成したりする理由にはなりません。
HTTPの成功だけでなく、論理的な処理を監視する
以下を個別に追跡します。
- 論理操作とアップストリーム試行。
- キューの待機と処理中のリクエスト。
- 文書化されたエラー理由別の拒否。
- 完了した操作ごとの入力/出力の使用量とコスト。
- タイムアウト、キャンセルされた処理、不完全なストリーム。
リクエスト識別子とサニタイズ済みのメタデータを使用します。デフォルトでは、認証ヘッダーやプロンプト全体をログに記録しないでください。エラー率が下がっても、再試行によって完了した各タスクのコストが2倍になっていれば、成功とは言えません。
ゲートウェイの制御とキャパシティは別々に確認する
cheapaimodelが公開している料金とアカウント情報には、APIキーごとの利用上限、有効期限、モデル/IPの許可リスト、およびアカウント残高が不足したときの403レスポンスが記載されています。この残高の状態は、短いバックオフでは解決できないものです。また、これらの制御によってリクエストやtokenのスループットが無制限になるわけでもありません。
連携をスケールする前に、最新のcheapaimodelドキュメントを確認し、使用予定のルートに適用される制限を確かめてください。アドミッション制御と再試行ポリシーは設定可能にしておき、変更のたびにアプリケーションロジックを書き直さなくて済むようにします。
目標は、予測可能な完了処理です。待ち時間の上限、説明可能な失敗、制御された利用額、そして回復を妨げるのではなく助ける再試行です。