ガイド一覧へ戻る
トラブルシューティング·2026年8月5日·最終更新 2026年9月30日·読了9分

OpenAI APIのレート制限 — どの制限に達したか、読み取り方、解決につながるリトライ

OpenAIからの429は、5つある上限のいずれかを超えたことを意味します。どの上限かによって、対策は正反対になります。レスポンスヘッダーから答えを直接読み取る方法と、実際にエラーを止めるリトライロジックを解説します。

最終確認日:。

OpenAIの429は、5つの上限のいずれかを超えたことを意味します — 最初にすべきことは、どの上限かを特定することです。対策の方向が正反対だからです。このページでは、各制限が測定するもの、レスポンスヘッダーから答えを直接読み取る方法、エラーを実際に止めるリトライロジック、正しいバックオフでも不十分な場合の対処法を説明します。

2026年9月30日に対して検証済み — OpenAIのレート制限ドキュメントに基づいています。

5つの制限 — いずれも単独で発動する可能性があります

指標測定対象通常、問題になる状況
RPM1分あたりのリクエスト数多数の小さな呼び出し — 分類、埋め込み、エージェントループ
TPM1分あたりのトークン数少数の大きな呼び出し — 大量の取得コンテキストを使うRAG、長文書
RPD1日あたりのリクエスト数Freeおよび低位ティア、1日のクォータを使い切るバッチジョブ
TPD1日あたりのトークン数同じく、トークン数で測定
IPM1分あたりの画像数画像生成ワークロード

最初に使い切った制限がエラーを発生させるため、「トークン制限にはまだ十分余裕がある」ことは、レート制限を除外する理由にはなりません。TPMには余裕があっても、RPMにはちょうど到達している可能性があります。制限はキー単位ではなく、組織単位かつモデル単位です。キーを追加してもクォータは増えません。

429の見え方

応答(HTTP 429)
HTTP/1.1 429 Too Many Requests
retry-after: 12
x-ratelimit-limit-requests: 500
x-ratelimit-remaining-requests: 0
x-ratelimit-reset-requests: 12s
x-ratelimit-limit-tokens: 200000
x-ratelimit-remaining-tokens: 143820
x-ratelimit-reset-tokens: 17s

{
  "error": {
    "message": "Rate limit reached for gpt-5.4 in organization org-... on requests per min (RPM).",
    "type": "requests",
    "code": "rate_limit_exceeded"
  }
}

必要な情報はすべてそのレスポンスにあります。本文には指標(「requests per min (RPM)」)が記載され、ヘッダーには正確な上限、残りの量、復旧時刻が示されます。

ヘッダー意味
retry-after再試行する前に待つ最小秒数
x-ratelimit-limit-requests制限を使い切るまでに許可される最大リクエスト数
x-ratelimit-remaining-requests使い切るまでに残っているリクエスト数
x-ratelimit-limit-tokens許可される最大トークン数
x-ratelimit-remaining-tokens残りのトークン数
x-ratelimit-reset-requests / -reset-tokens各カウンターがリセットされるまでの時間 — それぞれ独立してリセットされます

利用ティア

上限は利用ティアによって決まり、累積支出が増えるとOpenAIが自動的に昇格させます:

階層条件月間利用上限
無料許可された地域のユーザー月額$100
Tier 1支払い済み$5月額$100
Tier 2支払い済み$50月額$500
Tier 3支払い済み$100月額$1,000
Tier 4支払い済み$250月額$5,000
Tier 5支払い済み$1,000月額$200,000

モデル別のRPMおよびTPMの数値は、意図的にここには掲載していません。 モデルごとに異なり、モデルのリリースに伴って変わり、アカウントごとに調整される可能性があるためです。そのため、第三者サイトに掲載された数値表は、日付付きの推測にすぎません。自分のアカウントに関する権威ある情報源は、OpenAIダッシュボードの制限ページと、実行済みのすべてのレスポンスに含まれるx-ratelimit-*ヘッダーの2つです。ヘッダーを読んでください。

解決策:Retry-Afterに従い、その後ジッターを加える

OpenAIの公式推奨は、レスポンスにRetry-Afterが含まれている場合はそれに従い、ジッター付きの指数バックオフを行うことです。両方の要素が重要です。ヘッダーがなければ再試行が早すぎる可能性があり、ジッターがなければ、同じ瞬間に失敗したすべてのクライアントが同じ瞬間に再試行して一斉に失敗します — 1秒の障害を1分の障害に変える「サンダリングハード」です。

backoff.py
import random, time
import openai

client = openai.OpenAI()

def call_with_backoff(fn, *, max_attempts=6, base=0.5, cap=30.0):
    """Retry 429s: honour Retry-After when present, jittered backoff otherwise."""
    for attempt in range(max_attempts):
        try:
            return fn()
        except openai.RateLimitError as err:
            if attempt == max_attempts - 1:
                raise
            # The server's own answer beats any formula you invent.
            retry_after = (err.response.headers or {}).get("retry-after")
            if retry_after:
                delay = float(retry_after)
            else:
                # Full jitter: sleep a random point in [0, 2^n * base], capped.
                # Without the randomness every client that failed at the same
                # instant retries at the same instant and fails again together.
                delay = random.uniform(0, min(cap, base * 2**attempt))
            time.sleep(delay)

