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

Tracer un appel à un modèle

Après cette leçon: Je peux enregistrer ce que fait chaque appel, pour retrouver d’où vient une panne ou un retard.

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

Trouver l’étape lente

Tracer un appel à un modèle, c’est enregistrer ce que chaque étape d’une requête a fait et combien de temps elle a pris. C’est utile parce qu’une fonction à modèle échoue au milieu d’une chaîne. Deux lignes de journal aux extrémités ne disent pas où.

Un utilisateur se plaint que les réponses prennent dix secondes. Est-ce le prompt, le modèle, un nouvel essai ou la vérification ? Une trace répond d’un coup d’œil.

À la fin de cette leçon

Remarque

Je peux enregistrer ce que fait chaque appel, pour retrouver d’où vient une panne ou un retard.

Mots clés

MotCe que ça veut dire
Tracel’enregistrement d’une requête, du début à la fin
Spanune étape chronométrée à l’intérieur d’une trace
Parentle span qui en contient un autre
Attributun fait nommé, rangé sur un span
Temps proprela durée d’un span moins les durées de ses enfants directs
Identifiant de tracel’identifiant commun à tous les spans d’une requête
Expurgationretirer les secrets avant de ranger un enregistrement

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

Une trace est un arbre de spans

Une trace est une requête, faite de spans. Chaque span a un nom, un début, une fin et un parent. La racine n’a pas de parent. Tous les spans d’une requête partagent un identifiant de trace et portent des attributs.

Le temps propre d’un span est sa durée moins celles de ses enfants directs. Ci-dessous, la requête dure 856 ms mais son temps propre est 0 ms. L’appel au modèle a un temps propre de 850 ms : c’est l’étape lente.

Exemple détaillé : une requête

SpanParentDébutFinDurée
requeteaucun0856856 ms
construire le promptrequete044 ms
appel au modelerequete4854850 ms
verifier la reponserequete8548562 ms

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

Ce qu’une trace ne contient jamais

Un stockage de traces est lu par beaucoup de monde et gardé des semaines. Un span ne contient donc jamais de secret : clé d’API, jeton ou mot de passe. Il ne contient jamais de donnée personnelle : adresse électronique, nom ou numéro de téléphone.

En général, il ne garde pas non plus le prompt ni la réponse. Rangez des tailles, des nombres et des résultats. Retirez les clés dangereuses à un seul endroit, avant d’enregistrer le span.

Une erreur courante

Attention

Beaucoup pensent qu’écrire le prompt entier dans le journal est sans danger, puisque le journal est interne. Or les prompts contiennent ce que les gens ont tapé, et ils tapent des noms et des secrets. Notez la longueur et le résultat, pas le texte.

É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 traceur, partie 1

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' '' 'let maintenant = 0; // une horloge que nous avançons nous-mêmes : mêmes temps pour tous' 'const spans = [];' 'function avancer(ms) { maintenant = maintenant + ms; }' 'function ouvrir(nom, parent) {' '  const span = { id: spans.length + 1, nom, parent, debut: maintenant, fin: maintenant, attributs: {} };' '  spans.push(span);' '  return span;' '}' 'function fermer(span) { span.fin = maintenant; }' > trace1.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 traceur, partie 2

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// Clés qui n’entrent jamais dans une trace : secrets et données personnelles.' 'const JAMAIS = [\"courriel\", \"cle_api\", \"prompt\", \"nom\"];' 'function noter(span, cle, valeur) {' '  span.attributs[cle] = JAMAIS.includes(cle) ? \"[retiré]\" : valeur;' '}' >> trace1.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 traceur, partie 3

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function afficher(parent, profondeur) {' '  for (const s of spans) {' '    if (s.parent === parent) {' '      console.log(\"  \".repeat(profondeur) + s.nom + \" \" + (s.fin - s.debut) + \" ms \" + JSON.stringify(s.attributs));' '      afficher(s.id, profondeur + 1);' '    }' '  }' '}' >> trace1.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 traceur, partie 4

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function etapeModele(racine) {' '  const appel = ouvrir(\"appel au modele\", racine.id);' '  const messages = [{ role: \"user\", content: \"Cite un usage d’une trace, en une phrase.\" }];' '  const reponse = await demander(messages, \"Une trace montre quelle étape d’une requête a été lente.\", 40);' '  avancer(850); // 850 ms fixes sur notre horloge, quel que soit le temps réel' '  noter(appel, \"resultat\", reponse.texte.length > 0 ? \"ok\" : \"vide\");' '  noter(appel, \"prompt\", messages[0].content);' '  fermer(appel);' '}' >> trace1.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 traceur, partie 5

Commande
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  const racine = ouvrir(\"requete\", 0);' '  noter(racine, \"route\", \"/question\");' '  noter(racine, \"courriel\", \"[email protected]\");' '  const construire = ouvrir(\"construire le prompt\", racine.id);' '  avancer(4); fermer(construire);' '  await etapeModele(racine);' '  const verifier = ouvrir(\"verifier la reponse\", racine.id);' '  avancer(2); fermer(verifier); fermer(racine);' '  console.log(\"trace t-0001\");' '  afficher(0, 0);' '}' 'main();' >> trace1.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 afficher la trace

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

Ceci est une maquette

Le labo n’a pas de service de traçage. Les spans sont donc dans une liste, et l’horloge est un nombre que le script avance. Un vrai système envoie ses spans à un vrai service de traçage et lit la vraie horloge.

La forme reste la même : un identifiant de trace, un arbre, des attributs et une règle sur ce qui peut être rangé.

Une sortie possible

LigneCe qu’elle montre
trace t-0001L’identifiant de trace
requete 856 msLa racine, avec la route, et le courriel retiré
construire le prompt 4 msUn enfant, décalé de deux espaces
appel au modele 850 msL’étape lente, avec le prompt retiré
verifier la reponse 2 msLe dernier enfant

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.