Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Limites de débit et reprises sûres

Après cette leçon: Je peux reprendre un appel sans provoquer de tempête.

Leçon de 70 min6 commandesLab agent de code IA : utiliser opencode pour expliquer et corriger du code, et vérifier son travail

Comment reprendre sans provoquer de tempête

Une limite de débit est une règle : un service n’accepte qu’un certain nombre d’appels en peu de temps. Une reprise est un nouvel essai après le refus d’un appel. Une reprise sans précaution peut aggraver une surcharge.

Le module sur le coût, le traçage et la fiabilité reprend une fois, puis se replie. Cette leçon va plus loin. Elle ajoute des attentes qui grandissent et une gigue qui disperse les appelants. Elle limite les essais et rend une reprise sûre à répéter.

À la fin de cette leçon

Remarque

Je peux reprendre un appel sans provoquer de tempête.

Mots clés

MotCe que ça veut direExemple
Limite de débitle maximum d’appels qu’un service accepte dans une fenêtre
Attente croissanteune attente qui grandit après chaque essai raté400, 800, 1600
Gigueune petite attente différente pour chaque appelant
Tempêtede nombreux appelants qui reprennent au même instant
Idempotentsans risque à répéter : le faire deux fois vaut une fois
Horloge simuléeun nombre qu’on avance à la main au lieu d’attendre

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Comment compte une limite de débit

Le service découpe le temps en fenêtres de 1000 millisecondes. Dans chaque fenêtre, il accepte un nombre fixe d’appels, ici 2. Il refuse les autres jusqu’au début de la fenêtre suivante.

Le temps est ici un nombre qu’on avance à la main. Rien n’attend : chaque exécution donne la même réponse.

Exemple détaillé : 2 appels par fenêtre

Instant (ms)FenêtreAppels déjà acceptésRésultat
000Accepté
001Accepté
002Refusé, la fenêtre est pleine
40002Refusé de nouveau
120010Accepté, nouvelle fenêtre

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Une erreur courante

Attention

Beaucoup pensent que reprendre aussitôt est le plus rapide pour obtenir une réponse. Si le service est surchargé, chaque reprise immédiate ajoute de la charge, et le service va plus mal pour tout le monde. Attendez d’abord, et de plus en plus longtemps.

Attente croissante et gigue

L’attente croissante double. Avec une base de 400, les attentes sont 400, 800, 1600. Mettez-lui un plafond, ici 2000, sinon elle grandit sans fin.

Si six appelants échouent ensemble et attendent tous 400, ils reviennent tous ensemble. Une gigue ajoute un petit nombre différent pour chacun : ils reviennent un par un.

Exemple détaillé : base 400, plafond 2000

Essai ratéAttenteGigue de la demande 3Prochain essai à (depuis 0)
140034434
2800471281 (depuis 434)
31600102891 (depuis 1281)
42000, le plafondNon utiliséeAbandon si les essais sont limités à 4

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Une reprise doit pouvoir se répéter sans risque

Parfois un appel a réussi mais la réponse s’est perdue en chemin. L’appelant croit à un échec et réessaie. Si la reprise débite ou envoie encore, vous avez agi deux fois.

Donnez une clé à chaque action. Le serveur retient les clés déjà vues. Une répétition avec une clé connue ne fait rien de nouveau.

Écrire l’assistant du modèle, partie 1

Commande
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

Commande
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 le script de reprises, partie 1

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'function attente(essai, base, plafond) { return Math.min(base * Math.pow(2, essai - 1), plafond); }' 'function gigue(id, essai) { return (id * 7 + essai * 13) % 50; }' 'function executer(nombre, limite, fenetre, base, plafond, essais, gigueActive) {' '  const file = [];' '  const historique = {};' '  const comptes = {};' '  for (let id = 1; id <= nombre; id++) { file.push([0, id, 1]); historique[id] = []; }' > reprises.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 le script de reprises, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  while (file.length > 0) {' '    file.sort(function (a, b) { return a[0] - b[0] || a[1] - b[1] || a[2] - b[2]; });' '    const item = file.shift();' '    const creneau = Math.floor(item[0] / fenetre);' '    historique[item[1]].push(item[0]);' '    comptes[creneau] = comptes[creneau] || 0;' '    if (comptes[creneau] < limite) { comptes[creneau] = comptes[creneau] + 1; continue; }' '    if (item[2] < essais) {' '      const ajout = gigueActive ? gigue(item[1], item[2]) : 0;' '      file.push([item[0] + attente(item[2], base, plafond) + ajout, item[1], item[2] + 1]);' '    }' '  }' '  return historique;' '}' >> reprises.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 le script de reprises, partie 3

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  for (const active of [false, true]) {' '    const h = executer(6, 2, 1000, 400, 2000, 4, active);' '    const vus = {};' '    let pire = 0;' '    for (const id in h) h[id].slice(1).forEach(function (t) { vus[t] = (vus[t] || 0) + 1; pire = Math.max(pire, vus[t]); });' '    console.log((active ? \"avec gigue\" : \"sans gigue\") + \" : plus de reprises sur une milliseconde \" + pire);' '    console.log(\"  la requête 3 essaie à \" + h[3].join(\" \") + \", la requête 5 à \" + h[5].join(\" \"));' '  }' '  const reponse = await demander([{ role: \"user\", content: \"En une phrase courte, pourquoi ajouter une attente aléatoire à une reprise ?\" }], \"Pour que de nombreux appelants ne reprennent pas tous au même instant et ne surchargent pas à nouveau le service.\", 60);' '  console.log(\"le modèle dit : \" + reponse.texte);' '}' 'main();' >> reprises.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 les reprises

Commande
docker exec -w /home/node/project agent node reprises.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.

Ce que le Run affiche

LigneCe qu’elle montre
sans gigue : plus de reprises sur une milliseconde 4Quatre appelants sont revenus au même instant
la requête 3 essaie à 0 400 1200, la requête 5 à 0 400 1200 2800Sans gigue, les instants sont réguliers et identiques
avec gigue : plus de reprises sur une milliseconde 1Deux reprises ne partagent jamais un instant
la requête 3 essaie à 0 434 1281 2891, la requête 5 à 0 448 1259 2883Chaque appelant attend un peu différemment
le modèle dit : ...Une phrase du labo. Un échantillon enregistré si aucun modèle ne répond

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

À propos de ce labo et de sa source: Lab agent de code IA : utiliser opencode pour expliquer et corriger du code, et vérifier son travail

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.