resp = call_with_backoff(lambda: client.responses.create(
    model="gpt-5.4",
    input="Summarise this changelog in three bullets.",
))

TypeScriptでも同じ形になります:

backoff.ts
import OpenAI from "openai";

const client = new OpenAI();
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

export async function callWithBackoff<T>(
  fn: () => Promise<T>,
  { maxAttempts = 6, baseMs = 500, capMs = 30_000 } = {},
): Promise<T> {
  for (let attempt = 0; ; attempt++) {
    try {
      return await fn();
    } catch (err) {
      const status = (err as { status?: number }).status;
      if (status !== 429 || attempt === maxAttempts - 1) throw err;

      const retryAfter = (err as { headers?: Headers }).headers?.get("retry-after");
      const delay = retryAfter
        ? Number(retryAfter) * 1000
        : Math.random() * Math.min(capMs, baseMs * 2 ** attempt);
      await sleep(delay);
    }
  }
}

const resp = await callWithBackoff(() =>
  client.responses.create({ model: "gpt-5.4", input: "Hello" }),
);

公式SDKは429を自動的に再試行するため、ほとんどのアプリケーションでこれが必要になるのは、自分のHTTPクライアントで呼び出しをラップする場合、または別の動作が必要な場合だけです。たとえば、バックグラウンド処理により長い待機時間の上限を設定する場合や、12秒待つよりエラーになるほうがよいユーザー向けリクエストを即座に失敗させる場合です。

壊れる前に監視する

カウンターは失敗時だけでなく、すべてのレスポンスに含まれます。残りの値をログに記録すれば、レート制限をインシデントではなくゲージとして扱えます — リリースによって使い切る数日前から、余裕が縮小していることを確認できます。

observe_quota.py
# Log the remaining counters on every response, not just on failures.
# By the time you see a 429 the useful signal is already an hour old.
resp = client.responses.with_raw_response.create(model="gpt-5.4", input="…")
h = resp.headers

log.info(
    "openai_quota model=%s req_left=%s tok_left=%s reset_req=%s reset_tok=%s",
    "gpt-5.4",
    h.get("x-ratelimit-remaining-requests"),
    h.get("x-ratelimit-remaining-tokens"),
    h.get("x-ratelimit-reset-requests"),
    h.get("x-ratelimit-reset-tokens"),
)

parsed = resp.parse()   # the normal response object

これと併せて役立つ習慣が2つあります。429の件数ではなく、x-ratelimit-remaining-tokensが制限の一定割合を下回った時点でアラートを出すこと、そしてリトライだけでなくスケジュールにもジッターを追加することです。 :00にすべてを実行するcronは、自らバーストを作り出します。

バックオフでは解決しない場合

正しいバックオフはバーストを解消します。しかし、上限を超える持続的な需要には効果がありません。その場合、再試行は失敗を後ろ倒しにするだけです。労力の目安として、構造的な対策は次の順です:

  • 出力を制限する。推論トークンは請求対象となり、出力としてカウントされるため、無制限の生成はTPMを最も早く消費します。
  • 取得コンテキストを削減する。TPM上限下では、取得チャンクを半分にすると、追加費用なしでスループットが2倍になります。
  • モデルのサイズを適正化する。分類処理に最先端モデルは不要であり、小型モデルには独立した予算があります。
  • ワークロードを分離する。バッチジョブとレイテンシーに敏感なトラフィックが1つの組織レベルの上限を奪い合うのは、この問題を自ら引き起こす最も一般的な形です。
  • ティアを上げる。ティアは累積支出に応じて上がるため、これはすでに進行している場合も多くあります。

モデルファミリー間で負荷を分散する

このリストの最後の項目で、ゲートウェイが価値を発揮します。Kunavoは複数のモデルファミリーにわたり、OpenAI互換API(同じSDK、同じ呼び出し形式、1つのキー)を提供しています。そのため、飽和した上限からワークロードを移す際に必要なのは、2つ目の統合ではなくモデル文字列の変更です:

gateway.py
from openai import OpenAI

client = OpenAI(
    api_key="sk-kn-...",
    base_url="https://api.kunavo.com/v1",
)

# Same SDK, same call shape — the model string chooses the family.
client.chat.completions.create(
    model="gpt-5-6-terra",            # or claude-sonnet-5, claude-haiku-4-5, …
    messages=[{"role": "user", "content": "Hello"}],
)

具体的には、本番トラフィックと競合していたバッチ要約ジョブを、100万あたり$0.70 / $3.50の料金でclaude-haiku-4-5上で実行し、レイテンシーに敏感な経路はgpt-5-6-terra($0.70 / $4.20)またはclaude-sonnet-5($1.40 / $7.00)に残せます。異なるファミリーなら、異なるキューになります。

