Comment fonctionne un budget de contexte
Un budget de contexte est le nombre de jetons que vous laissez à chaque partie d’un prompt. Un modèle ne lit qu’une quantité limitée de texte à la fois. Quand les parties dépassent cette limite, il faut en sacrifier.
Le module sur le coût, le traçage et la fiabilité budgète l’argent et les appels. Cette leçon va plus loin : elle budgète la fenêtre elle-même, et vous dites à l’utilisateur ce qui a été laissé de côté.
À la fin de cette leçon
Remarque
Je peux décider ce qui tient dans une fenêtre et ce qui part en premier.
Mots clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Jeton | un petit morceau de texte que le modèle compte | environ un mot |
| Fenêtre | le maximum de jetons lus et écrits en un appel | |
| Budget | les jetons qu’une partie du prompt peut utiliser | |
| Priorité | l’importance d’une partie ; 0 n’est jamais écartée | |
| Couper | raccourcir une partie pour qu’elle tienne | |
| Réserve | la place gardée libre pour la réponse |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
La réponse a aussi besoin de place
La fenêtre est partagée entre le prompt et la réponse. Si le prompt la remplit, la réponse est coupée ou l’appel échoue.
Gardez donc d’abord la place de la réponse. Gardez ensuite une petite marge de sécurité, car votre compte n’est qu’une estimation. Ce qui reste est le budget du prompt.
Exemple détaillé : le budget du prompt
| Étape | Jetons | Pourquoi |
|---|---|---|
| Fenêtre | 4000 | Le maximum que le modèle sait traiter |
| Réserve pour la réponse | 500 | La réponse a besoin de place |
| Marge, 5 pour cent | 200 | 5 pour cent de 4000, au cas où le compte serait un peu faux |
| Budget du prompt | 3300 | 4000 moins 500 moins 200 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une erreur courante
Attention
Beaucoup pensent que la fenêtre ne sert qu’au prompt. Elle contient aussi la réponse. Un prompt qui remplit toute la fenêtre ne laisse aucune place pour répondre.
Quelle partie part en premier ?
Donnez à chaque partie une priorité. Les règles et la question de l’utilisateur ont la priorité 0 : elles ne sont jamais écartées. Si elles ne tiennent pas, le prompt est cassé et il faut le dire.
Prenez ensuite le reste par ordre d’importance. Gardez une partie si elle tient. Sinon écartez-la, mais une partie plus petite, plus loin, peut encore entrer.
Exemple détaillé : un budget de 3300
| Partie | Jetons | Priorité | Total jusque-là | Résultat |
|---|---|---|---|---|
| Règles | 300 | 0 | 300 | Gardée |
| Question | 100 | 0 | 400 | Gardée |
| Document A | 900 | 1 | 1300 | Gardée |
| Document B | 800 | 2 | 2100 | Gardée |
| Document C | 700 | 2 | 2800 | Gardée |
| Historique | 1400 | 3 | 4200 dépasserait | Écartée |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Couper plutôt que tout écarter
Écarter l’historique perd toute la conversation. Mieux vaut le couper : gardez les messages les plus récents qui tiennent.
Remontez du message le plus récent. Arrêtez-vous au premier qui ne tient pas, car un trou au milieu d’une conversation n’a aucun sens.
Exemple détaillé : 500 jetons restants
| Message | Jetons | Total | Résultat |
|---|---|---|---|
| Le plus récent | 200 | 200 | Gardé |
| Celui d’avant | 250 | 450 | Gardé |
| Deux avant | 300 | 750 dépasserait | On s’arrête ici |
| Le plus ancien | 100 | Jamais atteint | Écarté, même s’il tiendrait |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
É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 script de budget, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'function jetons(texte) { return texte.split(\" \").length; }' 'const parties = [' ' { nom: \"regles\", jetons: 60, priorite: 0 },' ' { nom: \"question\", jetons: 25, priorite: 0 },' ' { nom: \"doc A\", jetons: 120, priorite: 1 },' ' { nom: \"doc B\", jetons: 90, priorite: 2 },' ' { nom: \"historique\", jetons: 150, priorite: 3 },' ' { nom: \"doc C\", jetons: 80, priorite: 2 },' '];' > budget.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 budget, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function assembler(parties, budget) {' ' const ordre = parties.slice().sort(function (a, b) { return a.priorite - b.priorite; });' ' const gardes = [];' ' let utilise = 0;' ' for (const p of ordre) {' ' if (p.priorite === 0 || utilise + p.jetons <= budget) { gardes.push(p.nom); utilise = utilise + p.jetons; }' ' }' ' return { gardes: gardes, utilise: utilise };' '}' >> budget.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 budget, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' for (const budget of [350, 600]) {' ' const r = assembler(parties, budget);' ' const noms = parties.map(function (p) { return p.nom; });' ' console.log(\"budget \" + budget + \" : gardés \" + noms.filter(function (n) { return r.gardes.includes(n); }).join(\", \"));' ' console.log(\" écartés \" + (noms.filter(function (n) { return r.gardes.includes(n) === false; }).join(\", \") || \"aucun\") + \", utilisés \" + r.utilise);' ' }' >> budget.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 budget, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' const q = \"En une phrase courte, que doit perdre un prompt en premier quand il est trop long ?\";' ' const echantillon = \"Il perd d’abord les parties les plus anciennes ou les moins utiles, jamais les règles ni la question.\";' ' const reponse = await demander([{ role: \"user\", content: q }], echantillon, 60);' ' console.log(\"le modèle dit : \" + reponse.texte);' ' console.log(\"mon compte \" + jetons(q) + \", compte du modèle \" + (reponse.entree === null ? \"non fourni\" : reponse.entree));' '}' 'main();' >> budget.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 budget
docker exec -w /home/node/project agent node budget.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 |
|---|---|
| budget 350 : gardés regles, question, doc A, doc B | Les parties qui tiennent, dans leur ordre d’origine |
| écartés historique, doc C, utilisés 295 | Ce qui a été laissé de côté et les jetons utilisés |
| budget 600 : gardés ... et écartés aucun | Avec de la place, toutes les parties entrent |
| le modèle dit : ... | Une phrase du labo. Un échantillon enregistré si aucun modèle ne répond |
| mon compte ..., compte du modèle ... | Mon compte de mots à côté de celui du modèle, ou non fourni |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.