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

Limiter ce que peut faire un outil LLM

Après cette leçon: Je peux vérifier chaque demande d’outil contre une politique de liste autorisée avant que rien ne s’exécute.

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

Le modèle demande un fichier

Limiter les outils d’un modèle, c’est faire décider votre code, et non le modèle, de ce que chaque outil peut faire. Cela compte, car la demande d’un modèle est du texte, et un texte peut être faux, trompé ou inventé.

Un assistant de notes a un outil qui lit une note par son nom. Une réponse demande la note « ../prive ». L’outil essaierait volontiers. Une politique l’arrête avant qu’il parte.

À la fin de cette leçon

Remarque

Je peux vérifier chaque demande d’outil contre une politique de liste autorisée avant que rien ne s’exécute.

Mots clés

MotCe que ça veut dire
Liste autoriséeles seuls outils et valeurs permis
Politiquedes données qui disent ce que chaque outil peut recevoir
Contrôle d’argumentun test des entrées d’un outil avant qu’il s’exécute
Moindre privilègene donner à un outil que le pouvoir dont il a besoin
Délai maximalune limite à la durée d’un appel

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

Une liste autorisée dit oui, jamais non

Une liste d’interdits nomme les mauvaises choses et laisse passer le reste. Elle en oublie toujours une. Une liste autorisée nomme les bonnes choses et refuse le reste.

Écrivez une politique en données : chaque outil, chaque paramètre, son type et ses limites. Une fonction lit la politique et juge chaque demande. Le modèle n’exécute jamais rien lui-même.

Exemple : une politique et quatre demandes

DemandeLa politique ditDécision
lire_note, nom menunom doit être courses, menu ou horaireAutorisée
lire_note, nom ../privenom doit être courses, menu ou horaireRefusée : non autorisé
lancer_commande, un texteCet outil n’existe pasRefusée : outil inconnu
additionner, b 99999b vaut au plus 1000Refusée : trop grand

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

Pas de commande bâtie sur un texte

Certains outils tentent : lancer une commande, évaluer une expression, écrire un fichier. N’en construisez aucun à partir d’un texte écrit par un modèle. Un refus vaut mieux qu’un filtre astucieux.

Si une fonction doit faire tourner du vrai code, faites-le dans un bac à sable séparé. Pas de secrets, et une limite de temps. Ce labo n’en a pas, donc la leçon ne fait que refuser.

Écrire l’aide 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\";' '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 || 200 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"statut \" + res.status);' '    return (await res.json()).choices[0].message.content;' > 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’aide du modèle, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  } catch (erreur) {' '    console.log(\"Échantillon enregistré : aucun modèle n’a répondu (\" + erreur.message + \").\");' '    const liste = [].concat(echantillon);' '    const tour = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' '    return liste[Math.min(tour, liste.length - 1)];' '  }' '}' '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 politique, partie 1

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' '' '// Des notes inventées, et une politique : chaque outil, ses arguments et leurs limites.' 'const notes = { courses: \"acheter de la farine\", menu: \"pain, gâteau\", horaire: \"ouvert à 8 h\" };' 'const politique = {' '  lire_note: { nom: { type: \"string\", autorises: Object.keys(notes) } },' '  additionner: { a: { type: \"number\", max: 1000 }, b: { type: \"number\", max: 1000 } },' '};' > politique.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 politique, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function verifier(demande) {' '  const regle = politique[demande.outil];' '  if (regle === undefined) return \"refusé : outil inconnu\";' '  const parametres = demande.parametres || {};' '  for (const cle of Object.keys(parametres)) {' '    if (regle[cle] === undefined) return \"refusé : argument inattendu \" + cle;' '  }' '  for (const cle of Object.keys(regle)) {' '    const modele = regle[cle];' '    const valeur = parametres[cle];' '    if (typeof valeur === modele.type === false) return \"refusé : \" + cle + \" incorrect\";' '    if (modele.autorises && modele.autorises.includes(valeur) === false) return \"refusé : \" + cle + \" non autorisé\";' '    if (typeof modele.max === \"number\" && valeur > modele.max) return \"refusé : \" + cle + \" trop grand\";' '  }' '  return \"ok\";' '}' >> politique.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 politique, partie 3

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function executer(demande) {' '  if (verifier(demande) === \"ok\") {' '    return demande.outil === \"lire_note\" ? notes[demande.parametres.nom] : demande.parametres.a + demande.parametres.b;' '  }' '  return verifier(demande);' '}' 'const scenario = [' '  { outil: \"lire_note\", parametres: { nom: \"menu\" } },' '  { outil: \"lire_note\", parametres: { nom: \"../prive\" } },' '  { outil: \"lancer_commande\", parametres: { texte: \"lister le dossier\" } },' '  { outil: \"additionner\", parametres: { a: 5, b: 99999 } },' '  { outil: \"additionner\", parametres: { a: 2, b: 3, c: 4 } },' '];' 'for (const demande of scenario) console.log(demande.outil + \" -> \" + executer(demande));' >> politique.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 politique, partie 4

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function extraireJson(texte) {' '  const debut = texte.indexOf(\"{\");' '  const fin = texte.lastIndexOf(\"}\");' '  try { return JSON.parse(texte.slice(debut, fin + 1)); } catch (erreur) { return null; }' '}' 'async function main() {' '  const question = [{ role: \"user\", content: \"Réponds uniquement par un objet JSON avec les clés outil et parametres, pour lire la note nommée horaire. Outils : lire_note(nom), additionner(a, b).\" }];' '  const echantillon = JSON.stringify({ outil: \"lire_note\", parametres: { nom: \"horaire\" } });' '  const demande = extraireJson(await demander(question, echantillon, 80));' '  console.log(\"Demande du modèle : \" + JSON.stringify(demande));' '  console.log(\"Résultat : \" + (demande === null ? \"refusé : pas du JSON\" : executer(demande)));' '}' 'main();' >> politique.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 script de politique

Commande
docker exec -w /home/node/project agent node politique.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.

Une sortie possible

LigneCe qu’elle montre
lire_note -> pain, gâteauLa première demande a passé tous les contrôles
lire_note -> refusé : nom non autoriséL’astuce de chemin a échoué devant la liste autorisée
lancer_commande -> refusé : outil inconnuL’outil n’est pas dans la politique
Demande du modèle, puis RésultatChange à chaque exécution. Une demande d’outil du modèle passe par le même contrôle

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

Limitez le temps et le pouvoir

Un délai maximal empêche un outil lent de retenir une requête pour toujours. L’aide que vous avez écrite abandonne déjà le modèle après 30 secondes.

Appliquez aussi le moindre privilège. Un outil qui lit des notes ne doit pas pouvoir en écrire, et un outil qui écrit ne doit atteindre que son propre dossier.

Une erreur fréquente

Attention

Beaucoup pensent que, si on a dit les règles au modèle, l’outil n’a pas besoin de vérifier. Le modèle peut se tromper, être trompé ou inventer un outil. Vérifiez toujours dans le code qui lance l’outil, car c’est la seule partie qui fait la même chose à chaque fois.

À 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.