Trier la boîte du support
Classer des textes avec un modèle, c’est lui demander de choisir une étiquette dans une liste fixe pour chaque message. C’est utile, car un programme sait aiguiller une étiquette, mais pas une phrase libre.
L’appli de la cafétéria d’un campus veut envoyer chaque message à la facturation, à l’équipe de l’appli ou à un guichet général. Un modèle peut lire le message et nommer le bon service. Reste à savoir combien de fois il a raison.
À la fin de cette leçon
Remarque
Je peux étiqueter des textes d’après une liste fixe et mesurer la part d’étiquettes justes.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Étiquette | un mot qui nomme le genre d’un texte | facturation |
| Étiquettes autorisées | la liste fixe où l’étiquette doit se trouver | |
| Inconnu | l’étiquette d’un texte qui ne va dans aucune case | |
| Réponse connue | l’étiquette choisie d’avance par une personne | |
| Exactitude | la part des étiquettes égales à la réponse connue | |
| Cas de test | des textes à réponse connue, pour mesurer |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Donner une liste fixe et une étiquette inconnu
Mettez les étiquettes autorisées dans la consigne et dites : répondre uniquement par le mot. Ajoutez une porte de sortie. Si aucune étiquette ne convient, le modèle doit répondre inconnu, pour ne pas être forcé d’en choisir une fausse.
Nettoyez ensuite ce qui revient. Une réponse peut avoir une majuscule, un point ou des mots en plus. Transformez-la en une étiquette autorisée, ou en inconnu.
Exemple travaillé : nettoyer cinq réponses
| Réponse | Étiquette nettoyée | Pourquoi |
|---|---|---|
| facturation | facturation | Déjà une étiquette autorisée |
| Bogue. | bogue | Majuscule et point retirés |
| "autre" | autre | Guillemets retirés |
| C’est un bogue | inconnu | Plusieurs mots, pas une étiquette |
| remboursement | inconnu | Pas dans la liste autorisée |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Mesurer avec des réponses connues
Pour savoir si un étiqueteur est bon, testez-le. Écrivez d’abord des cas de test : des textes à réponse connue, choisie par une personne. Lancez le modèle sur chacun, nettoyez l’étiquette et comparez.
L’exactitude est le nombre d’étiquettes justes divisé par le nombre total, en pourcentage entier. Lisez ensuite les fausses : elles montrent quoi corriger dans la consigne.
Écrire l’aide 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\";' '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 || 200 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"statut \" + res.status);' ' return (await res.json()).choices[0].message.content;' > 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’aide du modèle, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' } catch (erreur) {' ' console.log(\"Échantillon enregistré : aucun modèle n’a répondu (\" + erreur.message + \").\");' ' const liste = [].concat(echantillon);' ' const tour = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' ' return liste[Math.min(tour, liste.length - 1)];' ' }' '}' '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 l’étiqueteur, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' '' 'const autorisees = [\"facturation\", \"bogue\", \"autre\"];' '// Des cas à réponse connue, écrits par une personne avant d’interroger le modèle.' 'const cas = [' ' { texte: \"On m’a débité deux fois mon repas.\", attendu: \"facturation\" },' ' { texte: \"L’appli se ferme quand j’appuie sur Payer.\", attendu: \"bogue\" },' ' { texte: \"À quelle heure ouvre la cafétéria le samedi ?\", attendu: \"autre\" },' ' { texte: \"Mon remboursement n’est toujours pas arrivé.\", attendu: \"facturation\" },' '];' > etiquette5.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’étiqueteur, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// Échantillons enregistrés, utilisés seulement si aucun modèle ne répond. Deux sont brouillons exprès.' 'const echantillons = [\"facturation\", \"Bogue.\", \"autre\", \"remboursement\"];' 'const DEMANDE = \"Donne à ce message d’assistance exactement un mot de cette liste : facturation, bogue, autre. Si aucun ne convient, réponds inconnu. Réponds uniquement par le mot.\n\nMessage : \";' '' '// Transformer toute réponse en une étiquette autorisée, ou en inconnu.' 'function nettoyerEtiquette(reponse) {' ' let texte = reponse.trim().toLowerCase();' ' while (texte.length > 0 && (texte.endsWith(\".\") || texte.endsWith(\" \"))) texte = texte.slice(0, -1);' ' return autorisees.includes(texte) ? texte : \"inconnu\";' '}' >> etiquette5.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’étiqueteur, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' let justes = 0;' ' let inconnus = 0;' ' for (let rang = 0; rang < cas.length; rang = rang + 1) {' ' const consigne = DEMANDE + cas[rang].texte;' ' const reponse = await demander([{ role: \"user\", content: consigne }], echantillons[rang], 10);' ' const etiquette = nettoyerEtiquette(reponse);' ' if (etiquette === cas[rang].attendu) justes = justes + 1;' ' if (etiquette === \"inconnu\") inconnus = inconnus + 1;' ' console.log((rang + 1) + \" \" + etiquette + \" (attendu : \" + cas[rang].attendu + \") \" + (etiquette === cas[rang].attendu ? \"juste\" : \"faux\"));' ' }' ' console.log(\"Exactitude : \" + justes + \" sur \" + cas.length + \" (\" + Math.floor(justes * 100 / cas.length) + \" pour cent)\");' ' console.log(\"Étiquettes inconnues : \" + inconnus);' '}' 'main();' >> etiquette5.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.
Le lancer sur quatre messages
docker exec -w /home/node/project agent node etiquette5.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.
Une sortie possible
| Ligne | Ce qu’elle peut montrer |
|---|---|
| 1 à 4 | Une étiquette, l’étiquette attendue, et juste ou faux |
| Exactitude | Par exemple 3 sur 4 (75 pour cent), ou 4 sur 4 |
| Étiquettes inconnues | Combien de réponses n’ont pas pu devenir une étiquette autorisée |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une erreur fréquente
Attention
Beaucoup pensent que 100 pour cent sur quelques cas prouve que l’étiqueteur est bon. Une poignée de cas prouve peu. Prenez beaucoup de cas, ajoutez des cas délicats et lisez les réponses fausses.