Montrer d’où vient une réponse
Une citation est un repère dans une réponse qui renvoie à la source d’où elle vient. C’est utile, car on fait plus confiance à une réponse qu’on peut vérifier, et votre programme peut contrôler les repères.
Le chatbot d’une bibliothèque dit qu’un livre en retard coûte dix centimes par jour [2]. Le lecteur regarde la source 2 et y voit la même règle.
À la fin de cette leçon
Remarque
Je peux montrer quelle source une réponse a utilisée.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Source | un passage de texte que la réponse peut utiliser | |
| Citation | un renvoi de la réponse vers sa source | |
| Repère | le numéro entre crochets qui fait la citation | [2] |
| Fondée | qui s’appuie sur les sources que vous avez données | |
| Source inutilisée | une source qu’aucun repère ne désigne |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Numérotez les sources et demandez des repères
Écrivez chaque source dans le message avec un numéro : [1], [2], [3]. Demandez ensuite au modèle de n’employer que ces sources et d’écrire le numéro après chaque fait.
Les sources d’ici sont des passages écrits dans le script. Trouver de vraies sources est un autre sujet, hors de cette leçon. La réponse est fondée quand elle reste dans ce que vous avez donné.
Exemple travaillé : des sources et une réponse
| Partie | Texte |
|---|---|
| Source [1] | Les adhérents peuvent emprunter jusqu’à six livres pour trois semaines. |
| Source [2] | Un livre rendu en retard coûte dix centimes par jour. |
| Question | Combien de livres puis-je emprunter, et quelle est l’amende de retard ? |
| Réponse | Vous pouvez emprunter six livres [1]. Un livre en retard coûte dix centimes par jour [2]. |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Vérifiez que chaque repère a une source
Un modèle peut écrire [4] alors qu’il n’y a que trois sources. Votre programme peut le repérer. Trouvez chaque repère, puis comparez chaque numéro à la liste des identifiants de source.
Cherchez aussi les sources inutilisées et les phrases sans repère. Elles montrent ce que la réponse a laissé de côté.
Une erreur fréquente
Attention
Beaucoup pensent qu’un repère prouve que la réponse est vraie. Il prouve seulement que la source existe. Le modèle peut citer la mauvaise source pour un fait. Le contrôle est un premier filtre, et une personne lit encore la source pour tout ce qui compte.
É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 contrôle des citations, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'const SOURCES = [' ' { id: 1, texte: \"Les adhérents peuvent emprunter jusqu’à six livres pour trois semaines.\" },' ' { id: 2, texte: \"Un livre rendu en retard coûte dix centimes par jour.\" },' ' { id: 3, texte: \"La bibliothèque ouvre à neuf heures et ferme à dix-sept heures en semaine.\" },' '];' > citer5.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 contrôle des citations, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function texteSources() {' ' return SOURCES.map(function (s) { return \"[\" + s.id + \"] \" + s.texte; }).join(\"\n\");' '}' 'function reperesDans(reponse) {' ' const trouves = [];' ' const motif = /\[(\d+)\]/g;' ' let m = motif.exec(reponse);' ' while (m) { trouves.push(Number(m[1])); m = motif.exec(reponse); }' ' return trouves;' '}' >> citer5.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 contrôle des citations, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function controler(reponse) {' ' const ids = SOURCES.map(function (s) { return s.id; });' ' const reperes = reperesDans(reponse);' ' const manquants = reperes.filter(function (n) { return ids.includes(n) === false; });' ' return { reperes: reperes, manquants: manquants, ok: reperes.length > 0 && manquants.length === 0 };' '}' 'function montrer(etiquette, resultat) {' ' console.log(etiquette + \" repères \" + JSON.stringify(resultat.reperes) + \", manquants \" + JSON.stringify(resultat.manquants) + \", ok : \" + resultat.ok);' '}' >> citer5.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 contrôle des citations, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const regle = \"Répondez en vous servant seulement de ces sources numérotées. Après chaque fait, écrivez le numéro de sa source entre crochets, comme [1]. Si les sources ne le disent pas, répondez : Je ne sais pas.\n\" + texteSources();' ' const question = \"Combien de livres puis-je emprunter, et quelle est l’amende de retard ?\";' ' // Échantillon enregistré, utilisé seulement si aucun modèle ne répond.' ' const echantillon = \"Vous pouvez emprunter six livres [1]. Un livre en retard coûte dix centimes par jour [2].\";' ' const reponse = await demander([{ role: \"system\", content: regle }, { role: \"user\", content: question }], echantillon, 80);' ' console.log(\"Réponse :\", reponse);' ' montrer(\"Contrôle :\", controler(reponse));' ' montrer(\"Réponse inventée :\", controler(\"Les prêts durent trois semaines [4].\"));' '}' 'main();' >> citer5.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.
Demander et contrôler les repères
docker exec -w /home/node/project agent node citer5.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 | Deux courtes phrases, chacune finissant par un repère comme [1] |
| Contrôle : | repères [1,2], manquants [], ok : true, si la réponse est restée dans les sources |
| Réponse inventée : | repères [4], manquants [4], ok : false, à chaque fois |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.