LLMのレート制限は、一定の時間枠内でアプリケーションがモデルに送信できるトラフィック量を決定します。エンジニアが最も頻繁に遭遇する2つの制限は、RPM(1分あたりのリクエスト数)とTPM(1分あたりのトークン数)です。あるワークロードが一方の制限内に収まっていても、もう一方を超えることがあります。
この違いは重要です。429をすべて単なるリクエスト数の問題として扱うと、再試行を追加してトークン負荷を増やし、レイテンシを悪化させ、障害をさらに深刻化させる可能性があります。本番で安全な設計では、まず制約されているリソースを特定し、そのうえでペーシング、キューイング、リトライ、トークン削減、あるいは別経路へのルーティングを選択します。
このガイドでは、その仕組みを説明し、キャパシティプランニングの式を示し、OpenAI互換API向けの上限付きTypeScriptリトライパターンを紹介します。
RPM vs. TPM: the quick answer
| Limit | Measures | Workloads that hit it first | Best first response |
|---|---|---|---|
| RPM | プロバイダーが定義した時間枠内で受け付けられたリクエスト数 | 小さな呼び出しが多い場合、エージェントのツールループ、高分岐の評価 | リクエストをペース制御する、処理をバッチ化する、またはバーストをキューに入れる |
| TPM | 時間枠内で受け付けられた入力トークンおよび/または出力トークン | 長いコンテキスト、大きな出力、検索量の多いプロンプト、並列評価 | トークン量を削減する、出力を制限する、またはキャパシティを別経路に振り分ける |
| RPD | 1日あたりのリクエスト数 | 定期実行のクローリング、広範なオフライン評価、無料プランのワークロード | スケジュールを変更するか、サービスティアを引き上げる |
| Concurrent requests | 同時に処理中のリクエスト数 | 遅い生成処理とストリーミングワークロード | ワーカー数を制限し、バックプレッシャーを適用する |
| 429 | 制限またはキャパシティポリシーによりリクエストが拒否された | 有効なバケットを超えるあらゆるワークロード | リトライする前にエラーを分類する |
RPMは頻度を制御します。TPMはスループットを制御します。同時実行数は同時に行う作業量を制御します。 これらは相互に関係しますが、同義ではありません。
Why a request can fail below the headline limit
600 RPMのような公開された制限値は、必ずしもクライアントが毎分の最初の1秒に600件のリクエストを送れることを意味しません。プロバイダーは一般的に、ローリングウィンドウやトークンバケット型の制御で制限を適用します。短いバーストでも、その分単位の計算上は安全に見えても、直ちに利用可能なキャパシティを使い切ってしまうことがあります。
429が早い段階で表示されるその他の理由には、次のようなものがあります。
- 制限は1つのAPIキーではなく、プロジェクト、組織、アカウント、モデルファミリー、またはサービスティアに適用される。
- 入力トークンと出力トークンで別々のバケットが使われる。
- 複数のワーカー、サービス、またはユーザーが同じクォータプールを共有している。
- 過去の失敗によるリトライが同じ制限を消費している。
- トラフィックが急激に増加する際に、プロバイダーが加速制限またはバースト制限を適用している。
- 別のモデルにはまだキャパシティがあるのに、モデル固有のプールが満杯である。
そのため、アプリケーションは自分自身のリクエストカウンターだけから原因を推測すべきではありません。レスポンスボディとヘッダーを読み、プロバイダーのリクエストIDを保持し、モデル、アカウント、トークン見積もり、試行回数、キュー遅延をログに記録してください。
A practical capacity formula
2つの独立した上限から始めます。
request_ceiling = RPM × safety_factor
token_ceiling = (TPM × safety_factor) ÷ average_tokens_per_request
safe_requests_per_minute = min(request_ceiling, token_ceiling)
1.0未満の安全係数を使います。たとえば0.7〜0.9にして、トークンのばらつき、リトライ、共有利用者、不均一な到着パターンを吸収します。
例
あるモデルプールで以下が許可されているとします。
- 1,000 RPM
- 2,000,000 TPM
- 1リクエストあたり平均合計4,000トークン
- 80%の運用安全係数
request_ceiling = 1,000 × 0.8 = 800 requests/minute
token_ceiling = (2,000,000 × 0.8) ÷ 4,000
= 400 requests/minute
safe_requests_per_minute = min(800, 400) = 400
TPMが制約要因です。ワーカーを増やしても持続可能なスループットは増えず、キューが大きくなるか、429応答が増えるだけです。
オンラインシステムでは、リトルの法則を使ってスループットを並行実行数の出発点に変換します。
target_concurrency ≈ requests_per_second × average_request_seconds
安全なレートが1分あたり400リクエスト(1秒あたり6.67リクエスト)で、モデルの平均レイテンシーが3秒なら、開始時の並行実行数は約20です。余裕は慎重に追加し、その後は実測のp95レイテンシーとトークン分布に基づいて調整します。
トークン制限はしばしば見えないボトルネック
チームはリクエスト数を監視していても、トークン量を見落としがちです。次のような場合にTPMの圧力は高まります。
- 各プロンプトに取得ドキュメントをさらに追加する。
- 長い会話履歴を保持する。
- タスクごとに複数の候補補完を実行する。
- 出力上限を増やす。
- 同じ大きなシステムプロンプトを繰り返し送信する。
- 1つのプロジェクトクォータに対して並列評価スイートを起動する。
成功した各リクエストについて、少なくとも次の4つのトークン値を測定します。
- 入力トークン。
- 出力トークン。
- 合計トークン。
- ワークロードとモデル別のロールिंगp50、p95、最大値。
平均だけで容量計画を立てるのは楽観的です。より安全なスケジューラは、高いパーセンタイルまたはワークロード固有の推定値に対して予約を行い、完了後に実使用量と照合します。
429の意味と、意味しないこと
HTTP 429 Too Many Requests は、サーバーが有効な制限または容量ポリシーの下でリクエストを拒否したことを示します。自動的に「1秒待って再試行」を意味するわけではありません。
429を運用上のバケットに分類します。
| 429 class | 証拠 | 正しい対応 |
|---|---|---|
| 短いバースト | 直近のスパイク。リトライヘッダーは短く、キューはそれ以外では健全 | サーバーのヒントを待ってから、ジッター付きで再試行する |
| 継続的なRPM枯渇 | リクエストレートが上限付近に張り付いている | ペースを落とすかキューに入れる。リトライだけでは解決できない |
| 継続的なTPM枯渇 | トークンレートが高い。長いプロンプトや出力が支配的 | トークンを減らす、作業を遅らせる、または別の利用可能なプールにルーティングする |
| 日次またはティア制限 | エラーが日次クォータ、請求、またはティア制限を示している | リトライを停止し、再スケジュールするかアカウント容量を変更する |
| 加速制限 | トラフィックが低いベースラインから急速に増加した | 徐々に増加させ、バーストを平準化する |
| プロバイダーのキャパシティイベント | クライアント側のレートは正常だが、一時的な拒否が繰り返される | 小さなリトライ予算を使い、その後は契約上安全なフォールバックを使う |
本文とヘッダーはプロバイダーによって異なります。提供される場合は、明示的な Retry-After またはレート制限リセットのシグナルを優先してください。それ以外の場合は、ランダムジッター付きの指数バックオフを使用します。
ジッター付き指数バックオフ
指数バックオフは、失敗するたびに待機時間を増やします。ジッターはその待機時間をランダム化し、数百のワーカーが同時に再試行しないようにします。
よく使われるフルジッターの式の一つは次のとおりです:
delay_ms = random(0, min(cap_ms, base_ms × 2^attempt))
本番環境のリトライポリシーには、次の境界条件も必要です:
- 最大試行回数: 通常は少数であり、無限ループにはしない。
- 最大経過時間: 呼び出し元のレイテンシ予算が尽きたら停止する。
- リトライ可能なステータス一覧: 一般的には
429、選択された5xx応答、および安全なネットワーク障害。 - サーバーヒント: 有効な場合は
Retry-Afterを尊重する。 - キャンセル: 上流のリクエストが中止されたら直ちに停止する。
- 可観測性: 試行回数、待機時間、最終ステータス、プロバイダーのリクエストIDを記録する。
失敗したリクエストでもレート制限の容量を消費する場合があります。そのため、攻撃的なリトライはスロットリング期間を延ばす可能性があります。
TypeScript: 境界付きリトライヘルパー
次の例では、OpenAI互換の Flatkey ベースURLを使用します。成功レスポンスの本文が消費される前にのみ再試行し、試行回数の上限または合計時間予算のいずれかが尽きた時点で停止します。
type ChatRequest = {
model: string;
messages: Array<{ role: "system" | "user" | "assistant"; content: string }>;
max_tokens?: number;
};
const sleep = (milliseconds: number) =>
new Promise((resolve) => setTimeout(resolve, milliseconds));
function retryAfterMilliseconds(response: Response): number | null {
const value = response.headers.get("retry-after");
if (!value) return null;
const seconds = Number(value);
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1_000);
const date = Date.parse(value);
return Number.isNaN(date) ? null : Math.max(0, date - Date.now());
}
export async function createChatCompletion(
apiKey: string,
request: ChatRequest,
options: { maxAttempts?: number; maxElapsedMs?: number } = {},
) {
const maxAttempts = options.maxAttempts ?? 4;
const maxElapsedMs = options.maxElapsedMs ?? 30_000;
const startedAt = Date.now();
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
const response = await fetch(
"https://router.flatkey.ai/v1/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(request),
},
);
if (response.ok) return response.json();
const retryable = response.status === 429 || response.status >= 500;
const finalAttempt = attempt === maxAttempts - 1;
if (!retryable || finalAttempt) {
throw new Error(`LLM リクエストは ${response.status} で失敗しました: ${await response.text()}`);
}
const hintedDelay = retryAfterMilliseconds(response);
const exponentialCap = Math.min(8_000, 500 * 2 ** attempt);
const jitteredDelay = Math.random() * exponentialCap;
const delayMs = hintedDelay ?? jitteredDelay;
if (Date.now() + delayMs - startedAt >= maxElapsedMs) {
throw new Error("LLM のリトライ予算を使い切りました");
}
await sleep(delayMs);
}
throw new Error("到達不能なリトライ状態");
}
本番利用では、リクエストのタイムアウト、構造化されたエラー型、メトリクス、およびアプリケーションのキャンセルシグナルを追加してください。操作がメール送信やツール実行のような外部副作用を発生させる可能性がある場合は、リトライする前にビジネス操作を冪等にしてください。
Retry, queue, reduce, or route?
制御を選ぶ際は、ステータスコードだけでなく原因を使ってください。
| 状況 | リトライ | キュー | トークン削減 | 別経路へルーティング |
|---|---|---|---|---|
単発の一時的な 429 |
はい、上限付きで | 任意 | いいえ | 通常はいいえ |
| RPM枯渇の繰り返し | 限定的に | はい | いいえ | 場合による |
| TPM枯渇の繰り返し | 限定的に | はい | はい | 多くの場合有用 |
| 日次クォータの枯渇 | いいえ | 後で | 任意 | はい、ポリシーで許可される場合 |
プロバイダの 5xx 障害 |
はい、上限付きで | はい | いいえ | リトライ予算の後にはい |
| 部分的なストリーミング応答 | 自動再実行なし | アプリケーション依存 | いいえ | 明示的な復旧セマンティクスがある場合のみ |
リトライ
失敗が一時的で、呼び出し側にまだ時間がある場合はリトライします。リクエストごとのリトライ予算とサービスレベルのリトライ予算を保持し、プロバイダ障害が総トラフィックを増幅しないようにします。
キュー
到着レートが一時的に持続可能なサービスレートを上回る場合はキューに入れます。役立つキューは次の情報を提供します。
- 最古アイテムの経過時間。
- 開始予定時刻。
- テナントごとの公平性。
- 古くなったジョブのキャンセル。
- 明示的なドロップ動作を伴う最大深度。
トークン削減
TPMが制約になる場合は、無関係なコンテキストを削除し、履歴を要約し、候補数を減らし、出力上限を下げ、対応している場合は再利用可能なプロンプト接頭辞をキャッシュし、短い対話トラフィックと長いバッチジョブを分離します。
別経路へルーティング
別のモデルやプロバイダが同じ契約を満たし、十分な容量を持つ場合はルーティングが適切です。フォールバックは、構造化出力、ツール呼び出し、コンテキスト長、安全ポリシー、レイテンシ目標など、必要な機能を維持しなければなりません。より深い実装フレームワークについては、LLM API fallback routing playbook を参照してください。
モデル評価におけるレート制限
不適切なスロットリングは評価を無効にする可能性があります。
たとえば、モデルAを10ワーカーでテストし、モデルBを100ワーカーでテストしたとします。モデルBのほうがスロットリングにより多くの時間を費やす場合、その測定レイテンシには、モデルAが一度も直面しなかったキュー待ちとリトライ遅延が含まれます。結果はモデル性能ではなく、ハーネス構成を表しているかもしれません。
妥当な比較のためには、次のようにします。
- モデルレイテンシ、キュー遅延、リトライ遅延を分ける。
- すべてのプロバイダに同じ到着プロセス、または正規化した利用率レベルを適用する。
- プロバイダが加速制御を使用する場合は、トラフィックを徐々にウォームアップする。
- 完了したタスクごとのトークン数と試行回数を記録する。
- 初回試行成功率と最終的な成功率の両方を報告する。
- トークンあたりのコストだけでなく、受理されたタスクあたりのコストを比較する。
- オーバーロードテストは、品質およびレイテンシのベンチマークとは別に実施する。
信頼性とコストの両方でプロバイダーを評価している場合は、このプロセスをAI API pricing comparisonと組み合わせてください。
本番向けのレート制限アーキテクチャ
堅牢なリクエスト経路は通常、5つの制御レイヤーで構成されます。
- アドミッション制御は、締め切りに間に合わない作業を拒否するか延期します。
- トークン予約は、リクエストの想定クォータコストを見積もります。
- レートリミッターは、各プロバイダー、モデルプール、テナント、優先度クラスの処理速度を調整します。
- リトライコントローラーは、ジッター付きで上限のあるリトライ予算を消費します。
- ルーターは、リトライ予算または容量ポリシーに従って移動すべきと判断された後、契約互換の代替先を選択します。
client
→ admission control
→ priority queue
→ RPM + token reservation limiter
→ provider/model route
→ bounded retry
→ contract-safe fallback
→ usage and latency logs
各アプリケーションワーカーに無制限のリトライループを配置しないでください。ポリシーを中央集約し、すべての呼び出し元が利用可能な容量について同じ認識を共有するようにします。
アラートを出す価値のあるメトリクス
これらを、プロバイダー、モデル、プロジェクト、ルート、テナント、ワークロードごとに追跡します。
- 1分あたりのリクエスト数と1分あたりのトークン数。
- 予約済みの推定トークン数と実際に使用したトークン数。
- 初回試行の成功率。
- 成功したリクエストあたりのリトライ回数。
- 分類された原因ごとの
429発生率。 - キューの深さと最古アイテムの経過時間。
- レート容量の待機に費やした時間。
- エンドツーエンドのp50、p95、p99レイテンシー。
- フォールバック率とフォールバック結果。
- 成功または受理されたタスク1件あたりのコスト。
総429件数だけに対するアラートはノイズが多くなります。より良いシグナルは、スロットリング率、キューの滞留時間、リトライ増幅、最終失敗率を組み合わせたものです。
よくある誤り
RPMを同時実行数の制限として扱うこと
RPMは時間あたりの受付数を測定し、同時実行数は処理中の作業量を測定します。遅いリクエストは、控えめなRPMでも高い同時実行数を生むことがあります。
すべての429を即座にリトライすること
即時リトライはワーカーを同期させ、より多くの容量を消費します。利用可能な場合はサーバー側のタイミングを尊重し、ジッターを追加してください。
すべてのモデルに1つのリミッターを使うこと
プロバイダーは個別または共有のプールを使う場合があります。モデル別ポリシーは、プロバイダーの文書化されたクォータ範囲と観測されたヘッダーに従うべきです。
共有コンシューマーを無視すること
ダッシュボード、バッチジョブ、本番APIが1つのプロジェクトクォータを共有している場合があります。ワークロードごとに容量を確保し、可能な限り重要なトラフィックを分離してください。
部分的なストリームをリトライすること
一度トークンがユーザーに届いた後にリクエストを再実行すると、コンテンツやツール操作が重複する可能性があります。黙ってリトライするのではなく、継続または再開の明示的なセマンティクスを定義してください。
Flatkeyが運用モデルをどう変えるか
Flatkeyは、対応するモデルプロバイダー全体へのアクセスに対して、1つのAPIキーとOpenAI互換のベースURLを提供します。これにより、アプリケーションは1つの統合面を持ちながら、ルーティングポリシーではモデル適合性、容量、信頼性、コストを考慮できます。
ゲートウェイは上流の制限を取り除くわけではありません。代わりに、それらの周囲で一貫した制御を実装しやすくします。つまり、1つのクライアント統合、集中管理されたリクエストログ、そしてルートが制約されている場合に対象トラフィックを移動するオプションです。より広いルーティング設計についてはAI APIゲートウェイアーキテクチャガイドを確認するか、本番ルートを選択する前に現在のFlatkeyの料金をご覧ください。
FAQ
RPMとTPMの違いは何ですか?
RPMは、一定時間内に何件のリクエストを受け付けるかを制限します。TPMは、受け付ける入力トークンおよび/または出力トークンの量を制限します。小さなプロンプトでは通常、最初にRPMが圧迫されますが、大きなコンテキストや高出力のワークロードでは、最初にTPMが圧迫されることがよくあります。
RPMの制限を下回っているのに、なぜ429エラーが出るのですか?
プロバイダーは、より短いローリングウィンドウ、トークンバケット、共有プロジェクト割り当て、個別のトークン制限、加速制限、またはモデル固有のプールを適用している場合があります。ローカルのリクエストカウンターは、クォータ全体の範囲を表していない可能性があります。
429は毎回リトライすべきですか?
いいえ。短時間のスロットリングには、少ない試行回数とジッターを伴ってリトライしてください。日次クォータの枯渇、課金制限、または回復する時間のない継続的な過負荷を、繰り返しリトライしてはいけません。
指数バックオフは成功を保証しますか?
いいえ。バックオフは衝突を減らし、一時的なキャパシティが回復するための時間を与えます。クォータを生み出すことはできません。継続的な枯渇には、需要の削減、キャパシティの追加、作業の遅延、または別の利用可能なルートが必要です。
LLMリクエストでは何回リトライすべきですか?
万能の回数はありません。ユーザーに見えるレイテンシ予算と失敗モードに基づいて試行回数を設定してください。多くの対話型アプリケーションでは、失敗または別ルートへの切り替えの前に、短い試行を数回 మాత్రమే許可すべきです。オフラインジョブなら、より長いキューを許容できます。
リトライはレート制限の対象になりますか?
対象になる場合があります。プロバイダーは失敗した試行をアクティブな制限に対してカウントすることがあるため、リトライの増幅は監視し、上限を設ける必要があります。
最終チェックリスト
- RPM、TPM、日次制限、同時実行数を個別に把握する。
- リクエスト上限とトークン上限の最小値からキャパシティを計算する。
- 安全係数を設け、公開されている最大値を下回って運用する。
- 持続的な負荷にはキューとペーシングを使用する。
Retry-Afterを尊重し、ジッター付きの指数バックオフを使用する。- 試行回数と総リトライ時間に上限を設ける。
- 部分ストリームや副作用を自動的に再実行しない。
- 必要な契約を維持するモデルにのみルーティングする。
- 評価では、キューとリトライの遅延をモデルのレイテンシから分離する。
- 生の
429件数だけでなく、リトライ増幅とキュー滞留時間でもアラートを出す。
レート制限は、まずキャパシティ計画の問題であり、リトライの問題ではありません。リクエスト頻度、トークンスループット、同時実行数、リトライ増幅を個別に測定できるようになると、429エラーは予測不能な本番ノイズではなく、実行可能なシグナルになります。



