API & SDKGuide
Timeout et tentatives du SDK Python OpenAI : les définir pour CheapTokens
Définissez timeout, max_retries et max_tokens dans le SDK Python OpenAI, interceptez les bonnes erreurs, et évitez qu'une requête bloquée tourne pendant 10 minutes.

Sur cette page
Votre script a appelé le modèle, rien n'est revenu, et dix minutes plus tard il attend toujours. C'est le comportement par défaut du SDK Python d'OpenAI : un timeout de 10 minutes et 2 tentatives. Pour le changer, passez timeout=30.0 et max_retries=2 à OpenAI(...), remplacez-les par appel avec client., et limitez la réponse avec max_tokens.
Le README du SDK (vérifié le 27 octobre 2026) documente tout cela. Ci-dessous, il est appliqué au point de terminaison CheapTokens, https:/, qui parle le format OpenAI Chat Completions. Les détails de cette configuration se trouvent dans Votre première requête API avec CheapTokens et la documentation.
Ce que fait le SDK quand vous ne définissez rien#
Deux valeurs par défaut comptent. Le timeout est de 10 minutes. Les tentatives sont de 2, avec un court backoff exponentiel, pour les erreurs de connexion et pour les réponses 408, 409, 429 et 5xx, et uniquement lorsque le corps de la requête peut être renvoyé en toute sécurité. Une requête qui expire est également réessayée.
Ainsi, chaque tentative a son propre timeout, et le pire des cas est approximativement le timeout multiplié par le nombre de tentatives, plus les pauses entre elles :
- par défaut : 600 × 3 = 1800 secondes, une demi-heure
timeout=30.0,max_retries=2: 30 × 3 = 90 secondes
Supposons qu'un point de terminaison web doive répondre en 30 secondes. Avec les valeurs par défaut, il peut rester bloqué une demi-heure avant que votre code ne voie une erreur. Essayez avec un autre réglage avant de continuer la lecture.
Devinez le nombre
Un client a timeout=45.0 et max_retries=3. Quel est le temps d'attente maximal en secondes avant l'exception, sans compter les pauses entre les tentatives ?
Votre estimation
0400
Afficher la réponse
Réponse: 180
45 × (3 tentatives + 1 première tentative) = 180 secondes ; les pauses entre les tentatives ajoutent un peu plus.
Définir timeout et max_retries sur le client#
La solution la plus simple est de définir les deux une fois, lors de la création du client :
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 doit être un entier non négatif. timeout prend un float, ou un objet httpx Timeout si vous voulez des limites séparées pour la connexion et la lecture. Le README de la branche main actuelle importe httpx2 pour cela, les versions plus anciennes utilisaient httpx, donc exécutez pip show openai et vérifiez laquelle votre installation utilise. Un simple float ne nécessite aucun import et fonctionne dans les deux cas.

Utilisez l'identifiant complet du modèle depuis la documentation CheapTokens, deepseek- ici : les identifiants diffèrent selon les fournisseurs. Ce modèle prend jusqu'à 32 768 jetons de sortie par réponse et a un contexte de 380K, c'est pourquoi la ligne max_tokens ci-dessus est là exprès. Plus de détails ci-dessous, et sur le modèle dans cheap DeepSeek.
Remplacer pour une seule requête#
Un client, différents travaux. Une réponse de chat doit abandonner rapidement, un résumé nocturne peut attendre. Au lieu de créer un second client, dérivez-en un pour l'appel :
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 renvoie une copie avec les nouvelles valeurs et laisse client intact. Définir max_retries=0 est le bon choix lorsque votre propre code réessaie déjà, par exemple une file d'attente de tâches qui remet la tâche en file. Sinon, les deux couches se multiplient : 3 tentatives SDK dans 3 tentatives de file d'attente, c'est 9 requêtes pour une tâche.
Intercepter les erreurs qui comptent#
Une fois les tentatives épuisées, le SDK lève une exception. Chaque classe d'erreur hérite de openai.APIError, et les requêtes échouées portent request_id, ce que vous journalisez :
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 NoneL'ordre va du plus étroit au plus large. APIStatusError couvre toute réponse 4xx ou 5xx, donc s'il venait en premier, il avalerait RateLimitError. Même idée pour le timeout : il se situe au-dessus de l'erreur de connexion générale. Dans un script par lots, return None est tout l'intérêt : journalisez le prompt, passez au suivant, et relancez les échecs à la fin.
Lorsque le timeout se déclenche et que les tentatives sont épuisées, voici à quoi ressemble l'exception :

Pour le cas 429 en détail, y compris l'attente entre les tentatives, voir 429 Too Many Requests d'une API IA.
Plafonner max_tokens pour qu'une longue réponse ne s'emballe pas#
Un timeout arrête l'attente. Il ne fait pas écrire moins au modèle. Sans max_tokens, un modèle avec une limite de réponse de 32 768 jetons est libre d'écrire une réponse très longue, et une longue réponse est lente. Définissez une limite adaptée à la tâche : 800 pour un résumé de ticket, 5 pour un oui/non.
Le coût est qu'une réponse peut être coupée. Vérifiez resp. : length signifie que le plafond a été atteint avant que le modèle ait fini. Pourquoi une réponse IA s'arrête-t-elle en milieu de phrase ? couvre cela. Si vous diffusez la réponse à la place, les premiers mots arrivent tôt et l'attente semble plus courte, voir Réponses en streaming en Python.
Ce que les tentatives font à la facture#
Une tentative est une nouvelle requête. Si une tentative a été traitée, c'est une requête distincte avec ses propres jetons. Supposons qu'un résumé de ticket fasse 1 500 jetons en entrée et 400 en sortie : une requête coûte $0.000063 aux prix actuels, et le tableau des tarifs complet contient les autres modèles. Les prix sont fixes par modèle, sans heures de pointe, donc une tentative à 3 h du matin coûte le même prix qu'à midi.
Déplacez les curseurs sur votre propre lot :
Calculateur de coût
Un lot de 1 000 résumés de tickets
Tokens d'entrée par requête: 1 500 · Tokens de sortie par requête: 400 · Requêtes par jour: 1 000
| Modèle | Par jour | Par mois |
|---|---|---|
| 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 |
Le tableau montre une passe. Si un dixième du lot nécessite une seconde tentative, ajoutez un dixième. Les tentatives sont une assurance bon marché lorsque les échecs sont rares, et une habitude coûteuse lorsque vous définissez max_retries=10 contre un point de terminaison qui échoue sans cesse.
Avant de livrer#
Liste de contrôle
Timeouts et tentatives, prêts pour la production



