429, 5xx et délais d'attente : pratiques d'ingénierie pour la tolérance aux pannes des passerelles LLM
La limitation de débit et les défaillances en amont sont la norme, pas l'exception, dans les applications LLM. Cet article détaille le traitement correct de chaque cas 429/5xx/timeout/401, dans quels cas on peut basculer automatiquement de canal, dans quels cas il ne faut jamais réessayer, et comment éviter la double facturation.
D'abord classifier, ensuite décider du traitement
« Réessayer trois fois pour toutes les erreurs » est l'approche erronée la plus courante. La sémantique des différents codes d'erreur est totalement différente, et la stratégie de traitement doit l'être aussi. Le tableau ci-dessous présente la stratégie réellement appliquée par notre passerelle, et peut servir de référence pour votre propre implémentation.
- Échec de connexion / DNS / TLS : basculer immédiatement vers le canal de secours.
- Timeout (sortie pas encore commencée) : basculer vers le canal de secours, au maximum 1 à 2 fois.
- HTTP 429 : après un court refroidissement, basculer de canal et réduire simultanément le poids de ce canal.
- HTTP 5xx : comptabiliser dans la fenêtre d'échecs ; des échecs consécutifs déclenchent le disjoncteur.
- 401 / 403 : problème d'identifiants ou de permissions, désactiver ces identifiants et alerter, ne pas réessayer.
- Solde insuffisant : suspendre ce canal et alerter.
- Erreur de paramètre 400 : après normalisation, renvoyer directement au client, sans nouvelle tentative ni facturation.
- SSE interrompu après émission partielle de contenu : renvoyer
upstream_stream_error, ne pas réessayer par défaut.
Pourquoi une interruption SSE ne peut pas être simplement réessayée
Dès qu'une réponse en streaming commence à émettre des tokens vers le client, cela signifie que l'amont a déjà produit (et facturera) une sortie. Si la passerelle changeait discrètement de canal pour recommencer, l'utilisateur verrait du contenu dupliqué, et vous auriez payé pour deux sorties.
La bonne approche est de considérer ce flux tronqué comme un succès partiel : renvoyer un code d'erreur indiquant au client que « l'amont a été interrompu », et laisser le côté métier décider s'il affiche le contenu existant avec une invite de nouvelle tentative, ou s'il recommence entièrement.
Le disjoncteur : la couche plus importante que la nouvelle tentative
La nouvelle tentative traite une requête individuelle ; le disjoncteur juge l'état global sur une période. Lorsqu'un canal atteint le seuil d'échecs consécutifs, on le marque « ouvert », on cesse de lui envoyer du trafic pendant un certain temps, puis on envoie un faible volume de trafic de sondage (semi-ouvert), et après plusieurs sondages réussis on rétablit complètement (fermé).
Sans disjoncteur, les nouvelles tentatives écrasent encore plus un canal déjà en panne et font grimper brutalement la latence moyenne des clients.
Idempotence et facturation des nouvelles tentatives
- Requêtes non streaming : après nouvelle tentative, facturer uniquement l'usage de la tentative finalement réussie.
- Requêtes streaming : la tentative qui a déjà émis des tokens a réellement généré un coût amont, il faut l'enregistrer, sans effacer la facture au motif d'une nouvelle tentative.
- Attribuer un
request_idà chaque requête utilisateur, partagé par toutes les nouvelles tentatives, afin de pouvoir rejouer intégralement « pourquoi ce canal a été choisi ». - Les remboursements/ajustements doivent passer par des écritures de registre, sans modifier directement le solde.
Ce qu'Admesh fait déjà
La stratégie ci-dessus est le comportement par défaut de la passerelle Admesh : bascule automatique entre plusieurs canaux amont d'un même public_model, chaque décision de routage est persistée en base, et le client peut voir dans l'historique d'usage le request_id, le modèle réellement utilisé et l'état de santé du canal ; les codes d'erreur sont renvoyés dans un format unifié (error.type / error.code / request_id).
À noter : le routage n'a lieu qu'au sein du pool de canaux d'un même public_model ; demander anthropic/xxx ne vous bascule pas vers le modèle d'un autre fournisseur — remplacer un modèle change directement la qualité de sortie, et c'est une décision que nous ne pouvons pas prendre à votre place.
Tarifs Admesh en direct (extrait)
Les prix proviennent de la configuration Admesh en direct, en USD par million de tokens. Consultez le catalogue des modèles pour la liste complète.
| Nom et identifiant du modèle | Fenêtre de contexte | Saisir le prix / 1 M | Prix de vente / 1 M | Taux de réussite du cache / 1 Mo |
|---|---|---|---|---|
Claude Fable 5 anthropic/claude-fable-5 | 1M | $3.25 / 1M | $16.25 / 1M | $0.325 / 1M |
Claude Fable 5.1 anthropic/claude-fable-5-1 | 1M | $3.25 / 1M | $16.25 / 1M | $0.08125 / 1M |
Claude Haiku 4.5 anthropic/claude-haiku-4-5-20251001 | 200K | $0.325 / 1M | $1.625 / 1M | $0.0325 / 1M |
Claude Haiku 5.5 anthropic/claude-haiku-5-5 | 1M | $0.0325 / 1M | $0.1625 / 1M | $0.00325 / 1M |
Claude Opus 4.5 anthropic/claude-opus-4-5-20251101 | 200K | $1.625 / 1M | $8.125 / 1M | $0.1625 / 1M |
Claude Opus 4.6 anthropic/claude-opus-4-6 | 1M | $1.625 / 1M | $8.125 / 1M | $0.1625 / 1M |
Claude Opus 4.7 anthropic/claude-opus-4-7 | 1M | $1.625 / 1M | $8.125 / 1M | $0.1625 / 1M |
Claude Opus 4.8 anthropic/claude-opus-4-8 | 1M | $1.625 / 1M | $8.125 / 1M | $0.1625 / 1M |
Les tarifs ci-dessus correspondent aux prix unitaires standard des canaux publics ; la facturation s'effectue en fonction de la consommation réelle de jetons. Consultez le catalogue complet des modèles
FAQ
En cas de 429, faut-il faire un sleep ou changer de modèle ?
Quelle durée de délai d'attente choisir ?
Les nouvelles tentatives entraînent-elles une double facturation ?
Références
Appelez ces modèles via une seule passerelle
Admesh fournit une API unifiée compatible OpenAI : une Base URL et une clé pour Claude, GPT, DeepSeek et plus encore. Les nouveaux comptes reçoivent un crédit d'essai sans expiration.
