Une équipe tombe en panne autrement
Une panne multi-agents est une façon dont une équipe d’agents déraille, alors qu’aucun agent seul ne le ferait. Cela compte, car la faute est dans la conversation entre eux, et chaque agent paraît correct isolément.
On la trouve en lisant la transcription, la liste des messages qu’ils ont envoyés.
À la fin de cette leçon
Remarque
Je peux trouver la panne dans une transcription et nommer son genre.
Mots-clés
| Mot | Ce que ça veut dire |
|---|---|
| Transcription | les messages envoyés par les agents, dans l’ordre |
| Boucle | le même message envoyé encore et encore |
| Interblocage | deux agents qui attendent chacun l’autre |
| Dérive du coût | une consommation de jetons qui dépasse le budget |
| Transmise | une hypothèse qui est reprise plus tard comme un fait |
| Garde-fou | une règle dans le code qui arrête une panne tôt |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Quatre façons de dérailler pour une équipe
Une boucle répète un seul message. Un interblocage met deux agents à attendre chacun que l’autre commence. Une dérive du coût grandit, car chaque tour relit tout l’historique.
La quatrième est plus discrète. Un exécutant devine, l’agent suivant répète l’hypothèse, et au troisième elle est écrite comme un fait.
Exemple travaillé : le signe et le garde-fou
| Panne | Signe dans une transcription | Garde-fou |
|---|---|---|
| Boucle | Mêmes émetteur, destinataire et texte trois fois | S’arrêter à la troisième répétition |
| Interblocage | Deux messages qui disent tous deux attente, échangés | Une limite de temps et un départage |
| Transmise | Une hypothèse, puis les mêmes mots comme un fait | Faire voyager le statut avec l’affirmation |
| Dérive | Des jetons par tour qui ne cessent de monter | Un budget pour toute l’exécution |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Contrôlez d’abord le signe le plus net
Une vraie transcription peut montrer plusieurs signes. Fixez un ordre et gardez-le. Un interblocage et une boucle arrêtent tous deux le travail, nommez-les donc avant le coût.
Le module précédent traitait le garde-fou de boucle. Cette leçon apprend à reconnaître les quatre, pour savoir quel garde-fou ajouter.
Une erreur fréquente
Attention
Beaucoup ajoutent une nouvelle tentative quand une équipe cale. Elle allonge une boucle et ne raccourcit pas un interblocage. Nommez d’abord la panne, puis choisissez le garde-fou qui lui convient.
É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 le détecteur de pannes, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'function m(de, vers, texte, jetons, statut) {' ' return { de: de, vers: vers, texte: texte, jetons: jetons, statut: statut };' '}' 'const T = {};' 'T.boucle = [m(\"auteur\", \"relecteur\", \"relis le brouillon\", 300, \"aucun\"), m(\"relecteur\", \"auteur\", \"ajoute une source\", 200, \"aucun\"),' ' m(\"auteur\", \"relecteur\", \"relis le brouillon\", 300, \"aucun\"), m(\"relecteur\", \"auteur\", \"ajoute une source\", 200, \"aucun\"),' ' m(\"auteur\", \"relecteur\", \"relis le brouillon\", 300, \"aucun\")];' 'T.interblocage = [m(\"planificateur\", \"verificateur\", \"attente de la relecture avant de planifier\", 150, \"aucun\"),' ' m(\"verificateur\", \"planificateur\", \"attente du plan avant de relire\", 150, \"aucun\")];' > panne.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 détecteur de pannes, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'T.transmise = [m(\"lecteur\", \"planificateur\", \"les visites du samedi ont monté de 40 pour cent\", 200, \"hypothese\"),' ' m(\"planificateur\", \"auteur\", \"les visites du samedi ont monté de 40 pour cent\", 200, \"fait\")];' 'T.derive = [m(\"a\", \"b\", \"tour un\", 1000, \"aucun\"), m(\"b\", \"a\", \"tour deux\", 2000, \"aucun\"), m(\"a\", \"b\", \"tour trois\", 4000, \"aucun\"),' ' m(\"b\", \"a\", \"tour quatre\", 8000, \"aucun\"), m(\"a\", \"b\", \"tour cinq\", 16000, \"aucun\")];' 'T.correct = [m(\"planificateur\", \"lecteur\", \"cherche la demande du dimanche\", 200, \"aucun\"), m(\"lecteur\", \"planificateur\", \"212 sur 400\", 150, \"fait\")];' >> panne.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 détecteur de pannes, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function deux(ms, essai) {' ' return ms.some(function (x, i) { return ms.some(function (y, j) { return i < j && essai(x, y); }); });' '}' 'function interblocage(ms) {' ' return deux(ms, function (x, y) {' ' return x.texte.startsWith(\"attente\") && y.texte.startsWith(\"attente\") && x.de === y.vers && x.vers === y.de;' ' });' '}' 'function boucle(ms) {' ' return ms.some(function (x) {' ' return ms.filter(function (y) { return y.de === x.de && y.vers === x.vers && y.texte === x.texte; }).length >= 3;' ' });' '}' >> panne.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 détecteur de pannes, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function transmise(ms) {' ' return deux(ms, function (x, y) { return x.statut === \"hypothese\" && y.statut === \"fait\" && x.texte === y.texte; });' '}' 'function total(ms) { return ms.reduce(function (a, x) { return a + x.jetons; }, 0); }' 'function trouver(ms, budget) {' ' if (interblocage(ms)) return \"interblocage\";' ' if (boucle(ms)) return \"boucle\";' ' if (transmise(ms)) return \"hypothese-transmise\";' ' return total(ms) > budget ? \"derive-du-cout\" : \"aucune\";' '}' >> panne.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 détecteur de pannes, partie 5
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' for (const nom of Object.keys(T)) {' ' console.log(nom + \" : \" + T[nom].length + \" messages, \" + total(T[nom]) + \" jetons, trouvé \" + trouver(T[nom], 20000));' ' }' ' const q = [{ role: \"user\", content: \"En une phrase : quelle règle simple empêche deux agents de s’envoyer le même message sans fin ?\" }];' ' const r = await demander(q, \"Compter chaque message et s’arrêter à la troisième répétition.\", 40);' ' console.log(\"Modèle : \" + r.texte.trim());' '}' 'main();' >> panne.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 le détecteur de pannes
docker exec -w /home/node/project agent node panne.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.
Ce sont des transcriptions enregistrées
Un vrai essai dépenserait le quota du labo sur une seule équipe en panne. Les cinq transcriptions sont donc des données enregistrées, courtes et inventées. Le détecteur est du vrai code.
Le seul appel en direct demande une règle. Ses mots changent à chaque exécution.
Une sortie possible
| Ligne | Ce qu’elle montre |
|---|---|
| boucle : 5 messages, 1300 jetons, trouvé boucle | Un message trois fois |
| interblocage : 2 messages, 300 jetons, trouvé interblocage | Chacun attend l’autre |
| transmise : 2 messages, 400 jetons, trouvé hypothese-transmise | Une hypothèse est devenue un fait |
| derive : 5 messages, 31000 jetons, trouvé derive-du-cout | Au-dessus du budget de 20000 |
| correct : 2 messages, 350 jetons, trouvé aucune | Aucun signe de panne |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.