La réponse qui a fait planter l’appli
Demander du JSON à un modèle de langage, c’est lui décrire, dans la consigne, la forme exacte de la réponse attendue. C’est utile, car un programme ne peut utiliser qu’une réponse qu’il sait lire.
Une appli de boulangerie demande à un modèle d’inventer une viennoiserie et son prix. Un jour, la réponse commence par « Bien sûr, voici » et le programme s’arrête. Le modèle a répondu, mais pas sous une forme lisible.
À la fin de cette leçon
Remarque
Je peux demander une réponse sous une forme que mon programme sait lire.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Consigne | le texte que l’on envoie à un modèle | |
| JSON | un format de texte pour des données, fait de clés et de valeurs | |
| Clé | le nom d’un champ dans un objet JSON | prix |
| Bloc de code | trois accents graves qui entourent du code dans une réponse | |
| Analyser | lire un texte pour en faire des données utilisables | |
| Limite de jetons | la longueur maximale d’une réponse |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Décrire la forme dans la consigne
Un modèle devine ce que vous voulez d’après vos mots. Décrivez donc la forme. Nommez les clés, donnez le type de chaque valeur et dites ce qu’il faut laisser de côté.
Terminez par une règle simple : répondre uniquement par le JSON. Plus vous laissez de place au hasard, plus les réponses seront différentes.
Exemple travaillé : trois consignes pour une viennoiserie
| La consigne dit | Ce qui peut revenir |
|---|---|
| Donne-moi une viennoiserie et un prix | Des phrases, parfois une liste, aucune clé fixe |
| Donne-moi une viennoiserie en JSON | Sans doute du JSON, avec des clés que vous n’avez pas choisies |
| Réponds par un objet JSON avec les clés nom (texte) et prix (un nombre). Réponds uniquement par le JSON. | Plus de chances d’obtenir la forme demandée |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Montrer un exemple de réponse
Un exemple vaut un paragraphe de règles. Mettez dans la consigne une réponse complète, avec des valeurs inventées, et dites que la vraie réponse doit avoir les mêmes clés.
Les modèles ont tendance à copier la mise en forme d’un exemple. Prenez des valeurs qu’on ne peut pas prendre pour de vraies, sinon un exemple recopié passe pour une vraie réponse.
Écrire l’aide 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\";' '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
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 premier script, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' '' 'const messages = [' ' { role: \"system\", content: \"Tu réponds uniquement par du JSON.\" },' ' { role: \"user\", content: \"Invente une viennoiserie pour une boulangerie. Réponds par un objet JSON avec les clés nom (texte) et prix (un nombre en euros). Réponds uniquement par le JSON.\" },' '];' 'const bloc = \"\x60\x60\x60\";' '// Échantillon enregistré, utilisé seulement si aucun modèle ne répond. Il est brouillon exprès.' 'const echantillon = \"Bien sûr, voici votre viennoiserie :\n\" + bloc + \"json\n\" + JSON.stringify({ nom: \"Pain aux raisins\", prix: 1.4 }) + \"\n\" + bloc + \"\nBonne dégustation.\";' > demande1.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 premier script, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function extraireJson(texte) {' ' try { return JSON.parse(texte); } catch (erreur) { }' ' const debut = texte.indexOf(\"{\");' ' const fin = texte.lastIndexOf(\"}\");' ' if (debut === -1 || fin < debut) return null;' ' try { return JSON.parse(texte.slice(debut, fin + 1)); } catch (erreur) { return null; }' '}' '' 'async function main() {' ' const reponse = await demander(messages, echantillon, 100);' ' console.log(\"Réponse brute :\");' ' console.log(reponse);' ' let entiere = true;' ' try { JSON.parse(reponse); } catch (erreur) { entiere = false; }' ' console.log(\"Toute la réponse est du JSON :\", entiere ? \"oui\" : \"non\");' ' console.log(\"Extrait :\", JSON.stringify(extraireJson(reponse)));' '}' 'main();' >> demande1.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 et lire la réponse
docker exec -w /home/node/project agent node demande1.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.
Une sortie possible
| Ligne | Ce qu’elle peut montrer |
|---|---|
| Réponse brute | Une phrase, puis le JSON dans un bloc de code, puis une autre phrase |
| Toute la réponse est du JSON | non |
| Extrait | {"nom":"Pain aux raisins","prix":1.4} |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Pourquoi une bonne consigne peut échouer
Même une consigne claire peut échouer. Le modèle peut ajouter une formule de politesse, entourer le JSON d’un bloc de code ou changer le nom d’une clé. Il peut aussi s’arrêter trop tôt si la limite de jetons est trop basse, et le JSON reste coupé.
On analyse donc et on vérifie toujours. Bien demander rend une mauvaise réponse plus rare, jamais impossible.
Une erreur fréquente
Attention
Beaucoup pensent qu’une consigne assez claire dispense de vérifier. Une consigne ne fait que réduire le risque d’une mauvaise réponse. Gardez la vérification, même si les cent dernières réponses étaient bonnes.