Un assistant de magasin qui répond aux questions
Un magasin de location de vélos crée un assistant. Un client tape une question. L’appli cherche le meilleur paragraphe parmi les réponses du magasin et le confie à un modèle de langage, qui rédige la réponse.
Si l’appli trouve le mauvais paragraphe, le modèle rédige très poliment une mauvaise réponse. Cette leçon teste la recherche. C’est du code simple : on peut la noter sans appeler aucun modèle.
À la fin de cette leçon
Remarque
Je peux tester une appli qui répond à des questions avec un petit jeu de questions, chacune avec le fait que la réponse doit contenir.
Mots clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Recherche | trouver le texte qui doit aider à répondre à une question | |
| Fait attendu | un court morceau de texte qu’une bonne réponse doit contenir | douze euros |
| Taux de réussite | la part des questions où le bon texte a été trouvé | |
| Mot vide | un mot courant, comme « le », qui apprend peu | |
| Fausse réponse | un texte a été trouvé, mais il ne contient pas le fait | |
| Pas de réponse | rien ne correspond, donc l’appli dit qu’elle ne sait pas |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Deux étapes, une seule se teste bien
Beaucoup d’applis répondent en deux étapes. D’abord la recherche : choisir le paragraphe qui correspond à la question. Ensuite un modèle de langage rédige la réponse à partir de ce paragraphe.
La réponse d’un modèle change d’un lancement à l’autre : elle se note mal. La recherche donne le même résultat à chaque fois : elle se note bien. Si elle se trompe, rien après elle ne peut être juste.
Compter les mots communs
Ici la correspondance est aussi simple que possible. Coupez la question en mots. Pour chaque paragraphe, comptez combien de ces mots s’y trouvent aussi. Le paragraphe au plus grand compte gagne.
Elle compare des mots entiers : « ouvre » ne correspond pas à « ouvrir ». Lancez le code et lisez les comptes.
Compter les mots communs pour une question
def mots(texte):
for signe in ".,?":
texte = texte.replace(signe, "")
return texte.lower().split()
docs = [
"Le magasin ouvre à neuf heures et ferme à dix-huit heures du lundi au samedi.",
"Un vélo coûte douze euros pour une journée et cinq euros pour une heure.",
"Vous pouvez rendre un vélo dans les trois stations de la ville.",
"Si un vélo tombe en panne, appelez le numéro écrit sur le cadre et nous viendrons le réparer.",
"Les casques sont gratuits avec chaque location, mais il faut les demander au comptoir.",
]
question = "Quel est le prix de la journée ?"
for texte in docs:
communs = []
for mot in mots(question):
if mot in mots(texte):
communs.append(mot)
print(len(communs), communs, "<-", texte[:28])
# Changez la question en "Où puis-je rendre un vélo ?" et relancez.
Un jeu de test : questions et faits
Pour noter l’appli, il faut un petit jeu de test. Il contient des questions qu’un client pourrait poser. Chacune a le fait attendu que le bon paragraphe contient.
Une question est juste si le paragraphe trouvé contient son fait. Elle est fausse si un paragraphe a été trouvé sans lui. Elle est sans réponse si rien n’a correspondu.
Écrire les cinq réponses du magasin
docker exec jupyter sh -c "printf '%s\n' 'd1|Le magasin ouvre à neuf heures et ferme à dix-huit heures du lundi au samedi.' 'd2|Un vélo coûte douze euros pour une journée et cinq euros pour une heure.' 'd3|Vous pouvez rendre un vélo dans les trois stations de la ville.' 'd4|Si un vélo tombe en panne, appelez le numéro écrit sur le cadre et nous viendrons le réparer.' 'd5|Les casques sont gratuits avec chaque location, mais il faut les demander au comptoir.' > faq.txt"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 les six questions de test
docker exec jupyter sh -c "printf '%s\n' 'Quand le magasin ouvre-t-il ?|neuf heures' 'Quel est le prix de la journée ?|douze euros' 'Où puis-je rendre un vélo ?|trois stations' 'Que faire si mon vélo tombe en panne ?|appelez le numéro' 'Ai-je droit à un casque ?|gratuits' 'Quels jours êtes-vous fermés ?|samedi' > questions.txt"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 notation
docker exec jupyter sh -c "printf '%s\n' 'import sys' '' 'IGNORER = [\"le\", \"la\", \"les\", \"un\", \"une\", \"de\", \"du\", \"des\", \"est\", \"quel\", \"quelle\", \"que\", \"qui\", \"où\", \"pour\", \"à\", \"en\", \"si\", \"et\", \"au\", \"mon\", \"ma\", \"vous\", \"nous\", \"ai-je\", \"puis-je\"]' '' '' 'def mots(texte):' ' for signe in \".,?\":' ' texte = texte.replace(signe, \"\")' ' return texte.lower().split()' '' '' 'docs = []' 'for ligne in open(\"faq.txt\", encoding=\"utf-8\"):' ' docs.append(ligne.strip().split(\"|\")[1])' 'ignorer = []' 'if sys.argv[1] == \"vides\":' ' ignorer = IGNORER' 'juste = 0' 'faux = 0' 'rien = 0' 'for ligne in open(\"questions.txt\", encoding=\"utf-8\"):' ' question, fait = ligne.strip().split(\"|\")' ' demande = []' ' for mot in mots(question):' > steps/demander.py"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 la suite du script de notation
docker exec jupyter sh -c "printf '%s\n' ' if mot not in ignorer:' ' demande.append(mot)' ' meilleur = \"\"' ' meilleur_commun = 0' ' for texte in docs:' ' commun = 0' ' for mot in demande:' ' if mot in mots(texte):' ' commun = commun + 1' ' if commun > meilleur_commun:' ' meilleur = texte' ' meilleur_commun = commun' ' if meilleur == \"\":' ' rien = rien + 1' ' print(\"rien :\", question)' ' elif fait in meilleur.lower():' ' juste = juste + 1' ' print(\"juste :\", question)' ' else:' ' faux = faux + 1' ' print(\"faux :\", question)' 'print(\"justes\", juste, \"faux\", faux, \"rien\", rien, \"taux\", round(juste / (juste + faux + rien), 2))' >> steps/demander.py"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.
Noter la correspondance simple
docker exec jupyter python3 steps/demander.py brutAffiché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.
Corriger une chose et noter de nouveau
Deux questions sont parties vers le mauvais paragraphe à cause de petits mots comme « de » et « la ». Retirez de la question ces mots vides avant de compter, et notez de nouveau.
On change une seule chose à la fois. Si vous en changiez trois d’un coup, vous ne sauriez pas laquelle a aidé.
Noter de nouveau en ignorant les mots vides
docker exec jupyter python3 steps/demander.py videsAffiché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 pensent que l’appli s’est améliorée parce que le taux est passé de 0.5 à 0.67. Regardez les autres nombres. Les deux fausses réponses sont devenues juste ou sans réponse, ce qui vaut mieux, mais deux questions ne trouvent toujours rien. Un jeu de test si petit dit où chercher, pas si l’appli est bonne.
Exemple travaillé : les deux lancements côte à côte
| Lancement | Justes | Fausses | Sans réponse | Taux |
|---|---|---|---|---|
| Mots entiers, rien ignoré | 3 | 2 | 1 | 0.5 |
| Mots vides ignorés | 4 | 0 | 2 | 0.67 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Plus loin : ajouter vos questions
Ajoutez quatre questions au fichier de test, chacune avec un fait. Mettez-en une à laquelle les cinq réponses du magasin ne peuvent pas répondre.
Notez de nouveau les deux lancements. Quelle issue serait la bonne pour la question sans réponse dans le texte du magasin ? L’appli la trouve-t-elle ?