APIとSDKガイド
OpenAI Python SDKのタイムアウトとリトライ:CheapTokens用に設定する
OpenAI Python SDKでtimeout、max_retries、max_tokensを設定し、適切なエラーをキャッチし、スタックしたリクエストが10分間実行されないようにします。

このページの内容
スクリプトがモデルを呼び出したのに何も返ってこず、10分後もまだ待っている。これはOpenAI Python SDKのデフォルトで、タイムアウトは10分、リトライは2回です。変更するには、timeout=30.0とmax_retries=2をOpenAI(...)に渡し、呼び出しごとにclient.で上書きし、max_tokensで回答を制限します。
SDKのREADME(2026年10月27日確認)にこれらすべてが記載されています。以下では、OpenAI Chat Completions形式を話すCheapTokensエンドポイントhttps:/に適用します。その設定の詳細はYour first API request with CheapTokensとdocsにあります。
何も設定しない場合のSDKの動作#
重要なデフォルトが2つあります。タイムアウトは10分です。リトライは2回で、短い指数バックオフを伴い、接続エラーと408、409、429、5xxレスポンスに対して行われ、リクエストボディを安全に再送できる場合に限られます。タイムアウトしたリクエストもリトライされます。
つまり、各試行には独自のタイムアウトがあり、最悪のケースはおおよそタイムアウト×試行回数に、試行間のポーズを加えたものになります:
- デフォルト:600 × 3 = 1800秒、30分
timeout=30.0、max_retries=2:30 × 3 = 90秒
Webエンドポイントが30秒以内に応答しなければならないとします。デフォルトでは、コードがエラーを認識するまでに30分間ハングする可能性があります。読み進める前に別の設定で試してみてください。
数字を当てる
クライアントがtimeout=45.0とmax_retries=3を持っています。例外が発生するまでの最悪の待ち時間は秒単位でいくらですか(試行間のポーズは数えません)?
あなたの予想
0400
答えを表示
答え: 180
45 × (3リトライ + 1初回試行) = 180秒。試行間のポーズが少し追加されます。
クライアントでtimeoutとmax_retriesを設定する#
最も簡単な修正は、クライアントを作成するときに両方を一度設定することです:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.cheaptokens.dev/v1",
api_key=os.environ["CHEAPTOKENS_API_KEY"],
timeout=30.0, # seconds per attempt
max_retries=2, # 0 turns retries off
)
resp = client.chat.completions.create(
model="deepseek-ai/DeepSeek-V4-Flash-0731",
messages=[{"role": "user", "content": "Summarize this ticket in two sentences: ..."}],
max_tokens=800,
)
print(resp.choices[0].message.content)
print(resp.usage.prompt_tokens, resp.usage.completion_tokens)max_retriesは非負の整数でなければなりません。timeoutはfloat、または接続と読み取りに別々の制限が必要な場合はhttpx Timeoutオブジェクトを受け取ります。現在のmainブランチのREADMEではそのためにhttpx2をインポートしていますが、古いバージョンではhttpxを使用していたので、pip show openaiを実行してインストールがどちらを使用しているか確認してください。単純なfloatはインポート不要でどちらでも動作します。

