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

Une piste d’audit infalsifiable

Après cette leçon: Je peux tenir un journal qui montre s’il a été modifié.

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

Comment tenir un journal qui montre les modifications

Une piste d’audit est un journal de qui a changé quoi et quand. Un journal que tout le monde peut modifier n’est pas une preuve, car personne ne peut savoir s’il a été changé.

Une chaîne d’empreintes fait apparaître une modification. Enregistrer une décision ne suffit pas. Cette leçon fait que l’enregistrement montre s’il a été changé.

À la fin de cette leçon

Remarque

Je peux tenir un journal qui montre s’il a été modifié.

Mots clés

MotCe que ça veut direExemple
Ajout seulon ajoute des entrées et on ne modifie jamais les anciennes
Empreinteun court code qui résume un texte1a47e90b
Chaînedes entrées qui gardent chacune l’empreinte de la précédente
Falsifierchanger un enregistrement sans en avoir le droit
Ancrela dernière empreinte, gardée ailleurs

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

Une empreinte résume un texte

Une empreinte transforme n’importe quel texte en un court code. Le même texte donne toujours le même code. Changez une seule lettre et le code change tout entier.

L’empreinte de cette leçon est petite et faite pour apprendre. Elle n’est pas sûre. Un vrai journal emploie une empreinte forte tirée d’une bibliothèque, et l’idée est la même.

Exemple détaillé : trois empreintes

TexteEmpreinte
(rien)811c9dc5
ae40c292c
abc1a47e90b

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

Une chaîne relie chaque entrée à la précédente

Chaque entrée garde son texte, l’empreinte de l’entrée d’avant et sa propre empreinte. Sa propre empreinte est faite de l’empreinte précédente, d’une barre et de son texte.

Modifiez l’entrée 2 : sa propre empreinte ne correspond plus. Chaque entrée suivante garde l’ancienne empreinte, donc les maillons cassent à partir de là.

Exemple détaillé : cinq entrées

EntréeTexteEmpreinte précédenteSa propre empreinte
0modèle figé sur assistant-v300000000c62bba59
1canari à 5 pour centc62bba59f9964152
2canari à 20 pour centf9964152f3c42d5d
3mise en ligne pour tousf3c42d5d518ac8cd
4ancienne version retirée518ac8cde7fac6c7

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

Une erreur courante

Attention

Beaucoup pensent qu’une chaîne d’empreintes empêche de changer le journal. Ce n’est pas le cas : elle montre seulement un changement. Qui peut écrire tout le fichier peut refaire toutes les empreintes. Gardez la dernière empreinte, l’ancre, là où cette personne ne peut pas aller, et comparez.

É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;' '}' > 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 };' >> 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 script de la piste, partie 1

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'const DEBUT = \"00000000\";' 'function empreinte(texte) {' '  let x = 2166136261;' '  for (let i = 0; i < texte.length; i++) {' '    x = x ^ texte.charCodeAt(i);' '    x = Math.imul(x, 16777619) >>> 0;' '  }' '  return (\"00000000\" + x.toString(16)).slice(-8);' '}' > piste.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 de la piste, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function ajouter(chaine, texte) {' '  const prec = chaine.length > 0 ? chaine[chaine.length - 1].empreinte : DEBUT;' '  return chaine.concat([{ texte: texte, prec: prec, empreinte: empreinte(prec + \"|\" + texte) }]);' '}' 'function premierCasse(chaine) {' '  let prec = DEBUT;' '  for (let i = 0; i < chaine.length; i++) {' '    const e = chaine[i];' '    if (e.prec === prec && e.empreinte === empreinte(e.prec + \"|\" + e.texte)) prec = e.empreinte;' '    else return i;' '  }' '  return -1;' '}' >> piste.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 de la piste, partie 3

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const notes = [\"modèle figé sur assistant-v3\", \"canari à 5 pour cent\", \"canari à 20 pour cent\",' '  \"mise en ligne pour tous\", \"ancienne version retirée\"];' 'let chaine = [];' 'notes.forEach(function (t) { chaine = ajouter(chaine, t); });' 'const ancre = chaine[4].empreinte;' 'const falsifie = chaine.map(function (e) { return { texte: e.texte, prec: e.prec, empreinte: e.empreinte }; });' 'falsifie[2].texte = \"canari à 90 pour cent\";' 'let refaite = [];' 'falsifie.forEach(function (e) { refaite = ajouter(refaite, e.texte); });' >> piste.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 de la piste, partie 4

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  console.log(\"empreinte de abc : \" + empreinte(\"abc\"));' '  console.log(\"premier maillon cassé dans le vrai journal : \" + premierCasse(chaine));' '  console.log(\"premier maillon cassé après une modification : \" + premierCasse(falsifie));' '  console.log(\"le journal refait est cohérent : \" + (premierCasse(refaite) === -1));' '  console.log(\"le journal refait correspond à l’ancre : \" + (refaite[4].empreinte === ancre));' '  const q = \"En une phrase courte, pourquoi une entrée modifiée se repère-t-elle facilement dans une chaîne d’empreintes ?\";' '  const echantillon = \"Chaque entrée garde l’empreinte de la précédente : une seule modification casse tous les maillons suivants.\";' '  const reponse = await demander([{ role: \"user\", content: q }], echantillon, 60);' '  console.log(\"le modèle dit : \" + reponse.texte);' '}' 'main();' >> piste.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 la piste d’audit

Commande
docker exec -w /home/node/project agent node piste.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
empreinte de abc : 1a47e90bLa même empreinte à chaque fois
premier maillon cassé dans le vrai journal : -1Aucun maillon cassé
premier maillon cassé après une modification : 2La modification est trouvée à l’entrée 2
le journal refait est cohérent : trueUne reconstruction complète passe le contrôle des maillons
le journal refait correspond à l’ancre : falseL’ancre montre quand même le changement
le modèle dit : ...Une phrase du labo. 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.