Routage de repli pour API LLM : guide de bascule en production
Le routage de repli pour les API LLM semble simple jusqu’au premier incident réel : intercepter une erreur, changer de modèle et réessayer. En production, cette règle peut transformer un problème chez un fournisseur en appels d’outils en double, en JSON cassé, en sortie de streaming mêlée, en trafic de retry incontrôlable, ou en réponse techniquement réussie mais qui ne satisfait plus le contrat produit.
Une conception plus sûre considère le repli comme une machine à états bornée, et non comme une liste de noms de modèles de secours. Chaque requête passe par un petit ensemble de décisions :
- L’échec est-il réessayable ?
- Est-il sûr de répéter cette requête ?
- La tentative suivante doit-elle utiliser la même cible ou une cible différente ?
- Le repli peut-il préserver le contrat requis ?
- La requête a-t-elle déjà produit une sortie ou des effets de bord ?
- La latence de bout en bout et le budget de tentatives ont-ils été épuisés ?
Ce guide transforme ces questions en matrice d’erreurs, politique de routage, contrôleur TypeScript, plan de test et checklist de déploiement pour les applications LLM multi-fournisseurs.
Les quatre actions derrière un routage de repli fiable pour API LLM
Ne mettez pas toutes les erreurs dans la même boucle de retry. Un routeur de production a besoin de quatre actions distinctes.
| Action | À utiliser quand | Exemples typiques |
|---|---|---|
| Réessayer la même cible | L’échec semble transitoire et le déploiement actuel peut se rétablir avant l’échéance de la requête | Connexion réinitialisée avant les en-têtes, timeout isolé, bref délai lié à la limite de débit |
| Bascule vers une cible équivalente | Le fournisseur, la région, le déploiement ou le compte est en mauvais état, mais le même contrat de modèle est disponible ailleurs | Panne régionale, quota de déploiement épuisé, réponses 5xx répétées |
| Basculer vers un autre modèle | Un modèle alternatif évalué peut préserver la capacité minimale et le contrat de sortie de l’application | Modèle principal indisponible et un modèle secondaire testé prend en charge les mêmes outils et le même schéma |
| Arrêter et exposer l’erreur | Répéter la requête ne la corrigera pas, peut créer des effets de bord, ou ne peut pas préserver le contrat | Authentification invalide, requête mal formée, paramètre non pris en charge, blocage de politique, flux partiel |
La distinction entre bascule et repli compte. La bascule conserve le contrat logique du modèle et change l’infrastructure. Le repli change le modèle ou le niveau de capacité. La bascule est généralement l’option la moins risquée.
Si vous avez besoin d’une vue plus large de la conception du chemin de requête autour des alias, du scoring de santé, de la facturation et de l’observabilité, commencez par le guide d’architecture de passerelle API IA. Cet article se concentre sur le contrôleur qui s’exécute une fois qu’une cible a été sélectionnée.
Construire une matrice erreur-vers-action avant d’écrire le code de retry
Les SDK de fournisseurs exposent différentes classes d’exceptions et différents corps de réponse, mais le routeur doit les normaliser dans une petite taxonomie interne.
| Échec normalisé | Réessayer la même cible ? | Équivalent de bascule ? | Repli vers un autre modèle ? | Notes |
|---|---|---|---|---|
| Échec de connexion avant l’acceptation de la requête | Oui, une fois | Oui | Peut-être | Rester dans un seul délai de bout en bout |
| Dépassement du délai avant les en-têtes de réponse | Peut-être | Oui | Peut-être | Ne répéter que les requêtes sûres à rejouer |
Limite de débit 429 |
Après un délai borné | Oui | Peut-être | Respecter les indications du serveur lorsqu’elles sont disponibles ; ne pas créer de tempête de réessais |
Erreur 5xx du fournisseur ou surcharge |
Une fois au maximum | Oui | Peut-être | Ouvrir le circuit après un seuil d’échec défini |
| Erreur d’authentification ou d’autorisation | Non | Non | Non | Corriger les identifiants ou la politique ; changer de modèle n’aide pas |
| Requête mal formée ou paramètre non pris en charge | Non | Non | Non | Corriger le contrat du client |
| Longueur de contexte dépassée | Pas de réessai aveugle | Non | Seulement avec une adaptation explicite | La troncature, la synthèse ou une route à plus grand contexte modifie la requête |
| Rejet pour sécurité ou politique | Pas de réessai aveugle | Non | Généralement non | Changer de fournisseur pour contourner une décision de politique n’est pas une stratégie de fiabilité |
| Échec de validation du schéma de sortie | Peut-être avec correction | Non | Seulement si évalué | Conserver la réparation du schéma séparée des réessais de transport |
| Le flux échoue avant le premier token | Peut-être | Oui | Peut-être | Aucune sortie visible pour l’utilisateur n’existe encore |
| Le flux échoue après le début de la sortie | Pas de bascule automatique | Non | Pas de bascule automatique | Ne pas fusionner deux réponses de modèle |
| L’appel d’outil a peut-être déjà été exécuté | Pas de réessai aveugle | Non | Pas de réessai aveugle | Exiger des clés d’idempotence ou une déduplication au niveau de l’outil |
La documentation officielle des fournisseurs renforce la nécessité de normaliser. Anthropic documente des erreurs distinctes de limite de débit, d’API et de surcharge, et précise qu’une requête en streaming peut toujours échouer après une première réponse réussie. OpenAI distingue également les requêtes invalides, les limites de débit et les défaillances côté serveur. Votre application doit traduire les signaux propres au fournisseur en décisions internes stables, plutôt que d’intégrer les noms des fournisseurs dans toute la logique métier.
Placez un seul budget de réessai autour de toute la requête
Les nouvelles tentatives de reprise existent souvent à plusieurs niveaux à la fois : le client HTTP, le SDK du fournisseur, la passerelle, le job d’arrière-plan et le service applicatif. Si chaque couche effectue trois tentatives, une seule action utilisateur peut se multiplier en bien plus d’appels en amont que l’équipe ne l’avait prévu.
Le schéma le plus sûr est le suivant :
- Choisir une seule couche pour gérer les reprises LLM et le repli.
- Définir une seule échéance de bout en bout pour la requête utilisateur ou le job.
- Définir un nombre maximal de tentatives en amont.
- Réserver une partie du délai au cible de repli.
- Utiliser un backoff exponentiel avec jitter pour les échecs transitoires.
- S’arrêter lorsque le temps restant ne permet plus une autre tentative utile.
Les recommandations d’AWS sur les timeouts, les reprises, le backoff et le jitter décrivent comment les tentatives peuvent amplifier la surcharge et recommandent un comportement borné plutôt qu’une répétition immédiate constante. Le même principe s’applique aux API de modèles, où un fournisseur sous charge est le moins en mesure d’absorber un trafic de tentatives synchronisées.
Un budget interactif pratique peut être exprimé sous forme de politique plutôt que de délais codés en dur :
type RetryBudget = {
deadlineMs: number;
maxAttempts: number;
maxSameTargetAttempts: number;
reserveForFallbackMs: number;
};
Les valeurs exactes dépendent du produit. Une interface de chat, un agent de code, un évaluateur par lots et un workflow vidéo asynchrone ne devraient pas partager le même budget.
Utiliser des disjoncteurs pour empêcher l’orientation vers des défaillances connues
Un disjoncteur empêche chaque nouvelle requête de redécouvrir la même panne.
Les états standard sont :
- Fermé : les requêtes circulent normalement pendant que le routeur mesure les échecs et la latence.
- Ouvert : la cible est temporairement inéligible parce que son comportement récent a dépassé un seuil.
- Mi-ouvert : un petit nombre de requêtes de test vérifient si la cible s’est rétablie.
Le modèle de disjoncteur d’Azure décrit ce cycle fermé/ouvert/mi-ouvert. Pour le routage LLM, la clé du disjoncteur doit être suffisamment spécifique pour isoler la surface défaillante. Les dimensions utiles incluent le fournisseur, le modèle, la région, le déploiement, le compte et la capacité. Un déploiement de complétion de texte peut être sain tandis qu’un chemin d’appel d’outils ou un point de terminaison régional est en échec.
Évitez d’ouvrir les circuits pour chaque erreur client. Une authentification invalide, des requêtes mal formées, un dépassement de contexte et un rejet par politique en disent généralement plus sur la requête que sur l’état de santé du fournisseur. Les disjoncteurs doivent réagir principalement à des signaux d’infrastructure transitoires tels que des échecs de connexion, des timeouts, de la surcharge et des erreurs serveur.
Préserver un contrat de capacités entre les modèles
Un modèle de repli n’est pas sûr simplement parce qu’il accepte une requête compatible OpenAI. Définissez le contrat minimal pour chaque alias de route.
route: support-agent-v3
requires:
modalities: [text]
streaming: true
tools: true
parallel_tool_calls: false
structured_output: json_schema
context_window_min: 64000
max_output_tokens_min: 4000
quality_gates:
task_success_rate_min: 0.94
schema_valid_rate_min: 0.995
policy:
same_model_failover_first: true
cross_model_fallback_allowed: true
Avant d’ajouter une cible à l’ensemble de repli, testez au moins :
- Paramètres de requête pris en charge
- Définition des outils et comportement des appels d’outils
- Validité des sorties structurées
- Forme des événements de streaming
- Limites de contexte et de sortie
- Comportement de sécurité adapté à l’application
- Champs de comptabilisation des jetons utilisés par les contrôles de coûts
- Latence et qualité sur des invites représentatives
Cette approche contract-first est particulièrement importante pour les flux de travail qui traversent plusieurs modalités. Le guide de routage d’agents multimodaux couvre des vérifications supplémentaires pour les routes texte, image, audio et vidéo.
Un contrôleur de repli en TypeScript
L’exemple suivant est volontairement neutre vis-à-vis des fournisseurs. Il suppose que les adaptateurs en amont normalisent les erreurs et les réponses avant que la couche de routage ne les voie.
type FailureKind =
| "connect"
| "timeout"
| "rate_limit"
| "overloaded"
| "server_error"
| "invalid_request"
| "auth"
| "policy"
| "context_overflow"
| "partial_stream"
| "unknown";
type Target = {
id: string;
contractId: string;
healthy: boolean;
circuit: "closed" | "open" | "half_open";
};
type RequestState = {
attempt: number;
sameTargetAttempts: number;
deadlineAt: number;
outputStarted: boolean;
sideEffectsPossible: boolean;
};
function canReplay(state: RequestState): boolean {
return !state.outputStarted && !state.sideEffectsPossible;
}
function isTransient(kind: FailureKind): boolean {
return [
"connect",
"timeout",
"rate_limit",
"overloaded",
"server_error",
].includes(kind);
}
function chooseNextAction(
kind: FailureKind,
state: RequestState,
current: Target,
equivalent: Target | undefined,
fallback: Target | undefined,
) {
if (!canReplay(state) || kind === "partial_stream") return { type: "stop" };
if (!isTransient(kind)) return { type: "stop" };
if (state.attempt >= 3 || Date.now() >= state.deadlineAt) {
return { type: "stop" };
}
if (
state.sameTargetAttempts < 1 &&
current.circuit === "closed" &&
current.healthy
) {
return { type: "retry", target: current };
}
if (equivalent?.healthy && equivalent.circuit !== "open") {
return { type: "failover", target: equivalent };
}
if (
fallback?.healthy &&
fallback.circuit !== "open" &&
fallback.contractId === current.contractId
) {
return { type: "fallback", target: fallback };
}
return { type: "stop" };
}
Le code de production a également besoin de délais avec jitter, de la propagation de l’annulation, d’identifiants de requête, de mises à jour du coupe-circuit, de télémétrie et d’un analyseur d’erreurs spécifique à l’adaptateur. La propriété importante est que la sécurité de relecture et la compatibilité de contrat sont vérifiées avant qu’une autre cible soit sélectionnée.
Traiter le repli du streaming comme un protocole distinct
Le streaming crée une frontière nette : une fois que le contenu atteint le client, la passerelle ne peut plus prétendre que la tentative n’a jamais eu lieu.
Si le service en amont échoue avant que le premier événement ne soit transmis, une nouvelle tentative ou un repli peut encore être transparent. Après la livraison du premier token, delta d’outil, événement d’image ou bloc audio, un basculement automatique du modèle risque de combiner deux réponses incompatibles.
Utilisez l’une de ces stratégies explicites :
- Échouer clairement le flux. Retournez un événement d’erreur stable avec l’identifiant de la requête et laissez le client proposer une nouvelle tentative.
- Mettre en tampon avant diffusion. Pour les réponses structurées courtes, validez le résultat complet avant de l’envoyer en aval. Cela se fait au détriment du temps jusqu’au premier token.
- Implémenter une reprise au niveau de l’application. Démarrez un nouveau tour avec un contexte explicite indiquant que la réponse précédente a été interrompue. Traitez cela comme une nouvelle génération du modèle, et non comme une continuation du même flux d’octets.
Ne concaténez pas silencieusement la sortie de deux modèles.
Separate tool-call reliability from model-call reliability
Une requête LLM peut être rejouable alors que l’outil qu’elle a sélectionné ne l’est pas. Un paiement, un e-mail, un déploiement, une écriture en base de données ou la création d’un ticket peuvent réussir même si la connexion au modèle échoue avant que l’application n’enregistre le résultat.
Protégez les outils d’écriture avec :
- Une clé d’idempotence dérivée de l’opération utilisateur, et non de la tentative du fournisseur
- Un enregistrement durable de l’exécution de l’outil
- Une déduplication à la frontière de l’outil
- Une distinction claire entre
planned,started,succeededetunknown - Une revue humaine pour les effets secondaires à fort impact incertains
Si des effets secondaires sont possibles et que leur résultat est inconnu, arrêtez le repli automatique. Commencez d’abord par réconcilier l’état de l’outil.
Observe fallback as a product outcome
Un faible taux d’erreur du fournisseur ne prouve pas que le repli fonctionne. Suivez le résultat complet du routage.
| Métrique | Ce qu’elle révèle |
|---|---|
| Taux de succès sur la cible primaire | Santé de base du fournisseur ou du déploiement |
| Taux de récupération après nouvelle tentative | Si les nouvelles tentatives vers la même cible sont utiles |
| Taux de récupération en bascule équivalente | Valeur des déploiements ou régions redondants |
| Taux de récupération du repli inter-modèles | Valeur de l’ensemble de modèles alternatifs |
| Taux de rejet du contrat | À quelle fréquence les cibles candidates échouent aux vérifications d’éligibilité |
| Validité du schéma après repli | Si les réponses « réussies » restent exploitables |
| Succès de la tâche après repli | Si les utilisateurs terminent toujours le travail prévu |
| Latence ajoutée par le repli | Coût de fiabilité payé par l’utilisateur |
| Écart de coût du repli | Impact de facturation du chemin de récupération |
| Durée d’ouverture du circuit et succès des sondes | Si les seuils du disjoncteur et le timing de récupération sont pertinents |
Consignez une raison de routage pour chaque tentative : cible sélectionnée, erreur normalisée, délai de nouvelle tentative, état du circuit, raison du repli, temps restant avant l’échéance de la requête et résultat final. Évitez de journaliser des prompts ou des sorties sensibles, sauf si la politique de données du produit l’autorise explicitement.
Test the failure paths before enabling automatic fallback
Exécutez une injection de défaillance dans un environnement de préproduction, puis déployez la politique en canari en production.
Transport and provider tests
- Coupez la connexion avant les en-têtes de réponse.
- Retournez des limites de débit répétées avec et sans conseils de nouvelle tentative.
- Simulez une surcharge et des erreurs serveur.
- Retardez le système principal jusqu’à ce que la date limite de la requête soit presque épuisée.
- Ouvrez un circuit cible et vérifiez que le trafic se déplace vers une route éligible.
- Rétablissez la cible et vérifiez que les sondes half-open ne restaurent pas trop tôt l’intégralité du trafic.
Tests de contrat
- Retirez un outil requis de l’adaptateur de repli.
- Retournez une sortie structurée invalide.
- Modifiez la forme d’un événement de streaming.
- Dépassez les limites de contexte ou de sortie.
- Comparez la qualité du repli sur un ensemble d’évaluation fixe.
Tests de sécurité des replays
- Échouez avant et après le premier événement streamé.
- Échouez après le début d’un outil côté écriture.
- Répétez la même clé d’idempotence.
- Annulez la requête client pendant que la tentative de repli est en attente.
Le test réussit uniquement lorsque le routeur choisit l’action attendue et enregistre la raison.
Où Flatkey s’insère
Flatkey fournit une clé API unique et une URL de base compatible OpenAI pour les modèles pris en charge, avec une utilisation et une facturation centralisées. Cela crée une frontière d’intégration stable pour l’accès multi-modèles et le routage.
Les équipes applicatives doivent néanmoins conserver la propriété du contrat de route décrit dans ce guide : quelles erreurs peuvent être relancées, quelles cibles sont équivalentes, si le repli inter-modèles est autorisé, comment les outils sont dédupliqués, et quel seuil de qualité une réponse rétablie doit atteindre.
Pour le chemin d’intégration le plus court, utilisez le Flatkey integration starter. Si vous migrez un client existant, la checklist de passerelle API compatible OpenAI couvre l’URL de base, les paramètres, le streaming et la vérification de la forme des erreurs.
Checklist de déploiement en production
- Normalisez les erreurs des fournisseurs dans une taxonomie interne stable.
- Définissez les actions de nouvelle tentative, de bascule équivalente, de repli inter-modèles et d’arrêt.
- Attribuez à un seul composant la responsabilité du budget de nouvelles tentatives.
- Appliquez une seule date limite de bout en bout et un nombre maximal de tentatives.
- Ajoutez un backoff exponentiel avec jitter pour les échecs transitoires.
- Cléz les coupe-circuits sur le plus petit domaine de défaillance utile.
- Définissez un contrat de capacité versionné pour chaque alias de route.
- Bloquez le changement automatique après le début d’une sortie partielle.
- Ajoutez l’idempotence et la réconciliation pour les outils côté écriture.
- Enregistrez les raisons de route et les résultats finaux des tâches.
- Injectez des défaillances de transport, de surcharge, de contrat, de streaming et d’effets de bord.
- Faites un canary du basculement équivalent avant d’activer le repli inter-modèles.
- Ajoutez des interrupteurs d’arrêt pour chaque cible et chaque politique de repli.
FAQ
Qu’est-ce que le routage de repli pour les API LLM ?
Le routage de repli pour les API LLM est une politique de fiabilité qui sélectionne un autre modèle ou fournisseur éligible lorsque la route privilégiée ne peut pas terminer une requête. Un repli sûr vérifie la sécurité du replay, la compatibilité des capacités, l’état du circuit, le budget de latence et l’état de sortie avant de basculer.
Quelle est la différence entre une nouvelle tentative LLM et un repli ?
Une nouvelle tentative répète la requête vers la même cible. Le basculement vers un secours se fait vers une infrastructure équivalente tout en préservant le contrat logique du modèle. Le repli inter-modèles change le modèle et nécessite donc des tests de compatibilité et de qualité plus poussés.
Une API LLM doit-elle réessayer chaque erreur 429 ou 5xx ?
Non. Les nouvelles tentatives doivent être bornées par une échéance de bout en bout, une limite d’essais, une politique de backoff, l’état du circuit et un contrôle de sécurité de réexécution. Un basculement équivalent peut être préférable à des appels répétés vers une cible en mauvais état.
Un routeur LLM peut-il changer de modèle pendant un flux ?
Pas de manière transparente après que la sortie est parvenue au client. Le comportement sûr par défaut consiste à interrompre clairement le flux ou à démarrer un nouveau tour au niveau de l’application. La concaténation de sorties partielles provenant de différents modèles peut corrompre le contrat de réponse.
Quand faut-il désactiver le repli inter-modèles ?
Désactivez-le lorsque le modèle alternatif ne peut pas préserver les outils requis, la sortie structurée, les limites de contexte, le comportement de sécurité, les seuils de qualité ou les garanties d’effets de bord. Désactivez aussi la relecture automatique après une sortie partielle ou une exécution d’outil incertaine.
Combien de tentatives de repli une requête LLM doit-elle effectuer ?
Il n’existe pas de nombre universel. Utilisez le plus petit nombre borné d’essais qui respecte le budget de latence du produit et les preuves issues des tests. Le routeur doit s’arrêter lorsque le délai restant ne permet pas une autre tentative utile.
Un repli fiable ne signifie pas « tout essayer ». Cela signifie rendre l’action suivante explicite, compatible, sûre à rejouer, observable et facile à interrompre.



