Retirer les données et ce que cela casse
Caviarder, c’est retirer les données personnelles d’un message avant qu’il aille ailleurs. Une application d’assistance peut caviarder un numéro de téléphone avant de demander une réponse à un modèle.
Le piège est que la réponse peut avoir besoin de ce numéro. La façon de caviarder décide si vous pourrez le remettre.
À la fin de cette leçon
Remarque
Je peux retirer des données personnelles et dire ce que cela casse.
Mots clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Caviarder | retirer les données personnelles d’un texte | |
| Masque | le remplacement d’une valeur par sa sorte | [COURRIEL] |
| Jeton | un remplaçant qu’on peut échanger en retour | [COURRIEL_1] |
| Table | la liste privée qui dit quel jeton est quelle valeur | |
| Restaurer | remettre les vraies valeurs |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Il y a trois façons de caviarder
Un masque remplace une valeur par sa sorte, comme [COURRIEL]. Deux courriels différents deviennent tous deux [COURRIEL] : on ne peut ni les distinguer ni les remettre.
Un jeton est numéroté, comme [COURRIEL_1]. Vous gardez une table privée des jetons et des valeurs, et vous ne l’envoyez jamais. Détruire une valeur, c’est la perdre pour de bon, sans table.
Exemple détaillé : un courriel, trois façons
| Méthode | Ce que voit le modèle | La réponse peut-elle le nommer ? | Peut-on le restaurer ? |
|---|---|---|---|
| Masque | [COURRIEL] | Non | Non |
| Jeton | [COURRIEL_1] | Oui, sous forme de jeton | Oui, avec votre table |
| Destruction | Rien | Non | Non, par conception |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Caviarder peut casser la réponse
Si le modèle ne voit jamais le courriel, il ne peut pas l’écrire. Une réponse qui dit « nous écrirons à votre adresse » convient. Une réponse qui doit répéter l’adresse a besoin d’un jeton.
Les jetons apportent un nouveau risque. Le modèle peut en perdre un ou le changer. Ne restaurez que les jetons qui reviennent, et vérifiez qu’aucun ne reste.
Une erreur courante
Attention
Beaucoup pensent que les jetons rendent les données anonymes. Ce n’est pas vrai. Vous gardez la table, donc vous pouvez retrouver les personnes. En mots simples du RGPD, ce sont des données pseudonymisées, qui restent des données personnelles. C’est un résumé, pas un avis juridique.
É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 le caviardeur, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'const texte = \"Merci d’écrire à [email protected] ou d’appeler le 0600000123. Cordialement, Léa.\";' 'const comptes = {};' 'const table = {};' 'function nettoyer(mot) {' ' let m = mot;' ' while (m.length > 0 && \".,;:?()\".includes(m[m.length - 1])) m = m.slice(0, -1);' ' return m;' '}' > caviarder.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 caviardeur, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function sorteDe(m) {' ' const arobase = m.indexOf(\"@\");' ' if (arobase > 0 && m.indexOf(\".\", arobase) > arobase + 1) return \"COURRIEL\";' ' if (m.length === 10 && (m.startsWith(\"06\") || m.startsWith(\"07\")) && Number.isInteger(Number(m))) return \"TELEPHONE\";' ' return \"\";' '}' 'function masquer(t) {' ' return t.split(\" \").map(function (mot) {' ' const m = nettoyer(mot);' ' return sorteDe(m).length === 0 ? mot : \"[\" + sorteDe(m) + \"]\" + mot.slice(m.length);' ' }).join(\" \");' '}' >> caviarder.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 caviardeur, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function jetonner(t) {' ' const connus = {};' ' return t.split(\" \").map(function (mot) {' ' const m = nettoyer(mot);' ' const sorte = sorteDe(m);' ' if (sorte.length === 0) return mot;' ' if (connus[m] === undefined) {' ' comptes[sorte] = (comptes[sorte] || 0) + 1;' ' connus[m] = \"[\" + sorte + \"_\" + comptes[sorte] + \"]\";' ' table[connus[m]] = m;' ' }' ' return connus[m] + mot.slice(m.length);' ' }).join(\" \");' '}' >> caviarder.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 caviardeur, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function restaurer(t) {' ' let sortie = t;' ' Object.keys(table).forEach(function (cle) { sortie = sortie.split(cle).join(table[cle]); });' ' return sortie;' '}' 'async function main() {' ' const sur = jetonner(texte);' ' console.log(\"masqué : \" + masquer(texte));' ' console.log(\"avec jetons : \" + sur);' ' console.log(\"table gardée ici : \" + JSON.stringify(table));' ' const q = \"Écrivez une courte réponse à ce message. Recopiez chaque jeton entre crochets exactement. \" + sur;' ' const echantillon = \"Merci. Nous écrirons à [COURRIEL_1] et appellerons le [TELEPHONE_1] aujourd’hui.\";' ' const r = await demander([{ role: \"user\", content: q }], echantillon, 80);' ' console.log(\"réponse : \" + r.texte);' ' console.log(\"restaurée : \" + restaurer(r.texte));' '}' 'main();' >> caviarder.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 le caviardeur
docker exec -w /home/node/project agent node caviarder.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 le Run affiche
| Ligne | Ce qu’elle montre |
|---|---|
| masqué : ... [COURRIEL] ... [TELEPHONE] ... | Seulement les sortes : rien ne peut être remis |
| avec jetons : ... [COURRIEL_1] ... [TELEPHONE_1] ... | Des remplaçants numérotés |
| table gardée ici : {...} | La liste privée, jamais envoyée |
| réponse : ... | Une réponse avec des jetons. Enregistrée quand aucun modèle ne répond |
| restaurée : ... | Les jetons remplacés par les valeurs inventées |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.