Guide et aperçu

Routage fiable de l'API LLM : délais d'attente, tentatives et replis de modèle sans régressions sémantiques

Une architecture pratique pour classer les échecs de l'API LLM, appliquer un budget de latence, sélectionner des modèles de repli compatibles, protéger les effets secondaires et valider chaque réponse acceptée.

Une demande de secours échoue simplement parce qu'un autre modèle a renvoyé HTTP 200. Le remplacement peut dépasser le budget de latence d'origine, omettre les champs JSON requis, appeler un autre outil ou produire une réponse avec une sémantique sensiblement différente. Un routage fiable de l'API LLM nécessite donc plus qu'une liste ordonnée de modèles : il nécessite un contrat, un classificateur d'échec, une politique de tentative limitée et une validation avant acceptation.

La règle centrale est simple : réessayez uniquement lorsque l'échec est vraisemblablement temporaire, et revenez uniquement lorsque la route suivante peut encore satisfaire le contrat de demande d'origine.

Définir le contrat de routage avant de choisir les modèles

Commencez par décrire ce qu'une réponse réussie doit apporter. Ce contrat de routage doit être lisible par machine et attaché à chaque charge de travail ou classe de requête.

{ "workload": "invoice_extraction", "modalités": ["texte", "image"], "max_input_tokens": 50 000, "requires_tools": faux, "structured_output": { "obligatoire": vrai, "schema_id": "facture-v3", "strict" : vrai }, "allowed_model_classes": ["extraction de documents"], "max_cost_usd" : 0,08, "deadline_ms": 8000

Le contrat doit couvrir les modalités requises, la capacité contextuelle, la prise en charge des outils, le comportement de sortie structuré, les classes de modèles acceptables, le coût maximum et le délai de bout en bout. Ajoutez des contraintes spécifiques à l'application si nécessaire, telles que les régions autorisées, la longueur de sortie minimale ou un motif de fin requis.

Recommandation : conservez des groupes de routage séparés et testés pour le texte brut, les sorties contraintes par un schéma, l'utilisation des outils, la vision et les requêtes à contexte long. Un modèle qui constitue une solution de secours acceptable pour le texte n'est pas automatiquement une solution de secours acceptable pour l'appel d'un outil ou la saisie d'une image.

Classer l'échec avant d'agir

Les erreurs d'authentification, les requêtes mal formées, les limites de débit et les pannes de serveur nécessitent des réponses différentes. Traiter chaque réponse d'échec comme une tentative réessayable gaspille la capacité et peut masquer les défauts.

Classe d'échecExemplesAction par défaut Échec de requête permanentIdentifiants non valides, paramètres mal formés, fonctionnalité non prise en chargeArrêter et renvoyer une erreur claire Incompatibilité d'itinéraireContexte trop volumineux, entrée d'image non prise en charge, mode schéma indisponibleEssayez uniquement un itinéraire compatible Échec du transport transitoireRéinitialisation de la connexion, échec DNS, délai d'expiration sélectionnéRéessayez dans les limites du budget restant Échec de capacité ou de débitHTTP 429, service surchargé, réponses 5xx sélectionnéesSuivez les conseils de nouvelle tentative ou utilisez une solution de secours saine Réponse réussie non valideJSON mal formé, outil inconnu, champ obligatoire manquantRejeter, puis réessayer ou revenir en arrière si la politique le permet Exécution ambiguëConnexion perdue après que le fournisseur ait accepté la demandeDédupliquer avant de rejouer

Fait : les demandes infructueuses à débit limité peuvent toujours être prises en compte dans les limites du fournisseur. Des tentatives immédiates agressives peuvent donc aggraver la limitation au lieu de la résoudre. Les nouvelles tentatives consomment également de la capacité supplémentaire en cas de panne, et les politiques de nouvelle tentative sur plusieurs couches d'application peuvent multiplier la charge résultante.

Recommandation : laissez une couche s'approprier les tentatives de génération de modèle. Dans une architecture typique, la passerelle API AI est le bon propriétaire car elle voit l'état de l'itinéraire, l'historique des tentatives, la latence et le coût. Désactivez les tentatives automatiques dans les clients de niveau inférieur lorsque cela est possible, ou comptez-les explicitement dans le même budget de tentatives.

Dépenser un budget de latence de bout en bout

Les délais d'attente par tentative sont insuffisants. Trois tentatives avec un délai d'attente de cinq secondes peuvent transformer une opération prévue de cinq secondes en une réponse de quinze secondes, avant que l'attente et la validation ne soient incluses.

Enregistrez une date limite absolue lorsque la demande entre dans la passerelle. Avant chaque tentative, calculez le temps restant :

remaining = date limite - current_time
requis = connect_allowance + Generation_allowance + validation_allowance
si restant < requis :
    stop_sans_launching_another_attempt

Pour un délai de huit secondes, une allocation initiale raisonnable pourrait réserver 300 ms pour le travail de la passerelle et la validation finale, accorder jusqu'à 4,5 secondes pour la route principale et conserver environ 3,2 secondes pour une solution de secours. Ces valeurs sont un exemple et non une référence. Ils doivent être dérivés des distributions de latence mesurées pour les fournisseurs, modèles, régions et tailles de sortie réels.

Utiliser un intervalle exponentiel limité avec instabilité pour les tentatives transitoires :

délai = random(0, min(cap, base * 2^retry_index))

Les indications de nouvelle tentative du fournisseur, telles qu'une valeur de nouvelle tentative, doivent avoir la priorité lorsqu'elles respectent le délai restant. Arrêtez-vous après un petit nombre de tentatives. Une politique courante est une tentative principale plus une tentative de secours, avec une nouvelle tentative facultative sur le même itinéraire uniquement en cas d'échec de connexion précoce qui n'aurait pas pu générer de sortie facturable.

Compromis : le repli séquentiel améliore la disponibilité mais augmente la latence de queue. Les requêtes parallèles ou couvertes peuvent réduire la latence lors des ralentissements, mais elles consomment plus de capacité et peuvent entraîner des frais pour plusieurs générations réussies. La couverture doit être limitée aux charges de travail critiques en termes de latence et sans effets secondaires, avec annulation et contrôle des coûts.

Sélectionnez les solutions de secours par capacité, et non par classement

Une table de secours doit coder la compatibilité plutôt qu'un ordre de préférence global. Filtrez les routes candidates par rapport au contrat avant de prendre en compte l'état de santé, la latence ou le prix.

candidats = itinéraires
  .filter(supports_required_modalities)
  .filter (context_limit >=estimate_input_size)
  .filter(supports_required_tools)
  .filter(supports_requested_schema_mode)
  .filter (model_class dans Allowed_model_classes)
  .filter (coût_estimé <= coût_restant_budget)
  .filter (not_temporously_suppressed)
sélectionné = rang (candidats, santé, latence, coût)

La prise en charge des sorties structurées mérite des tests explicites. Même lorsque deux routes annoncent une génération contrainte par le schéma, elles peuvent prendre en charge différents sous-ensembles de schéma JSON ou interpréter les cas extrêmes différemment. Les modèles compatibles avec les outils peuvent également différer dans la sélection des outils, la construction des arguments et le comportement des appels parallèles.

Fait : le changement de famille de modèles peut préserver la disponibilité des transports tout en modifiant le style, la qualité du raisonnement, le comportement en matière de sécurité, la tokenisation et la sélection des outils. Le succès HTTP ne constitue pas une preuve d'équivalence sémantique.

Prédiction : à mesure que les catalogues de modèles se développent, les politiques de routage de production utiliseront de plus en plus de profils de fonctionnalités versionnés et de tests d'acceptation spécifiques à la charge de travail au lieu de listes de modèles statiques. Considérez cela comme une orientation de conception et non comme une garantie quant au comportement du fournisseur.

Valider la réponse avant de l'accepter

Exécutez chaque réponse, y compris la réponse principale, via le même pipeline d'acceptation. La validation doit avoir lieu avant que le résultat ne soit mis en cache, facturé en interne comme réussi ou transmis à un exécuteur d'outil.

  1. Confirmez que le transport est terminé et que l'enveloppe de réponse peut être analysée.
  2. Vérifiez le motif de fin et rejetez la troncature lorsque la sortie complète est requise.
  3. Valider la sortie structurée par rapport au schéma d'origine.
  4. Vérifiez les champs obligatoires, les valeurs d'énumération et les invariants d'application.
  5. Autoriser uniquement les noms d'outils enregistrés et valider les arguments par rapport à chaque schéma d'outil.
  6. Appliquez des contrôles sémantiques spécifiques à la charge de travail là où une fausse acceptation serait coûteuse.

Pour l'extraction des factures, les contrôles sémantiques peuvent nécessiter un total non négatif, un code de devise pris en charge et des totaux de lignes dans une tolérance explicitement définie. Pour la classification, exigez une étiquette de l'ensemble autorisé. Pour la génération de code, l'analyse ou la compilation peuvent être appropriées. Ces contrôles ne prouvent pas la qualité, mais ils empêchent que des violations prévisibles du contrat soient considérées comme des succès.

Ne réparez pas silencieusement chaque réponse mal formée. La normalisation déterministe, telle que la suppression des espaces environnants inoffensifs, peut être acceptable. Deviner les champs financiers manquants ou réécrire les arguments de l'outil change la signification du modèle et devrait déclencher un rejet ou un examen humain.

Séparer les tentatives de génération des effets secondaires

Les requêtes LLM utilisent généralement HTTP POST, qui n'est pas intrinsèquement idempotent. Plus important encore, une réponse modèle peut déclencher une action externe telle que facturer un moyen de paiement, envoyer un message, créer un ticket ou modifier l'infrastructure. Réessayer de générer et rejouer cette action sont des décisions distinctes.

Attribuez un ID d'opération à la limite de l'application et un ID de tentative à chaque appel de modèle. Conserver l'état d'exécution de l'outil par rapport à une clé déterministe, telle que :

execution_key = opération_id + nom_outil + canonical_arguments_hash

Avant d'exécuter un outil, vérifiez si cette clé est en attente, terminée ou en échec. Renvoie le résultat stocké pour une exécution terminée plutôt que de l'exécuter à nouveau. Pour les opérations dont les arguments peuvent légitimement changer, nécessitent une approbation au niveau de l'application ou un nouvel ID d'opération.

Un délai d'attente ambigu nécessite un traitement spécial. Si la connexion échoue après la transmission d'une requête, la passerelle peut ne pas savoir si la génération a eu lieu. Une clé d'idempotence prise en charge par le fournisseur peut être utile lorsqu'elle est disponible. Sinon, enregistrez le résultat comme inconnu et appliquez une politique de relecture spécifique à la charge de travail au lieu de supposer que rien ne s'est produit.

Supprimez les routes non saines et exposez chaque tentative

Un disjoncteur ou une suppression temporaire de l'état empêche chaque nouvelle demande de redécouvrir le même itinéraire défaillant. Ouvrez le circuit après un taux d'erreur défini ou un seuil de défaillance consécutive, puis admettez des sondes limitées dans un état semi-ouvert. Ajustez les seuils par itinéraire et classe d'échec afin qu'une demande client mal formée ne puisse pas faire apparaître un modèle sain indisponible.

Enregistrez un événement au niveau de la demande et un événement par tentative. Les champs utiles incluent l'ID d'opération, l'ID de tentative, le fournisseur et le modèle sélectionnés, la classe d'échec, le code d'état, la latence, le nombre de jetons, le coût estimé, la raison de repli, le résultat de la validation, l'état du circuit et le résultat final. Rédigez ou hachez les invites, les sorties et les arguments des outils en fonction de leurs exigences de sensibilité et de conservation.

Les mesures opérationnelles utiles incluent le taux de repli, les tentatives par demande terminée, le taux d'épuisement des délais, le taux de rejet de validation, les résultats ambigus, le coût par réponse acceptée et la latence par itinéraire final. Un taux de réussite HTTP croissant ainsi qu'un taux de rejet de validation croissant sont un avertissement selon lequel la disponibilité du transport masque les échecs des contrats.

Liste de contrôle du déploiement de la production

  • Définissez un contrat de routage versionné pour chaque classe de charge de travail.
  • Mappez les erreurs du fournisseur en catégories permanentes, transitoires, incompatibles, à réponse non valide et ambiguë.
  • Choisissez un propriétaire de nouvelle tentative et limitez le nombre total de tentatives.
  • Propagez une date limite absolue via la passerelle, le client fournisseur, la validation et l'exécution de l'outil.
  • Créez des groupes de secours dont les capacités ont été testées plutôt qu'une seule chaîne de modèles globale.
  • Valider les schémas, les appels d'outils, les motifs de fin et les invariants de domaine.
  • Effets secondaires de déduplication avec les clés d'opération et d'exécution.
  • Ajouter une suppression de route avec des sondes semi-ouvertes délimitées.
  • Consignez la latence au niveau des tentatives, les jetons, le coût, les échecs et les résultats d'acceptation.
  • Délai d'expiration d'injection, 429 s, erreurs 5xx sélectionnées, JSON mal formé, débordement de contexte et succès lents lors de la préparation.

Commencez par une route principale et une solution de secours compatible pour une seule charge de travail à faible risque. Comparez la qualité, la latence et le coût des réponses acceptées avant d’étendre la stratégie. L’objectif n’est pas le taux de repli le plus élevé possible. Il s'agit d'un système limité qui renvoie une réponse satisfaisant le contrat d'origine ou échoue clairement avant de provoquer un travail en double ou des dommages sémantiques.

Lecture connexe

FAQ

Questions fréquemment posées

Quelles erreurs de l’API LLM doivent déclencher une nouvelle tentative ?
Réessayez uniquement les échecs classés comme transitoires, tels que les échecs de connexion sélectionnés, les délais d'attente, les limites de débit et les erreurs du serveur du fournisseur. Ne réessayez pas automatiquement les informations d'identification non valides, les demandes mal formées, les fonctionnalités non prises en charge ou les erreurs de limite de contexte. Une erreur de limite de contexte peut justifier un repli compatible avec un contexte long, mais répéter la même requête sur la même route ne la corrigera pas.
Combien de tentatives de repli de modèle une passerelle doit-elle autoriser ?
Il n’existe pas de numéro universel, mais la limite doit être faible et régie par un délai unique de bout en bout. Un point de départ pratique est une tentative principale et une solution de repli compatible. Ajoutez une autre tentative uniquement lorsque les gains de fiabilité mesurés justifient la latence, la capacité et le coût supplémentaires.
Les requêtes d’appel d’outils peuvent-elles être réessayées en toute sécurité ?
La génération de modèle peut être réessayée dans le cadre d'une stratégie limitée, mais l'exécution d'outils externes doit être dédupliquée séparément. Utilisez un ID d'opération et une clé d'exécution déterministe, conservez le résultat de l'outil et évitez de rejouer les paiements, les messages ou d'autres effets secondaires simplement parce que la génération a été répétée.
Un modèle moins cher peut-il être utilisé comme solution de repli automatique ?
Uniquement lorsqu'il satisfait au même contrat de routage et réussit les tests d'acceptation spécifiques à la charge de travail. Le prix à lui seul n’établit pas la compatibilité. Vérifiez les exigences en matière de modalité, de contexte, de sortie structurée, d'outil, de latence et de qualité avant de placer un modèle dans un groupe de secours.