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

Un jeu d’évaluation pour le texte vers SQL

Après cette leçon: Je peux noter des requêtes candidates sur un jeu de questions aux réponses connues.

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

Comment tester une fonction texte vers SQL

Un jeu d’évaluation pour le texte vers SQL est une liste de questions aux réponses connues, relancée à chaque changement de consigne ou de modèle. Il dit si un changement a amélioré ou abîmé les choses.

Les modules 68 et 85 notent des réponses en mots. Cette leçon note du SQL par les lignes qu’il renvoie.

À la fin de cette leçon

Remarque

Je peux noter des requêtes candidates sur un jeu de questions aux réponses connues.

Mots clés

MotCe que ça veut dire
Jeu d’évaluationdes questions aux réponses connues, relancées à chaque changement
Requête de référenceune requête vérifiée à la main qui donne les bonnes lignes
Concordance des résultatsles mêmes lignes que la requête de référence
Régressionune question qui réussissait avant et échoue maintenant
Barrièreune règle qui bloque un changement

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

Chaque cas a une question et une référence

Un cas contient une question, une requête de référence et le fait que l’ordre compte ou non. Écrivez la référence vous-même et vérifiez ses lignes à la main sur le jeu d’essai.

Lancez la référence pour obtenir les lignes attendues. Le jeu continue ainsi de marcher quand les données grossissent, tant que les références restent justes.

Exemple détaillé : cinq cas pour la médiathèque

CasQuestionLignes de référence
1Prêts faits au mois 34
2Membres différents au mois 33
3Livres encore dehors5
4Titres empruntés par le membre 2Carte de la pluie, Moteurs tranquilles, Sept Bouilloires
5Livres jamais empruntésAu nord de midi

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

Noter par le résultat, pas par le texte

COUNT(id) et COUNT(*) donnent ici le même nombre, et une jointure peut s’écrire en sous-requête. Deux textes différents peuvent être justes tous les deux.

Lancez donc chaque candidate et comparez ses lignes aux lignes de référence. Comparer le texte exact déclare fausses des réponses justes, comme le montre le Run.

Exemple détaillé : texte et résultat se contredisent

CandidateMême texte que la référenceMêmes lignes que la référence
SELECT COUNT(id) FROM prets WHERE mois = 3NonOui
Une jointure écrite IN (SELECT livre_id ...)NonOui
SELECT COUNT(*) FROM pretsNonNon

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

Une régression se cache sous un même score

Une nouvelle consigne répare la question 2 et casse la question 3. Les deux versions réussissent quatre questions sur cinq : le score n’a pas bougé.

Comparez cas par cas. Une question qui réussissait et échoue maintenant est une régression, et la barrière bloque le changement jusqu’à sa correction.

Une erreur courante

Attention

Beaucoup pensent qu’un taux de réussite égal veut dire que rien n’a empiré. Une question peut être réparée pendant qu’une autre casse. Comparez chaque cas avec le dernier passage, et bloquez tout changement qui perd une réussite.

