API i SDKPrzewodnik
Limit czasu i ponowienia w OpenAI Python SDK: ustaw je dla CheapTokens
Ustaw timeout, max_retries i max_tokens w OpenAI Python SDK, przechwytuj właściwe błędy i nie pozwól, by zawieszone żądanie działało przez 10 minut.

Na tej stronie
Twój skrypt wywołał model, nic nie wróciło, a dziesięć minut później wciąż czeka. Taki jest domyślny stan OpenAI Python SDK: 10-minutowy limit czasu i 2 ponowienia. Aby to zmienić, przekaż timeout=30.0 i max_retries=2 do OpenAI(...), nadpisz je dla pojedynczego wywołania przez client. i ogranicz odpowiedź przez max_tokens.
README SDK (sprawdzone 27 października 2026) dokumentuje to wszystko. Poniżej zastosowano to do endpointu CheapTokens, https:/, który mówi w formacie OpenAI Chat Completions. Szczegóły tej konfiguracji są w Twoje pierwsze żądanie API z CheapTokens oraz w dokumentacji.
Co robi SDK, gdy nic nie ustawisz#
Znaczenie mają dwa ustawienia domyślne. Limit czasu to 10 minut. Ponowienia to 2, z krótkim wykładniczym backoffem, dla błędów połączenia oraz odpowiedzi 408, 409, 429 i 5xx, i tylko wtedy, gdy treść żądania można bezpiecznie wysłać ponownie. Żądanie, które przekroczy limit czasu, również jest ponawiane.
Zatem każda próba ma własny limit czasu, a najgorszy przypadek to w przybliżeniu limit czasu pomnożony przez liczbę prób plus przerwy między nimi:
- domyślnie: 600 × 3 = 1800 sekund, pół godziny
timeout=30.0,max_retries=2: 30 × 3 = 90 sekund
Załóżmy, że endpoint webowy musi odpowiedzieć w ciągu 30 sekund. Przy ustawieniach domyślnych może wisieć przez pół godziny, zanim twój kod zobaczy błąd. Wypróbuj to na innym ustawieniu, zanim przeczytasz dalej.
Zgadnij liczbę
Klient ma timeout=45.0 i max_retries=3. Jaki jest najgorszy czas oczekiwania w sekundach przed wyjątkiem, nie licząc przerw między próbami?
Twoje przypuszczenie
0400
Pokaż odpowiedź
Odpowiedź: 180
45 × (3 ponowienia + 1 pierwsza próba) = 180 sekund; przerwy między próbami dodają jeszcze trochę.
Ustaw timeout i max_retries na kliencie#
Najprostsza poprawka to ustawienie obu raz, przy tworzeniu klienta:
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 musi być nieujemną liczbą całkowitą. timeout przyjmuje float albo obiekt httpx Timeout, jeśli chcesz osobne limity dla łączenia i odczytu. README bieżącej gałęzi main importuje w tym celu httpx2, starsze wersje używały httpx, więc uruchom pip show openai i sprawdź, której używa twoja instalacja. Zwykły float nie wymaga importu i działa w obu przypadkach.

Użyj pełnego identyfikatora modelu z dokumentacji CheapTokens, tutaj deepseek-: identyfikatory różnią się między dostawcami. Ten model przyjmuje do 32 768 tokenów wyjściowych na odpowiedź i ma kontekst 380K, dlatego powyższa linia max_tokens jest tam celowo. Więcej o tym poniżej, a o modelu w tani DeepSeek.
Nadpisz to dla jednego żądania#
Jeden klient, różne zadania. Odpowiedź czatu powinna szybko się poddać, nocne podsumowanie może poczekać. Zamiast tworzyć drugiego klienta, wyprowadź go dla wywołania:
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 zwraca kopię z nowymi wartościami i pozostawia client bez zmian. Ustawienie max_retries=0 jest właściwym wyborem, gdy twój własny kod już ponawia, na przykład kolejka zadań, która ponownie dodaje zadanie do kolejki. W przeciwnym razie obie warstwy się mnożą: 3 próby SDK wewnątrz 3 prób kolejki to 9 żądań dla jednego zadania.
Łap błędy, które mają znaczenie#
Gdy ponowienia się wyczerpią, SDK zgłasza wyjątek. Każda klasa błędu dziedziczy po openai.APIError, a nieudane żądania niosą request_id, co właśnie logujesz:
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 NoneKolejność jest od wąskich do szerokich. APIStatusError obejmuje każdą odpowiedź 4xx lub 5xx, więc gdyby był pierwszy, połknąłby RateLimitError. To samo dotyczy limitu czasu: znajduje się powyżej ogólnego błędu połączenia. W skrypcie wsadowym return None jest sednem sprawy: zaloguj prompt, przejdź do następnego i uruchom ponownie nieudane na końcu.
Gdy limit czasu zadziała, a ponowienia się wyczerpią, wyjątek wygląda tak:

Szczegóły przypadku 429, w tym oczekiwanie między próbami, znajdziesz w 429 Too Many Requests z API AI.
Ogranicz max_tokens, aby długa odpowiedź nie wymknęła się spod kontroli#
Limit czasu przestaje czekać. Nie sprawia, że model pisze mniej. Bez max_tokens model z limitem odpowiedzi 32 768 tokenów może swobodnie napisać bardzo długą odpowiedź, a długa odpowiedź jest wolna. Ustaw limit pasujący do zadania: 800 dla podsumowania zgłoszenia, 5 dla tak/nie.
Koszt jest taki, że odpowiedź może zostać ucięta. Sprawdź resp.: length oznacza, że limit zadziałał, zanim model skończył. Omawia to Dlaczego odpowiedź AI urywa się w połowie zdania?. Jeśli zamiast tego strumieniujesz odpowiedź, pierwsze słowa pojawiają się wcześnie i oczekiwanie wydaje się krótsze, zobacz Strumieniowanie odpowiedzi w Pythonie.
Co ponowienia robią z rachunkiem#
Ponowienie to nowe żądanie. Jeśli próba została przetworzona, to osobne żądanie z własnymi tokenami. Załóżmy, że podsumowanie zgłoszenia to 1500 tokenów na wejściu i 400 na wyjściu: jedno żądanie kosztuje $0.000063 przy dzisiejszych cenach, a pełna tabela cen zawiera pozostałe modele. Ceny są stałe dla modelu, bez godzin szczytu, więc ponowienie o 3 w nocy kosztuje tyle samo co o południu.
Przesuń suwaki na własną partię:
Kalkulator kosztów
Partia 1000 podsumowań zgłoszeń
Tokeny wejściowe na żądanie: 1500 · Tokeny wyjściowe na żądanie: 400 · Żądania dziennie: 1000
| Model | Dziennie | Miesięcznie |
|---|---|---|
| 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 |
Tabela pokazuje jedno przejście. Jeśli dziesiąta część partii wymaga drugiej próby, dodaj jedną dziesiątą. Ponowienia to tanie ubezpieczenie, gdy awarie są rzadkie, i kosztowny nawyk, gdy ustawisz max_retries=10 przeciwko endpointowi, który ciągle zawodzi.
Zanim wdrożysz#
Lista kontrolna
Limity czasu i ponowienia gotowe do produkcji



