Prompt Rate Limits & Batching: Your LLM API Has a Speed Limit (たとえあなたの製品がそうでないとしても) あなたは機能を送信し、あなたのトラフィックがピークし、突然あなたのLLMレイヤーが戻り始める まるで駐車券を発行しているかのように。 429s 悪いニュース:料金制限は避けられない。 良いニュース: 通常、大規模なプロンプト、爆発的なトラフィック、およびスケールで解析できない出力フォーマットによって発生します。 most LLM “rate limit incidents” are self-inflicted この記事は、以下のために実践的なプレイブックです。 早速関連のゴールを理解し、 共通の失敗モードを回避し、そして 答えをスープに変えることなく、リクエストをバッチリする。 1)あなたが実際に打った3つの限界(そしてそれらの意味) さまざまなプロバイダは物事を異なって名付けていますが、メカニズムは一貫しています。 1.1 コンテキストウィンドウ(リクエストごとに最大トークン) もしあなたの モデルコンテキストウィンドウを超えると、リクエストが即座に失敗します。 input + output 症状 : 「最大コンテキスト長度を超えた」 「あなたのメッセージはXトークンを生み出した・・・」 フィックス: 短縮、概要、またはデータを切断します。 1.2 RPM(リクエスト毎分) あなたはトークン制限の下にあり、あまりにも多くの呼び出しを吹き飛ばした場合にも引きずり込まれる可能性があります Gemini は RPM をコアの次元として明示的に文書化します。 症状 : “Rate limit reached for requests per minute” (毎分のリクエストに達した料金制限) HTTP 429 フィックス: クライアント側のペーシング、列、そしてバックオフ。 1.3 TPM/トークンパスポート制限 Anthropic measures rate limits in 関連記事 (ITPM/OTPM) ジェミニーは同様に、トークン毎分をキー次元として説明しています。 RPM + input tokens/minute + output tokens/minute 症状 : 「Token Usage Per Minute」に達した料金制限 429 + Retry-After header (Anthropic calls this out) フィックス: トークンを削減し、バッチを効率的に、またはより高い割合を要求します。 2)最も一般的な「早期限」の失敗パターン 2.1 「one prompt to rule them all」の反パターン あなたは求める: 抽出 分類 書き換え 認証 形式化 ビジネス論理 ...一つのリクエストで、そしてなぜトークンの使用がピークするのか疑問に思います。 複数の段階の論理が必要な場合は、 (構造化された中間出力を持つ小さなプロンプト) Split the workflow Prompt Chaining Bursty Traffic (The Silent RPM Killer) Cron jobs、retries、user clicks、webhook bursts — everything aligns in the worst possible minute. Cron jobs, retries, user clicks, webhook bursts — everything aligns in the worst possible minute. Cron jobs, user clicks, webhook bursts — everything aligns in the worst possible minute. Cron jobs, retries, user clicks, webhook bursts — everything aligns in the worst possible minute. クライアントが機械銃のようにリクエストを送信する場合、プロバイダーはボンサーのように反応します。 2.3 非構造化された出力 = コストの高いパッシング 出力が「kinda JSON-ish」であれば、パッサーはフルタイムのセラピストになります。 モデル output あるいは固定テーブル. 形式を契約として扱う。 strict JSON 3) Rate Limit Survival Kit (Compliant, Practical, Boring) 3.1 Prompt-side: 信号を失うことなくトークンを縮小 マーケティングフローを削除します(モデルはあなたの会社の起源ストーリーを必要としません)。 繰り返しのボイラープレートを短い「ポリシーブロック」に変換し、再利用します。 「材料=316ステンレス鋼」は段落を打つ。 通常、30~50%を節約する小さなリモート書き換え Before (chatty): 「2010年に設立されたスマートホームブランドです...3つのマーケティングラインを書いてください。 「2010年に設立されたスマートホームブランドです...3つのマーケティングラインを書いてください。 After (dense + precise): “Write 3 UK ecommerce lines. Product: smart bulb. Material=PC flame-retardant. Feature=3 colour temperatures. Audience=living room.” “Write 3 UK ecommerce lines. Product: smart bulb. Material=PC flame-retardant. Feature=3 colour temperatures. Audience=living room.” 3.2 リクエスト側:大人のようにバックコフ プロバイダーが帰ってくる場合 Anthropic は 429s で Retry-After を明示的に返します。 Retry-After Exponential Backoff + Jitter を使用する。 試み1:1S 試み2:2-3s 試み 3: 4 - 6s 優雅に失敗する 3.3 システム側:列 + 競合カプセル あなたのアカウントが10の同時リクエストをサポートしている場合は、200のリクエストと「希望」を実行しないでください。 使用: 仕事の列 競争のためのセマフォー RPM/TPMの制限値 4)バッチング:通話、コスト、および429を削減する最速の方法 バッチングとは: . one API request handles multiple independent tasks タスクが最適なときは: 同じタイプ(たとえば、20製品ブラーブ) 独立(一歩も他者に依存しない) 同じ出力スケジュール なぜ役立つのか ネットワーク・ラウンド・トリップの減少 リクエスト数が減り、RPM圧力が下がる より予測可能なパスポート また、OpenAIの価格ページには、いくつかのモデルの「バッチAPI価格」列が明示的に含まれています(これは「バッチングは無料」という意味ではありませんが、エコシステムがこのパターンを期待している強力なヒントです)。 5) 分離しないバッチング・プロンプト・テンプレート The Batching Prompt Template That Doesn't Fall Apart 以下は、圧力の下で読み取れるフォーマットです。 5.1 タスクブロック + 厳格な JSON 応答スケジュールを使用する SYSTEM: You output valid JSON only. No Markdown. No commentary. USER: You will process multiple tasks. Return a JSON array. Each item must be: { "task_id": <int>, "title": <string>, "bullets": [<string>, <string>, <string>] } Rules: - UK English spelling - Title ≤ 12 words - 3 bullets, each ≤ 18 words - If input is missing: set title="INSUFFICIENT_DATA" and bullets=[] TASKS: ### TASK 1 product_name: Insulated smart mug material: 316 stainless steel features: temperature alert, 7-day battery audience: commuters ### TASK 2 product_name: Wireless earbuds material: ABS shock-resistant features: ANC, 24-hour battery audience: students 「INSUFFICIENT_DATA」という条項は、あなたの命を救うものです. 壊れた一つのタスクは、すべてのバッチを毒にするべきではありません。 6)Python Implementation: Batch → Call → Parse (With Guardrails) 以下は、あなたが適応できる近代的なパターンです(プロバイダーのSDKは異なりますので、それらを適用してください。 (コピーパステの保証はありません) structure import json import random import time from typing import Any, Dict, List, Tuple MAX_RETRIES = 4 def backoff_sleep(attempt: int, retry_after: float | None = None) -> None: if retry_after is not None: time.sleep(retry_after) return base = 2 ** attempt jitter = random.random() time.sleep(min(10, base + jitter)) def build_batch_prompt(tasks: List[Dict[str, str]]) -> str: header = ( "You output valid JSON only. No Markdown. No commentary.\n\n" "Return a JSON array. Each item must be:\n" "{\n \"task_id\": <int>,\n \"title\": <string>,\n \"bullets\": [<string>, <string>, <string>]\n}\n\n" "Rules:\n" "- UK English spelling\n" "- Title ≤ 12 words\n" "- 3 bullets, each ≤ 18 words\n" "- If input is missing: set title=\"INSUFFICIENT_DATA\" and bullets=[]\n\n" "TASKS:\n" ) blocks = [] for t in tasks: blocks.append( f"### TASK {t['task_id']}\n" f"product_name: {t.get('product_name','')}\n" f"material: {t.get('material','')}\n" f"features: {t.get('features','')}\n" f"audience: {t.get('audience','')}\n" ) return header + "\n".join(blocks) def parse_json_strict(text: str) -> List[Dict[str, Any]]: # Hard fail if it's not JSON. This is intentional. return json.loads(text) def call_llm(prompt: str) -> Tuple[str, float | None]: """Return (text, retry_after_seconds). Replace with your provider call.""" raise NotImplementedError def run_batch(tasks: List[Dict[str, str]]) -> List[Dict[str, Any]]: prompt = build_batch_prompt(tasks) for attempt in range(MAX_RETRIES): try: raw_text, retry_after = call_llm(prompt) return parse_json_strict(raw_text) except json.JSONDecodeError: # Ask the model to repair formatting in a second pass (or log + retry) prompt = ( "Fix the output into valid JSON only. Preserve meaning.\n\n" f"BAD_OUTPUT:\n{raw_text}" ) backoff_sleep(attempt) except Exception as e: # If your SDK exposes HTTP status + retry-after, use it here backoff_sleep(attempt) last_error = e raise RuntimeError(f"Batch failed after retries: {last_error}") 「クラシック」スニッピットと何が変わったのか? JSONは厳しい契約として扱います。 私たちはフォーマット修理を明示的に処理します(そして安く保ちます)。 私たちはバックコフ論理を中心化し、すべての呼び出しが同じように動作します。 7)バッチサイズを選ぶ方法(誰もが難しい方法を学ぶルール) バッチサイズは以下によって制限されます: Batch size is limited by: コンテキスト ウィンドウ (max tokens per request) TPMパスポート Response Parsing 安定性 「One Batch Failed」に対するあなたのビジネス容忍性 実践的なヒューリズム: 10~20個のアイテムでスタート トークン使用量 increase until you see: output format drift, or timeouts / latency spikes, or context overflow risk and always keep a . max batch token budget 8.「コスト数学」 ファンタジーナンバーなし 値段が変わり、モデルが変わる。 したがって、古い1Kトークンの値をハードコードする代わりに、プロバイダの現在の価格ページを使用してコストを計算します。 OpenAI は API 価格設定ページでトークンごとの価格設定を公開しています。Anthropic はまた、価格設定とドキュメント料金制限レベルを公開しています。 有用なコスト評価: cost ≈ (input_tokens * input_price + output_tokens * output_price) / 1,000,000 次に、あなたがコントロールする変数を最適化します: SHRINK INPUT TOKEN 出力トークン制限 電話回数を減らす(バッチ) 9)バッチングのリスク(そして焼かれない方法) リスク1:1つの悪いアイテムがバッチを台無しにする 「Insufficient_DATA」をタスクごとに返します。 Fix: リスク2: output format drift breaks parsing 厳格なJSON、修理ステップ、ログアップ。 Fix: リスク3:batch too big → context overflow トークン予算 + 自動分割 Fix: リスク4:割引を回避する「創造的な」試み より多くの容量が必要な場合は、より高い制限を要求し、プロバイダーの条件に従ってください。 Fix: 最終取 料金制限は敵ではありません 彼らはあなたの早期警告システムです: スピードが長すぎて、 渋滞が激しすぎて、 あるいは、あなたのアーキテクチャは「無限のパフォーマンス」を仮定します。 あなたが payloads (prose ではない) のようなプロンプトを扱うなら、ペッシングを追加し、大人のようにバッチを加えると、あなたは: 429 未満 低コスト ドラマなしでスケールするシステム それがゲーム全体です。