Ton script parle à une API d'IA. OpenAI, Anthropic, Mistral, peu importe. Un matin, tout roule ; le lendemain, paf : une erreur 429 (trop de requêtes), un 500 (le serveur a rendu l'âme) ou un timeout réseau. Ton programme s'arrête net, et toi tu relances à la main en priant pour que ça passe. On a tous vécu ça. La bonne nouvelle, c'est qu'il existe une solution propre : Tenacity.
Tenacity est une bibliothèque Python qui réessaie une fonction qui échoue, avec des règles fines : combien de fois, combien de temps attendre entre deux essais, et quelles erreurs méritent un second passage. En quelques lignes, ton script passe de fragile à incassable. On va le prouver avec du vrai code, sans clé API ni serveur à configurer.
Étape 1 — Installe Tenacity
Rien de plus simple. Un environnement propre, puis :
pip install tenacityC'est tout. La bibliothèque n'a quasiment aucune dépendance et se charge en une seconde.
Étape 2 — Le problème : un appel qui plante
Imagine un appel à un modèle de langage. Dans la vraie vie, il échoue de temps en temps : l'API est saturée, le serveur tousse, la connexion saute. On va simuler ça avec une fonction qui rate ses trois premiers appels, puis finit par répondre :
class RateLimitError(Exception):
pass
class ServerError(Exception):
pass
COMPTEUR = {"n": 0}
def appeler_le_modele(prompt):
COMPTEUR["n"] += 1
n = COMPTEUR["n"]
if n == 1 or n == 2:
raise RateLimitError("429 Too Many Requests")
if n == 3:
raise ServerError("500 Internal Server Error")
return {"reponse": f"Le modele repond a : {prompt}"}Étape 3 — La solution : le décorateur @retry
On enveloppe notre appel dans un décorateur. Trois règles à fournir :
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
@retry(
retry=retry_if_exception_type((RateLimitError, ServerError)),
wait=wait_exponential(multiplier=1, min=1, max=10),
stop=stop_after_attempt(6),
)
def reponse_fiable(prompt):
return appeler_le_modele(prompt)
print(reponse_fiable("Explique la recursion a un enfant de 6 ans"))Décortiquons. retry_if_exception_type dit à Tenacity de ne réessayer que si l'une de ces deux erreurs est levée : un vrai bug de ton code ne sera pas masqué par des relances inutiles. wait_exponential patiente de plus en plus longtemps : 1 seconde, puis 2, 4, 8, plafonné à 10. C'est le backoff exponentiel, celui que recommandent tous les fournisseurs d'API. Enfin, stop_after_attempt fixe une limite : six essais, puis on abandonne proprement.
À l'exécution, la fonction rate ses trois premiers appels, attend 1, 2 puis 4 secondes, et réussit au quatrième. Ton script ne s'est jamais arrêté.
Étape 4 — Le jitter : ne sois pas un mouton
Petit raffinement qui change tout en production. Si mille scripts se reconnectent tous à la même seconde après un incident, l'API retombe aussitôt. Le jitter ajoute un délai aléatoire pour étaler les tentatives :
from tenacity import wait_exponential_jitter
# au lieu de wait_exponential(...)
wait=wait_exponential_jitter(initial=1, max=10)Tu remplaces wait_exponential par wait_exponential_jitter. Tes essais partent à 1, 2, 4 secondes, plus une dose d'aléatoire. Indispensable dès que ton script tourne en plusieurs exemplaires.
Étape 5 — Un vrai client HTTP
Dans la vraie vie, rien ne change : le même décorateur s'applique à un appel HTTP. Voici un client qui poste sur une API et relance tant qu'elle répond 429 ou 500 :
import requests
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
@retry(
retry=retry_if_exception_type(requests.HTTPError),
wait=wait_exponential(multiplier=1, min=1, max=5),
stop=stop_after_attempt(5),
)
def demander(prompt):
r = requests.post("https://ton-api-ia.example.com/v1/chat", json={"prompt": prompt}, timeout=10)
r.raise_for_status()
return r.json()raise_for_status() transforme n'importe quelle réponse 4xx ou 5xx en exception, que Tenacity rattrape et relance. Pour les timeouts, ajoute requests.Timeout à la liste des exceptions à retenter.
Conclusion
En une vingtaine de lignes, tu viens de rendre ton script résistant à la réalité. Les API d'IA sont lentes, saturées et capricieuses : Tenacity ne rend pas ton code plus intelligent, il le rend patient. Et c'est exactement ce qu'il faut quand on discute avec un modèle. La prochaine fois qu'un 429 t'interrompt en pleine nuit, ce n'est plus toi qui relances : c'est ton code.
Si tu veux creuser, regarde du côté de retry_if_result (relancer selon la valeur retournée) et stop_after_delay (relancer pendant un temps donné). Bon code, et que tes appels retombent toujours sur leurs pattes.