CheapTokens docsの完全なモデルIDを使用してください。ここではdeepseek-です。IDはプロバイダー間で異なります。このモデルは回答あたり最大32,768出力トークンを受け付け、380Kのコンテキストを持つため、上記のmax_tokens行が意図的にあります。詳細は以下と、モデルについてはcheap DeepSeekにあります。
1つのリクエストに対して上書きする#
1つのクライアント、異なるジョブ。チャットの返信はすぐに諦めるべきで、夜間の要約は待つことができます。2つ目のクライアントを作成する代わりに、呼び出し用に派生させます:
quick = client.with_options(timeout=5.0, max_retries=0)
resp = quick.chat.completions.create(
model="deepseek-ai/DeepSeek-V4-Flash-0731",
messages=[{"role": "user", "content": "Reply with one word: ok"}],
max_tokens=5,
)with_optionsは新しい値を持つコピーを返し、clientはそのままにします。max_retries=0を設定するのは、自分のコードがすでにリトライしている場合、たとえばタスクを再エンキューするジョブキューに適切です。そうでなければ、2つの層が掛け算になります:3つのSDK試行が3つのキュー試行内にあると、1つのタスクに9つのリクエストになります。
重要なエラーをキャッチする#
リトライが尽きた後、SDKは例外を発生させます。すべてのエラークラスはopenai.APIErrorから継承し、失敗したリクエストはrequest_idを持ち、これをログに記録します:
import openai
def ask(prompt: str) -> str | None:
try:
r = client.chat.completions.create(
model="deepseek-ai/DeepSeek-V4-Flash-0731",
messages=[{"role": "user", "content": prompt}],
max_tokens=800,
)
return r.choices[0].message.content
except openai.APITimeoutError:
print("timed out after retries")
except openai.RateLimitError as e:
print("429, slow down:", e.request_id)
except openai.APIConnectionError:
print("cannot reach the API")
except openai.APIStatusError as e:
print("HTTP", e.status_code, e.request_id)
return None順序は狭いものから広いものへ。APIStatusErrorは任意の4xxまたは5xxレスポンスをカバーするので、最初に来るとRateLimitErrorを飲み込んでしまいます。タイムアウトも同様で、一般的な接続エラーの上に位置します。バッチスクリプトでは、return Noneが要点です:プロンプトをログに記録し、次に進み、最後に失敗を再実行します。
タイムアウトが発生し、リトライが使い果たされると、例外は次のようになります:

429の場合の詳細、試行間の待機を含めて、429 Too Many Requests from an AI APIを参照してください。
max_tokensを制限して長い回答が暴走しないようにする#
タイムアウトは待機を停止します。モデルに書く量を減らさせるわけではありません。max_tokensがなければ、32,768トークンの回答制限を持つモデルは非常に長い返信を書くことができ、長い返信は遅いものです。ジョブに合った制限を設定してください:チケット要約には800、はい/いいえには5。
コストは回答が途中で切れる可能性があることです。resp.を確認してください:lengthはモデルが終了する前に上限に達したことを意味します。Why does an AI answer stop mid-sentence?でカバーされています。代わりに回答をストリーミングすると、最初の単語が早く到着し、待ち時間が短く感じられます。Streaming responses in Pythonを参照してください。
リトライが請求に与える影響#
リトライは新しいリクエストです。試行が処理された場合、それは独自のトークンを持つ別のリクエストです。チケット要約が入力1,500トークン、出力400トークンだとします:1つのリクエストは今日の価格で$0.000063かかり、完全な価格表には他のモデルがあります。価格はモデルごとに固定で、ピーク時間はないので、午前3時のリトライは正午のものと同じコストです。
スライダーを自分のバッチに合わせて動かしてください:
コスト計算機
1,000件のチケット要約のバッチ
リクエストあたりの入力トークン数: 1,500 · リクエストあたりの出力トークン数: 400 · 1日あたりのリクエスト数: 1,000
| モデル | 1日あたり | 1か月あたり |
|---|---|---|
| GLM-5.3-Flash$0.02$0.04 | $0.046 | $1.38 |
| DeepSeek-V4-Flash$0.015$0.10 | $0.0625 | $1.88 |
| MiniMax-M2.7$0.05$0.15 | $0.135 | $4.05 |
表は1回のパスを示しています。バッチの10分の1が2回目の試行を必要とする場合、10分の1を追加します。リトライは失敗が稀な場合には安価な保険であり、失敗し続けるエンドポイントに対してmax_retries=10を設定する場合には高価な習慣です。
出荷前に#
チェックリスト
タイムアウトとリトライ、本番環境対応



