Continuer à fonctionner quand le modèle échoue
Une solution de repli est ce que fait une fonction quand un appel à un modèle échoue, pour que l’utilisateur obtienne quand même quelque chose. C’est utile parce que les appels échouent de plusieurs façons, et qu’une seule réponse à toutes est mauvaise pour la plupart.
Un délai dépassé mérite un nouvel essai. Un refus, non. Un budget du jour épuisé demande une réponse en cache ou un message honnête. Choisissez selon la panne.
À la fin de cette leçon
Remarque
Je peux faire fonctionner une fonction quand un appel à un modèle échoue, en choisissant un repli pour chaque sorte de panne.
Mots clés
| Mot | Ce que ça veut dire |
|---|---|
| Repli | ce que vous faites à la place quand un appel échoue |
| Nouvel essai | redemander au même modèle, après une attente |
| Second modèle | un autre modèle interrogé quand le premier échoue |
| Réponse simple | un message fixe et honnête, sans modèle |
| Dégrader | donner une réponse plus petite plutôt que rien |
| Nature de la panne | la raison pour laquelle un appel a échoué |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un repli est une chaîne, dans l’ordre
Listez les options de la moins coûteuse à la plus dégradée. D’abord un nouvel essai, après une attente. Puis un second modèle. Puis une réponse en cache, qui peut être vieille. Enfin une réponse simple : un message fixe, vrai, qui dit à l’utilisateur quoi faire.
Chaque étape coûte du temps et de l’argent. Une chaîne qui tente tout à chaque panne double votre facture pendant une panne générale.
Exemple détaillé : quel repli convient
| Panne | D’abord | Pourquoi |
|---|---|---|
| Délai dépassé, limite de débit | Un nouvel essai | Passe souvent tout seul |
| Erreur du serveur | Second modèle | Le premier est en panne |
| Mauvais format | Un nouvel essai | Un second essai passe souvent |
| Refus | Réponse simple | Redemander ne changera rien |
| Budget épuisé | Réponse en cache | Aucun appel n’est permis |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Borner la chaîne et le dire
Mettez une limite à chaque étape : un nouvel essai, un second modèle. Attendez entre deux essais, et comptez l’attente dans le délai de l’utilisateur. Ne laissez jamais un repli cacher une panne. Notez quelle étape a répondu.
Une réponse en cache peut être périmée : dites-le si cela compte. Une réponse simple ne doit jamais faire croire qu’elle vient du modèle.
Une erreur courante
Attention
Beaucoup pensent que réessayer est toujours le repli le plus sûr. Mais réessayer un refus fait perdre de l’argent, et réessayer pendant une panne ajoute de la charge. Réessayez seulement les pannes qui peuvent passer seules, et une seule fois.
Écrire l’assistant du modèle, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Les jetons d’une réponse, ou null si elle n’en donne pas.' 'function compter(donnees, nom) {' ' return donnees.usage && typeof donnees.usage[nom] === \"number\" ? donnees.usage[nom] : null;' '}' > model.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire l’assistant du modèle, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function demander(messages, echantillon, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"statut \" + res.status);' ' const d = await res.json();' ' return { texte: d.choices[0].message.content, entree: compter(d, \"prompt_tokens\"), sortie: compter(d, \"completion_tokens\"), enregistre: false };' ' } catch (erreur) {' ' console.log(\"Échantillon enregistré : aucun modèle n’a répondu (\" + erreur.message + \").\");' ' return { texte: echantillon, entree: null, sortie: null, enregistre: true };' ' }' '}' 'module.exports = { demander };' >> model.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la chaîne de repli, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' '' 'let maintenant = 0; // des millisecondes, sur une horloge que nous avançons nous-mêmes' 'const stock = new Map([[\"horaires\", \"Nous ouvrons à neuf heures et fermons à dix-sept heures.\"]]);' 'const SIMPLE = \"Désolé, l’assistant ne peut pas répondre maintenant. Réessayez plus tard.\";' '// Une panne enregistrée remplace une vraie. Rien ici ne provoque de vraie erreur.' 'function echouer(nature) { throw new Error(nature); }' > fallback5.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la chaîne de repli, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function secondModele() {' ' const messages = [{ role: \"user\", content: \"Donne les horaires, de neuf à dix-sept heures, en une phrase.\" }];' ' return (await demander(messages, \"Nous ouvrons à neuf heures et fermons à dix-sept heures.\", 40)).texte;' '}' >> fallback5.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la chaîne de repli, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function repondre(question, second) {' ' const etapes = [' ' [\"premier modèle\", function () { echouer(\"limite_de_debit\"); }],' ' [\"nouvel essai\", function () { maintenant = maintenant + 200; echouer(\"limite_de_debit\"); }],' ' [\"second modèle\", second],' ' [\"cache\", function () { return stock.has(question) ? stock.get(question) : echouer(\"absent\"); }],' ' ];' >> fallback5.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la chaîne de repli, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' for (const [nom, lancer] of etapes) {' ' try {' ' const texte = await lancer();' ' console.log(question + \" : \" + nom + \" a répondu à \" + maintenant + \" ms\");' ' return texte;' ' } catch (erreur) {' ' console.log(question + \" : \" + nom + \" a échoué (\" + erreur.message + \")\");' ' }' ' }' ' console.log(question + \" : réponse simple\");' ' return SIMPLE;' '}' >> fallback5.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire la chaîne de repli, partie 5
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const panne = function () { echouer(\"erreur_serveur\"); };' ' await repondre(\"horaires\", secondModele);' ' await repondre(\"horaires\", panne);' ' await repondre(\"remboursement\", panne);' '}' 'main();' >> fallback5.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Lancer la chaîne
docker exec -w /home/node/project agent node fallback5.jsAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Les pannes sont enregistrées
Rien dans ce Run ne provoque de vraie panne. Les refus et l’erreur du serveur sont écrits dans le script comme données enregistrées, et l’horloge est un nombre qu’il avance. Seul le second modèle est un vrai appel.
Un vrai système reçoit ces erreurs d’un vrai réseau, et attend pour de vrai entre deux essais.
Une sortie possible
| Ligne | Ce qu’elle montre |
|---|---|
| horaires : premier modèle a échoué (limite_de_debit) | Une panne enregistrée |
| horaires : nouvel essai a échoué (limite_de_debit) | Le nouvel essai, après 200 ms sur notre horloge |
| horaires : second modèle a répondu à 200 ms | Le seul vrai appel |
| horaires : cache a répondu à 400 ms | Le second modèle est en panne, le cache répond |
| remboursement : réponse simple | Rien n’était en cache, on utilise le message simple |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.