Choisir ce que le modèle voit
L’ingénierie du contexte consiste à décider ce qui entre dans la fenêtre du modèle à chaque étape d’une exécution d’agent. La fenêtre est finie, donc chaque partie est un choix.
Un agent qui garde tous les fichiers et tous les résultats d’outils peut remplir sa fenêtre en quelques étapes. Les instructions utiles sont alors noyées sous des sorties dont personne n’a besoin.
À la fin de cette leçon
Remarque
Je peux choisir ce qui entre dans la fenêtre à chaque étape, lui donner un budget et dire quoi retirer d’abord.
Mots clés
| Mot | Ce que ça veut dire |
|---|---|
| Fenêtre de contexte | tout ce que le modèle lit en un appel |
| Budget | le plus grand nombre de jetons qu’une fenêtre peut contenir |
| Épinglé | une partie qu’on ne retire jamais |
| Résultat d’outil | ce qu’un outil a affiché, renvoyé au modèle |
| Mémoire | des notes gardées entre les exécutions et chargées au début |
| Ordre de retrait | les parties qui partent d’abord quand la fenêtre est pleine |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une fenêtre est faite de parties
Chaque appel envoie des parties dans un ordre fixe. Les instructions disent qui est l’agent et ce qu’il peut faire. La mémoire garde des notes durables. Les fichiers sont ce sur quoi il travaille. Les résultats d’outils sont ce que ses outils ont affiché. L’historique est la conversation jusqu’ici.
Le module « Construire des agents » explique comment la mémoire est stockée. Ici, la question est seulement de savoir combien en tient.
Que retirer en premier
Donnez un budget à toute la fenêtre et retirez des parties jusqu’à ce qu’elle tienne. Retirez d’abord ce qui coûte le moins à reconstruire. Un vieux résultat d’outil peut être redemandé. Un fichier peut être relu. La mémoire est plus lente à refaire.
Ne retirez jamais les instructions. Épinglez le fichier en cours de modification. Arrêtez de retirer dès que la fenêtre tient, car chaque retrait de trop fait perdre quelque chose.
Ordre de retrait d’un agent de code
| Partie | Retirée | Pourquoi |
|---|---|---|
| Résultats d’outils | D’abord, les plus anciens en premier | L’outil peut tourner de nouveau |
| Fichiers | Ensuite, sauf s’ils sont épinglés | Le fichier peut être relu |
| Mémoire | En troisième | Les notes sont plus lentes à refaire |
| Historique | En dernier | Il contient ce que la personne a demandé |
| Instructions | Jamais | Sans elles, l’agent n’a plus de règles |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une erreur courante
Attention
Beaucoup coupent par le début, en retirant les plus anciens messages quel que soit leur contenu. Les instructions partent alors en premier. Retirez selon ce qu’est une partie, pas selon son âge.
É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 constructeur de fenêtre, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'const BUDGET = 58;' '// Ici un jeton est un mot. Un vrai tokeniseur compte autrement.' 'function taille(texte) { return texte.split(\" \").length; }' 'const parties = [' ' { genre: \"instructions\", nom: \"regles\", texte: \"Vous êtes un assistant de code. Modifiez seulement les fichiers montrés. Dites ce que vous avez changé.\" },' ' { genre: \"memoire\", nom: \"notes\", texte: \"Le projet utilise des tabulations. Les tests sont dans tests. Lancez-les avant chaque commit.\" },' ' { genre: \"fichier\", nom: \"app.py\", epingle: true, texte: \"def total(articles): return sum(articles) # additionne les prix du panier\" },' '];' > contexte1.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 constructeur de fenêtre, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'parties.push({ genre: \"resultat_outil\", nom: \"essai 1\", texte: \"3 reussis 1 echoue test_total attendu 12 obtenu 10 dans tests slash test_app\" });' 'parties.push({ genre: \"resultat_outil\", nom: \"essai 2\", texte: \"4 reussis 0 echoue\" });' 'parties.push({ genre: \"fichier\", nom: \"lisezmoi\", texte: \"Un petit script de boutique qui calcule le prix des paniers et imprime un recu.\" });' 'const ORDRE = [\"resultat_outil\", \"fichier\", \"memoire\"];' 'function total(liste) {' ' let somme = 0;' ' for (const p of liste) somme = somme + taille(p.texte);' ' return somme;' '}' >> contexte1.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 constructeur de fenêtre, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function assembler(toutes, budget) {' ' const gardees = toutes.slice();' ' const retirees = [];' ' for (const genre of ORDRE) {' ' for (const p of toutes) {' ' if (total(gardees) <= budget) break;' ' if (p.genre === genre && p.epingle === undefined) {' ' gardees.splice(gardees.indexOf(p), 1);' ' retirees.push(p.nom);' ' }' ' }' ' }' ' return { gardees: gardees, retirees: retirees, utilises: total(gardees) };' '}' >> contexte1.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 constructeur de fenêtre, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const f = assembler(parties, BUDGET);' ' console.log(\"budget \" + BUDGET + \", utilisé \" + f.utilises);' ' for (const p of parties) {' ' console.log((f.gardees.includes(p) ? \"gardé \" : \"retiré \") + p.genre + \" \" + p.nom + \" \" + taille(p.texte));' ' }' ' const corps = f.gardees.slice(1).map(function (p) { return p.nom + \" : \" + p.texte; }).join(\" | \");' ' const question = corps + \" | Quel fichier modifiez-vous en premier ? Une phrase.\";' ' const messages = [{ role: \"system\", content: f.gardees[0].texte }, { role: \"user\", content: question }];' ' const reponse = await demander(messages, \"Je modifie app.py en premier, car le test qui échoue porte sur total.\", 40);' ' console.log(\"modèle : \" + reponse.texte);' '}' 'main();' >> contexte1.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 et voir ce qui est retiré
docker exec -w /home/node/project agent node contexte1.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.
Des mots tiennent lieu de jetons
Une vraie fenêtre se compte en jetons, avec le tokeniseur du modèle. Ici un mot vaut un jeton, donc chaque étudiant affiche les mêmes tailles. L’idée reste la même : additionner les parties et comparer à une limite.
Le Run fait un court appel avec ce qui est gardé. Sans modèle, il affiche un échantillon enregistré.
Une sortie possible
| Ligne | Ce qu’elle montre |
|---|---|
| budget 58, utilisé 56 | La fenêtre tient maintenant |
| gardé instructions regles 17 | Les instructions ne sont jamais retirées |
| retiré resultat_outil essai 1 13 | Le plus ancien résultat d’outil part en premier |
| retiré resultat_outil essai 2 4 | Le retrait s’arrête dès que ça tient |
| gardé fichier lisezmoi 15 | Aucun fichier n’a été retiré, le lisezmoi reste |
| modèle : ... | Une phrase. Les mots changent à chaque exécution |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.