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

Construire un chatbot en ligne de commande

Après cette leçon: Je peux assembler des appels à un modèle en un programme qu’une personne peut utiliser.

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

Un chatbot est une boucle autour d’un appel

Un assistant en ligne de commande est un programme qui lit une ligne que vous tapez et l’envoie à un modèle de langage. Il affiche la réponse et recommence jusqu’à ce que vous quittiez. C’est le plus petit programme utile construit sur un modèle.

Il compte, car il réunit tout ce qui précède. On y trouve des messages, un historique, un flux et un appel raté qui ne doit pas casser la discussion.

À la fin de cette leçon

Remarque

Je peux assembler des appels à un modèle en un programme qu’une personne peut utiliser.

Mots clés

MotCe que ça veut direExemple
Boucledu code qui se répète jusqu’à ce qu’on lui dise de s’arrêter
Commandeune ligne tapée qui pilote le programme, pas le modèle/quitter
Historiqueles messages précédents que chaque appel renvoie
Couperretirer les plus anciens messages pour que l’historique reste court
Sortie proprepartir exprès, sans erreur et sans rien perdre

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

Le programme est une boucle avec une liste

Chaque tour fait les mêmes étapes. Lire une ligne. L’ajouter à l’historique comme message user. Envoyer les messages. Afficher la réponse. Ajouter la réponse à l’historique comme message assistant.

La liste est toute la mémoire du programme. Si elle est fausse, toutes les réponses suivantes le sont aussi.

Écrire la partie 1 : l’historique et sa limite

Commande
docker exec -w /home/node/project agent node -e 'require("fs").writeFileSync("assistant.js", ["// assistant.js, partie 1 : l’historique, et une limite à sa taille.", "const labo = require(\"./labo.js\");", "const readline = require(\"readline\");", "const consigne = { role: \"system\", content: \"Vous êtes un assistant utile. Répondez en une ou deux phrases courtes.\" };", "const historique = [];", "const LIMITE = 6;", "", "// Garder seulement les derniers messages, sans jamais commencer par un message assistant.", "function couper() {", "  while (historique.length > LIMITE) historique.shift();", "  while (historique.length > 0 && historique[0].role === \"assistant\") historique.shift();", "}"].join("\n") + "\n")'

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.

Coupez l’historique pour qu’il reste court

Chaque appel envoie tout l’historique : une longue discussion coûte donc plus à chaque tour et peut dépasser la taille que le modèle sait lire. Coupez-le : gardez seulement les derniers messages.

Après la coupe, la liste ne doit pas commencer par un message assistant. Une discussion commence par l’utilisateur, comme vous l’avez vu à la première leçon.

Ajouter la partie 2 : le flux

Commande
docker exec -w /home/node/project agent node -e 'require("fs").appendFileSync("assistant.js", ["", "// Partie 2 : envoyer l’historique et afficher le flux à mesure qu’il arrive.", "const { morceauxDe } = require(\"./flux.js\");", "async function fluxReponse() {", "  let reponse = \"\";", "  for await (const morceau of morceauxDe({ max_tokens: 120, messages: [consigne, ...historique] })) {", "    reponse += morceau;", "    process.stdout.write(morceau);", "  }", "  if (reponse === \"\") throw new Error(\"aucun mot reçu\");", "  return reponse;", "}"].join("\n") + "\n")'

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.

Ajouter la partie 3 : un historique cohérent

Commande
docker exec -w /home/node/project agent node -e 'require("fs").appendFileSync("assistant.js", ["", "// Partie 3 : garder l’historique cohérent. Un appel raté retire la question.", "async function repondre(texte) {", "  historique.push({ role: \"user\", content: texte });", "  try {", "    const reponse = await fluxReponse();", "    process.stdout.write(\"\\n\");", "    historique.push({ role: \"assistant\", content: reponse });", "    couper();", "  } catch (erreur) {", "    historique.pop();", "    console.log(\"\\nExemple enregistré : je ne peux pas joindre le modèle, voici une réponse enregistrée. (\" + erreur.message + \")\");", "  }", "}"].join("\n") + "\n")'

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 erreur fréquente

Attention

Beaucoup laissent la question dans l’historique quand un appel échoue. Au tour suivant, deux messages user se suivent et l’ordre est rompu. Quand un appel échoue, retirez la question, dites-le, et laissez la personne réessayer.

Des commandes et une sortie propre

Certaines lignes sont pour le programme, pas pour le modèle. Une ligne qui commence par / est une commande : /quitter part, /effacer vide l’historique et /historique le compte.

Cherchez les commandes avant d’appeler le modèle. Ainsi, une personne peut toujours partir, quoi que fasse le modèle.

Ajouter la partie 4 : la boucle

Commande
docker exec -w /home/node/project agent node -e 'require("fs").appendFileSync("assistant.js", ["", "// Partie 4 : la boucle. Une ligne qui commence par / est une commande.", "const lignes = readline.createInterface({ input: process.stdin });", "const invite = () => process.stdout.write(\"vous> \");", "(async () => {", "  console.log(\"Assistant prêt. Commandes : /quitter, /effacer, /historique.\");", "  invite();", "  for await (const ligne of lignes) {", "    const texte = ligne.trim();", "    if (!process.stdin.isTTY) console.log(texte);", "    if (texte === \"/quitter\") break;", "    if (texte === \"/effacer\") { historique.length = 0; console.log(\"Historique effacé.\"); }", "    else if (texte === \"/historique\") console.log(historique.length + \" messages gardés.\");", "    else if (texte !== \"\") { process.stdout.write(\"assistant> \"); await repondre(texte); }", "    invite();", "  }", "  console.log(\"Au revoir.\");", "  process.exit(0);", "})();"].join("\n") + "\n")'

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.

Discuter avec un scénario tapé

Commande
printf "Je m’appelle Samir.\nComment je m’appelle ?\n/historique\n/effacer\n/historique\n/quitter\n" | docker exec -i -w /home/node/project agent node assistant.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.

Exemple travaillé : ce qu’a fait le scénario

TapéCe qu’a fait le programme
Je m’appelle Samir.A envoyé 2 messages (le message système et la question), affiché une réponse, gardé 2
Comment je m’appelle ?A envoyé 4 messages (avec le message système), affiché une réponse, gardé 4
/historiqueA affiché 4 messages gardés
/effacerA vidé l’historique
/quitterA affiché Au revoir et est parti

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

Discutez vous-même avec lui

Le scénario ci-dessus a été tapé pour vous. Pour discuter à la main, ouvrez un terminal dans le labo et tapez cette ligne : docker exec -it -w /home/node/project agent node assistant.js. Puis tapez des questions et finissez par /quitter.

Il attend que vous tapiez, donc ce n’est pas un bouton. Ne tapez ni mot de passe ni rien de personnel : ce que vous tapez est envoyé à un modèle.

Pour aller plus loin : changez l’assistant

Changez la consigne de la partie 1 pour donner une personnalité à l’assistant, et passez LIMITE à 4. Discutez pendant six tours.

Notez ce que l’assistant a oublié et quand. Dites ce que coûte un long historique, et ce que vous feriez à ce sujet.

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