Vérifier un juge avant de lui faire confiance
Un juge est un modèle qui note les réponses d’un autre modèle. Il coûte peu, donc les équipes s’en servent beaucoup. Mais un juge peut pencher d’un côté sans que personne le voie.
Le module sur l’évaluation et les tests montre un juge et son accord avec des personnes. Cette leçon va plus loin, avec trois tests calculés en nombres.
À la fin de cette leçon
Remarque
Je peux découvrir comment un correcteur est biaisé avant de m’y fier.
Mots clés
| Mot | Ce que ça veut dire |
|---|---|
| Juge | un modèle qui note des réponses |
| Kappa | l’accord avec des personnes, au-delà de ce que donne le hasard |
| Biais de position | une préférence pour une place plutôt que pour une réponse |
| Biais de longueur | une préférence pour la réponse la plus longue |
| Jeu d’étalonnage | des réponses qu’une personne a notées pour éprouver un juge |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
L’accord ne suffit pas : le hasard aide
Un juge est d’accord avec une personne sur 90 % des réponses. Cela semble bon. Mais si presque toutes les réponses réussissent, un juge qui dit toujours « réussi » obtient aussi un score élevé.
Le kappa retire la part du hasard. Il vaut 1 pour un accord parfait et 0 quand le juge n’est pas meilleur que le hasard.
Exemple détaillé : vingt réponses notées
| Mesure | Valeur | Comment on la calcule |
|---|---|---|
| Éléments | 20 | On les compte |
| Juge et personne d’accord | 18 | 90 % d’accord |
| Accords dus au hasard, fois 400 | 296 | réussis fois réussis, plus échoués fois échoués |
| Kappa | 0,62 | (360 moins 296) divisé par (400 moins 296) |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une erreur courante
Attention
Beaucoup pensent qu’un fort taux d’accord prouve qu’un juge est fiable. Ce n’est pas vrai quand une étiquette est bien plus fréquente. Calculez le kappa et prenez un jeu d’étalonnage qui a assez de chaque étiquette.
Échangez l’ordre pour trouver le biais de position
Montrez deux réponses au juge, A puis B, et notez son choix. Montrez-les ensuite dans l’ordre B puis A. Un juge juste choisit la même réponse les deux fois.
Si le choix change, le juge a suivi la place. Comptez les changements. S’ils atteignent un quart des cas ou plus, signalez le juge.
Comptez quand la réponse la plus longue gagne
Certains juges aiment les réponses longues. Pour le tester, écartez les paires de même longueur. Parmi les autres, comptez les fois où le juge prend la plus longue.
Environ la moitié est normal. Trois sur quatre ou plus montrent que la longueur guide la note.
É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 les tests du juge, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'const H = \"rrrrrerrrrrerrrerrre\";' 'const J = \"rrrrrrrrrrrerrrrrrre\";' 'const lignes = [' ' \"1 40 55 B B\", \"2 62 30 A A\", \"3 48 70 B A\", \"4 33 51 A B\",' ' \"5 80 45 A B\", \"6 52 52 A A\", \"7 29 66 B B\", \"8 71 40 A B\",' ' \"9 44 90 B B\", \"10 58 36 A A\", \"11 35 62 A B\", \"12 77 41 A A\",' '].map(function (l) {' ' const p = l.split(\" \");' ' return { a: Number(p[1]), b: Number(p[2]), un: p[3], deux: p[4] };' '});' > juge.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 les tests du juge, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function compter(texte, c) { return texte.split(c).length - 1; }' 'const n = H.length;' 'let accord = 0;' 'for (let i = 0; i < n; i++) { if (H[i] === J[i]) accord++; }' 'const hasard = compter(J, \"r\") * compter(H, \"r\") + compter(J, \"e\") * compter(H, \"e\");' 'const kappa = (accord * n - hasard) / (n * n - hasard);' >> juge.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 les tests du juge, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'let premier = 0;' 'let second = 0;' 'let plus_long = 0;' 'let inegales = 0;' 'lignes.forEach(function (l) {' ' if (l.un === \"A\" && l.deux === \"B\") premier++;' ' if (l.un === \"B\" && l.deux === \"A\") second++;' ' if (l.a === l.b) return;' ' inegales++;' ' if ((l.un === \"A\") === (l.a > l.b)) plus_long++;' '});' >> juge.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 les tests du juge, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' console.log(\"accord : \" + (accord * 100 / n) + \" pour cent, kappa : \" + kappa.toFixed(2));' ' console.log(\"test d’échange : \" + (premier + second) + \" sur \" + lignes.length + \" ont changé (première place \" + premier + \", seconde \" + second + \")\");' ' console.log(\"la plus longue gagne : \" + plus_long + \" sur \" + inegales + \" (\" + Math.floor(plus_long * 100 / inegales) + \" pour cent)\");' >> juge.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 les tests du juge, partie 5
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' const q = \"Notez cette réponse à la question Où est la bibliothèque ? par réussi ou échoué, un seul mot : Demandez à quelqu’un.\";' ' const reponse = await demander([{ role: \"user\", content: q }], \"échoué\", 5);' ' console.log(\"note en direct : \" + reponse.texte);' '}' 'main();' >> juge.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 tests du juge
docker exec -w /home/node/project agent node juge.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 que les tests affichent
| Ligne | Ce qu’elle montre |
|---|---|
| accord : 90 pour cent, kappa : 0.62 | Un fort accord, plus faible une fois le hasard retiré |
| test d’échange : 5 sur 12 ont changé | Cinq choix ont suivi la place |
| la plus longue gagne : 9 sur 11 | La plus longue a gagné 81 % du temps |
| note en direct : ... | Une vraie note du labo. Un échantillon enregistré si aucun modèle ne répond |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.