この仕組みでできることと、できないことを明確にしておきましょう。単一アカウント・単一モデルのボトルネックを解消し、フェイルオーバー先を提供します。しかし容量を生み出すことはできません。総量が単一ティアの許容量を本当に超えている場合は、ティアを上げるか作業量を減らす必要があります。すべてのモデルの料金は料金ページにあり、Anthropicの制限に対する同等の手順はClaude API 429 rate_limit_errorにあります。

よくある質問

OpenAIのAPIレート制限とは何ですか?

OpenAIは、RPM(1分あたりのリクエスト数)、TPM(1分あたりのトークン数)、RPD(1日あたりのリクエスト数)、TPD(1日あたりのトークン数)、IPM(1分あたりの画像数)の5つの指標を同時に計測し、いずれか1つを超えると直ちにHTTP 429を返します。実際の上限は利用ティアと特定のモデルによって異なるため、アカウントに適用される正確な数値は、OpenAIダッシュボードの組織の制限ページと、すべてのレスポンスに含まれるx-ratelimit-*ヘッダーで確認してください。公開された表ではありません。

OpenAIの利用ティアとは何ですか?

2026年9月30日時点で、OpenAIは6つのティアを案内しています。各ティアは累積支出によって利用可能になり、月間利用上限が設定されています:Free(対応地域で利用可能、月間利用上限$100)、$5支払い後のTier 1(月間利用上限$100)、$50支払い後のTier 2(月間利用上限$500)、$100支払い後のTier 3(月間利用上限$1,000)、$250支払い後のTier 4(月間利用上限$5,000)、$1,000支払い後のTier 5(月間利用上限$200,000)。支出が累積すると自動的に昇格します。

OpenAIの429 rate_limit_exceededを解決するには?

レスポンスにRetry-Afterヘッダーが含まれている場合はそれに従い、含まれていない場合は、ランダムなジッターを加えた指数バックオフで再試行してください — これはOpenAIが公式に推奨している方法です。公式SDKはすでに自動再試行を行います。自作のHTTPクライアントでは実装が必要です。正しいバックオフ後も429が続く場合、単なるバーストではなく、実際にクォータを超えています。構造的な対策は、バッチを小さくする、最大出力トークン数を制限する、スケジュール済みジョブを1分間に分散する、または上位ティアへ移行することです。

実際にどのレート制限に達したか確認するには?

ヘッダーを読みます。x-ratelimit-remaining-requestsがゼロならリクエスト制限、x-ratelimit-remaining-tokensがゼロならトークン制限に達しています。2つは独立してリセットされます。x-ratelimit-reset-requestsとx-ratelimit-reset-tokensで、それぞれ復旧する時刻を確認できます。メッセージ本文にも該当する指標が記載されます。両者の対策は逆なので、推測すると時間を無駄にします。リクエスト制限にはキューイング、トークン制限には短いプロンプトが必要です。

レート制限はキー単位ですか、それとも組織単位ですか?

キー単位ではなく、組織単位かつモデル単位です。APIキーを増やしてもクォータは増えません。そのため、同じ組織内の本番ワークロードとバッチジョブは同じ上限を奪い合います。キーを追加するより、分離することが重要です。

ゲートウェイでOpenAIのレート制限に対処できますか?

1つのアカウントのモデル単位の上限がボトルネックになっている場合には役立ちます。ゲートウェイを使うと、同じキーと同じSDKのまま、別のモデルファミリーへ作業を移せるためです。バッチ要約ジョブを、レイテンシーに敏感なトラフィックと同じキューに入れる必要はありません。ただし、ゼロから容量を生み出すことはできません。総量が単一ティアの許容量を本当に超えている場合は、ティアを上げるか作業量を減らす必要があります。

新しく作ったアカウントなのに、なぜレート制限にかかるのですか?

FreeとTier 1のアカウントには、上位ティアにはない1日単位の上限(RPDとTPD)があるため、控えめなテストスクリプトでも午後のうちに1日分の許容量を使い切ることがあります。Tier 1は累積支払い$5で解除されます。

429が発生すると料金がかかりますか?

いいえ — 拒否されたリクエストは処理されず、請求もされません。発生するコストはレイテンシーと、そのレイテンシーに対してリトライロジックが行う処理です。

APIキーを増やせばスループットは上がりますか?

いいえ。制限は組織単位かつモデル単位です。追加キーは帰属管理や無効化には役立ちますが、容量は増やしません。

429は自分で捕捉すべきですか、それともSDKに任せるべきですか?

通常のケースはSDKに任せ、デフォルトの動作が自分の用途に合わない場合だけ自分で捕捉してください。たとえば、即座に失敗させるべきユーザー向けリクエストや、デフォルトよりはるかに長い待機時間を許容できるバックグラウンドジョブです。

実際にはクォータ枯渇である429については?

月間利用上限を使い切った場合も429として返され、バックオフをいくら行っても解消されません — メッセージ本文で両者を区別できます。ヘッダーのカウンターが正常なのに拒否され続ける場合は、リトライコードを変更する前に請求状況を確認してください。