É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;' '}' '// Une réponse peut entourer la requête d’un bloc délimité : on garde l’intérieur.' 'function sqlDe(texte) {' '  const morceaux = texte.split(String.fromCharCode(96).repeat(3));' '  const dedans = (morceaux.length > 2 ? morceaux[1] : texte).trim();' '  return dedans.toLowerCase().startsWith(\"sql\") ? dedans.slice(3).trim() : dedans;' '}' > 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, sqlDe };' >> 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 base de la médiathèque, partie 1

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { DatabaseSync } = require(\"node:sqlite\");' '// Une médiathèque inventée : six livres, quatre membres, neuf prêts.' 'const LIVRES = [[1, \"Le Phare des oranges\", 2019], [2, \"Port de verre\", 2021], [3, \"Carte de la pluie\", 2015],' '  [4, \"Moteurs tranquilles\", 2023], [5, \"Sept Bouilloires\", 2018], [6, \"Au nord de midi\", 2022]];' 'const MEMBRES = [[1, \"Amina\"], [2, \"Bruno\"], [3, \"Chloé\"], [4, \"Driss\"]];' '// id, livre_id, membre_id, mois, rendu (1 rendu, 0 encore dehors)' 'const PRETS = [[1, 1, 1, 3, 1], [2, 2, 1, 3, 1], [3, 3, 2, 3, 0], [4, 1, 3, 3, 1], [5, 1, 1, 4, 0],' '  [6, 4, 2, 4, 0], [7, 2, 3, 4, 1], [8, 5, 2, 5, 0], [9, 2, 4, 5, 0]];' > mediatheque.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 base de la médiathèque, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function remplir(db, table, lignes) {' '  const marques = lignes[0].map(function () { return \"?\"; }).join(\", \");' '  const inserer = db.prepare(\"INSERT INTO \" + table + \" VALUES (\" + marques + \")\");' '  lignes.forEach(function (ligne) { inserer.run(...ligne); });' '}' 'function ouvrir(fichier) {' '  const db = new DatabaseSync(fichier || \":memory:\");' '  db.exec(\"CREATE TABLE livres (id INTEGER PRIMARY KEY, titre TEXT, annee INTEGER)\");' '  db.exec(\"CREATE TABLE membres (id INTEGER PRIMARY KEY, nom TEXT)\");' '  db.exec(\"CREATE TABLE prets (id INTEGER PRIMARY KEY, livre_id INTEGER REFERENCES livres(id), \"' '    + \"membre_id INTEGER REFERENCES membres(id), mois INTEGER, rendu INTEGER)\");' '  remplir(db, \"livres\", LIVRES);' '  remplir(db, \"membres\", MEMBRES);' '  remplir(db, \"prets\", PRETS);' '  return db;' '}' 'module.exports = { ouvrir };' >> mediatheque.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 d’évaluation, partie 1

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander, sqlDe } = require(\"./model\");' 'const { ouvrir } = require(\"./mediatheque\");' 'const db = ouvrir();' 'const cas = [' '  { ref: \"SELECT COUNT(*) FROM prets WHERE mois = 3\" },' '  { ref: \"SELECT COUNT(DISTINCT membre_id) FROM prets WHERE mois = 3\" },' '  { ref: \"SELECT COUNT(*) FROM prets WHERE rendu = 0\" },' '  { ref: \"SELECT l.titre FROM prets p JOIN livres l ON p.livre_id = l.id WHERE p.membre_id = 2\" },' '  { ref: \"SELECT titre FROM livres WHERE id NOT IN (SELECT livre_id FROM prets)\" },' '];' > evaluer.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 d’évaluation, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const A = [\"SELECT COUNT(id) FROM prets WHERE mois = 3\",' '  \"SELECT COUNT(membre_id) FROM prets WHERE mois = 3\", cas[2].ref,' '  \"SELECT l.titre FROM livres l JOIN prets p ON p.livre_id = l.id WHERE p.membre_id = 2\",' '  \"SELECT l.titre FROM livres l LEFT JOIN prets p ON p.livre_id = l.id WHERE p.id IS NULL\"];' 'const B = [cas[0].ref, cas[1].ref, \"SELECT COUNT(*) FROM prets\",' '  \"SELECT titre FROM livres WHERE id IN (SELECT livre_id FROM prets WHERE membre_id = 2)\", cas[4].ref];' 'function lignes(sql) {' '  try { return db.prepare(sql).all().map(function (r) { return JSON.stringify(Object.values(r)); }).sort().join(\"|\"); }' '  catch (erreur) { return null; }' '}' >> evaluer.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 d’évaluation, partie 3

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function noter(sql, i) {' '  const obtenu = lignes(sql);' '  return obtenu === null ? \"erreur\" : obtenu === lignes(cas[i].ref) ? \"réussi\" : \"échoué\";' '}' 'function taux(liste, test) {' '  return Math.floor(100 * liste.filter(test).length / liste.length) + \" pour cent\";' '}' 'const a = A.map(noter);' 'const b = B.map(noter);' 'const meme = function (sql, i) { return sql === cas[i].ref; };' '// Une régression : réussie en A, pas réussie en B.' 'const perdues = [];' 'a.forEach(function (v, i) { if (v === \"réussi\" && b[i] === \"échoué\" || v === \"réussi\" && b[i] === \"erreur\") perdues.push(i + 1); });' >> evaluer.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 d’évaluation, partie 4

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  a.forEach(function (v, i) { console.log(\"question \" + (i + 1) + \" : A \" + v + \", B \" + b[i]); });' '  const reussi = function (v) { return v === \"réussi\"; };' '  console.log(\"par le résultat : A \" + taux(a, reussi) + \", B \" + taux(b, reussi));' '  console.log(\"par le texte exact : A \" + taux(A, meme) + \", B \" + taux(B, meme));' '  console.log(\"régressions dans B : \" + (perdues.length ? perdues.join(\", \") : \"aucune\"));' '  console.log(\"barrière : \" + (perdues.length ? \"bloquer, une question réussie échoue maintenant\" : \"livrer\"));' '  await direct();' '}' >> evaluer.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 d’évaluation, partie 5

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function direct() {' '  const q = \"prets(id, livre_id, membre_id, mois, rendu)\nQuestion : Combien de membres différents ont emprunté un livre au mois 3 ?\";' '  const echantillon = \"SELECT COUNT(DISTINCT membre_id) FROM prets WHERE mois = 3;\";' '  const reponse = await demander([{ role: \"system\", content: \"Répondez par une seule requête SELECT pour SQLite, et rien d’autre.\" },' '    { role: \"user\", content: q }], echantillon, 120);' '  const sql = sqlDe(reponse.texte);' '  console.log(\"le modèle a écrit : \" + sql);' '  console.log(\"  notée à part des totaux : \" + noter(sql, 1));' '}' 'main();' >> evaluer.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.

Noter deux versions sur cinq questions

Commande
docker exec -w /home/node/project agent node --experimental-sqlite --no-warnings evaluer.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
question 2 : A échoué, B réussiLa nouvelle consigne a réparé la question 2
question 3 : A réussi, B échouéLa nouvelle consigne a cassé la question 3
par le résultat : A 80 pour cent, B 80 pour centLe score n’a pas bougé
par le texte exact : A 20 pour cent, B 60 pour centLe texte déclare fausses des réponses justes
régressions dans B : 3La question perdue
barrière : bloquer, une question réussie échoue maintenantLa décision

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.