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

Le schéma de la base dans la consigne

Après cette leçon: Je peux décrire le schéma d’une base assez brièvement pour qu’un modèle en tire du SQL.

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

Ce que le texte vers SQL doit savoir

Le texte vers SQL, c’est un modèle de langage qui transforme une question en mots simples en requête SQL. Le modèle n’a jamais vu votre base : il devine les tables que vous ne décrivez pas.

Le module 4 enseigne le SQL et le module 63 demande une forme fixe à un modèle. Cette leçon décide de ce qu’il faut dire au modèle sur vos tables.

À la fin de cette leçon

Remarque

Je peux décrire le schéma d’une base assez brièvement pour qu’un modèle en tire du SQL.

Mots clés

MotCe que ça veut direExemple
Texte vers SQLun modèle qui change une question en requête
Schémales tables et les colonnes d’une base
Clé étrangèreune colonne qui désigne une ligne d’une autre tableprets.livre_id
Jointurel’appariement des lignes de deux tables sur une colonne
Noteune ligne qui dit ce que signifient les valeurs d’une colonne

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

Le minimum : tables, colonnes et jointures

Pour écrire une requête, le modèle a besoin de trois choses. Il lui faut le nom des tables, les colonnes de chaque table et la façon dont les tables se joignent.

Sans les jointures, il devine. Joindre prets.id à livres.id, par exemple, tourne sans erreur et donne les mauvais livres.

Exemple détaillé : le schéma de la médiathèque

TableColonnesSe joint à
livresid, titre, anneeRien
membresid, nomRien
pretsid, livre_id, membre_id, mois, rendulivre_id à livres.id, membre_id à membres.id

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

Certaines colonnes demandent une note

Le nom d’une colonne ne dit pas toujours ce que veulent dire ses valeurs. Dans la médiathèque, rendu vaut 1 quand le livre est revenu et 0 tant qu’il est dehors.

Un modèle qui ne lit que le nom pourrait tester rendu = « non » ou rendu IS NULL. Une note courte par colonne floue évite cette supposition.

Exemple détaillé : des noms qui demandent une note

ColonneUne supposition sans noteLa note
prets.rendurendu = « non »1 si rendu, 0 si encore dehors
prets.moisUne date comme 2026-03-01De 1 à 12, cette année
livres.anneeAnnée de l’achatAnnée de la parution

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

Une erreur courante

Attention

Beaucoup pensent qu’un modèle connaît déjà leur base. Il ne l’a jamais vue. Envoyez les tables, les jointures et les notes avec chaque question, car chaque requête repart de zéro.

Une description courte plutôt que tout le CREATE

Vous pourriez coller chaque instruction CREATE TABLE. Une ligne courte par table, puis les jointures et les notes, dit la même chose sous une forme facile à lire.

Dans une base de quarante tables, n’envoyez que les tables utiles à la question. Moins de mots coûtent moins cher et laissent moins de place aux erreurs de lecture.

É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 du schéma, 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 tables = db.prepare(\"SELECT name, sql FROM sqlite_master WHERE type = ? ORDER BY name\").all(\"table\");' 'function court(t) {' '  const cols = db.prepare(\"SELECT name, type FROM pragma_table_info(?)\").all(t.name)' '    .map(function (c) { return c.name + \" \" + c.type; });' '  return t.name + \"(\" + cols.join(\", \") + \")\";' '}' 'const liens = [];' 'tables.forEach(function (t) {' '  db.prepare(\"SELECT * FROM pragma_foreign_key_list(?)\").all(t.name).forEach(function (k) {' '    liens.push(t.name + \".\" + k.from + \" -> \" + k.table + \".\" + k.to);' '  });' '});' > schema.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 du schéma, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const notes = [\"prets.rendu vaut 1 quand le livre est rendu, 0 tant qu’il est dehors\", \"prets.mois va de 1 à 12, cette année\"];' 'const schema = tables.map(court).concat(liens, notes).join(\"\n\");' 'const complet = tables.map(function (t) { return t.sql; }).join(\"\n\");' 'console.log(schema);' 'console.log(\"texte CREATE complet : \" + complet.length + \" caractères, version courte avec notes : \" + schema.length);' >> schema.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 du schéma, partie 3

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const question = \"Combien de prêts ont été faits au mois 3 ?\";' '  const systeme = \"Répondez par une seule requête SELECT pour SQLite, et rien d’autre.\";' '  const echantillon = \"SELECT COUNT(*) FROM prets WHERE mois = 3;\";' '  const reponse = await demander([{ role: \"system\", content: systeme },' '    { role: \"user\", content: schema + \"\nQuestion : \" + question }], echantillon, 120);' '  console.log(\"le modèle a écrit : \" + sqlDe(reponse.texte));' '  console.log(\"pas encore vérifiée : les leçons 2 à 5 la vérifient\");' '}' 'main();' >> schema.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.

Décrire le schéma et demander

Commande
docker exec -w /home/node/project agent node --experimental-sqlite --no-warnings schema.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
livres(id INTEGER, titre TEXT, annee INTEGER)Une ligne courte par table
prets.livre_id -> livres.idUne ligne par jointure, lue dans les clés étrangères
prets.rendu vaut 1 quand le livre est rendu, 0 tant qu’il est dehorsUne note écrite à la main
texte CREATE complet : 282 caractères, version courte avec notes : 323La taille des deux formes
le modèle a écrit : SELECT COUNT(*) FROM prets WHERE mois = 3;La requête, ou 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.