Aller au contenu
English

Un premier essai sans compte

  • Leçon 2
  • 40 min
  • Module 1 : Commencer par une seule requête au modèle

Ce que vous saurez faire

Faites fonctionner le projet du cours sur votre ordinateur et vérifiez son fonctionnement, sans compte ni clé. Chaque leçon suivante commence avec ce projet et cette vérification.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 40 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • Python 3.12 ou une version plus récente, selon Installer et vérifier Python.
  • Le dossier ~/projects. S’il manque, exécutez d’abord mkdir ~/projects.
  • Un éditeur comme VS Code et une connexion Internet pour télécharger le projet et ses paquets (environ 30 Mo).
  • Git est facultatif : vous pouvez plutôt télécharger un fichier ZIP.

Vous n’avez besoin d’aucun compte, d’aucune clé d’API et d’aucun paiement. Rien dans cette leçon n’appelle un modèle.

Testé sur macOS (puce Apple), avec Python 3.12.13 et 3.14.6. Les versions des paquets : openai 3.26.1, pydantic 2.14.0, httpx 0.28.1 et pytest 9.1.1. Les commandes Windows et Linux suivent le cours de Python; elles n’ont pas été exécutées pour cette leçon.

Au théâtre, la vedette est occupée et coûte cher. Les autres acteurs répètent donc avec une doublure, qui lit les répliques de la vedette mot pour mot. Les acteurs peuvent répéter une scène vingt fois, sans frais, et les répliques ne changent jamais. Si un acteur dit une réplique absente du texte, la doublure n’a pas de réponse. C’est utile aussi : cela montre que quelqu’un a changé la scène.

Le problème : un vrai modèle est un mauvais partenaire d’exercice

Section intitulée « Le problème : un vrai modèle est un mauvais partenaire d’exercice »

TermeAmiraLa développeuse de Larkfield. Elle écrit le code des outils du service d’assistance dans les cours. veut travailler toute la journée sur le code de l’assistant : changer une ligne, exécuter, vérifier la sortie, puis recommencer. Avec un vrai TermeModèle hébergéUn modèle qui fonctionne sur les ordinateurs d’un fournisseur. Votre code lui envoie des requêtes par Internet, et vous payez chaque appel.En savoir plus Modèle hébergé ou autohébergéLes LLM : comment ils fonctionnent et comment en choisir un, chaque exécution exige trois choses qui peuvent manquer à l’apprenant : un compte, une clé et un moyen de paiement. Chaque exécution a aussi besoin du réseau et prend environ trois secondes.

Pire encore, la réponse change. Amira a envoyé trois fois la même requête pour le billet de soutien T-80008 à Termechat-smallLe nom que le code de Larkfield donne à un petit modèle hébergé peu coûteux : gpt-6-luna sur Azure. Le code utilise ce nom, donc le modèle peut changer sans modifier le code.En savoir plus Ce qu'est une API de LLMCréer des applications fiables avec les API de LLM. Elle a reçu trois réponses différentes, avec 241, 238 et 308 jetons (tokens) de sortie. Les trois étaient correctes, mais un test ne peut pas vérifier une sortie exacte qui change à chaque exécution. Et un échec, comme une erreur du fournisseur, ne survient pas au moment où vous voulez l’étudier.

L’idée : une simulation qui rejoue de vraies réponses

Section intitulée « L’idée : une simulation qui rejoue de vraies réponses »

Un objet simulé (mock) imite un vrai composant pour les exercices et les tests. Le mot signifie « pas réel, mais conçu pour sembler réel », comme dans un examen simulé. Le fournisseur simulé du projet joue le rôle de la doublure : il n’appelle pas de modèle. Il cherche une vraie réponse enregistrée pour exactement la même requête, puis la renvoie.

Le fournisseur simulé a besoin d’un nom pour chaque requête afin de trouver le bon enregistrement. Il calcule ce nom à partir de la requête elle-même : le modèle, les messages et les paramètres. Il calcule ensuite leur hachage, une courte empreinte qui change complètement dès qu’un seul caractère change. Les enregistrements du cours sont stockés sous ces empreintes.

Voici l’empreinte, la clé de requête, de deux petites requêtes. Elles diffèrent d’un seul caractère : « Hi » et « Hi! ».

from assistant.providers import request_key
a = {"model": "chat-small", "messages": [{"role": "user", "content": "Hi"}], "max_completion_tokens": 10}
print(request_key(a))
a["messages"][0]["content"] = "Hi!"
print(request_key(a))

La sortie :

f820d94a816df5e3
ee89cd3383490bd7

Un caractère a changé, et toute la clé a changé. Le fournisseur simulé répond donc uniquement à une requête qu’il a déjà vue, à l’identique. La requête du projet pour le billet T-80008, la requête v1 et chat-small a la clé 3b337102809abc06. Le fichier recordings/eval_text.jsonl contient une vraie réponse sous cette clé : gpt-6-luna sur Azure.

Un flux de haut en bas. python -m assistant analyse T-80008. load_ticket : le billet de data/tickets.csv. build_request : modèle chat-small, 2 messages, max_completion_tokens 1000. request_key : SHA-256 des champs de la requête, 3b337102809abc06. Une décision : un enregistrement avec cette clé? Oui : Completion, le texte de réponse enregistré, finish_reason, jetons, latence, puis affichage : la réponse JSON et une ligne de résumé. Non : RecordingNotFound, No recording for this request (aucun enregistrement pour cette requête).
Comment le fournisseur simulé trouve la réponse pour un billet. La clé est une vraie empreinte de la requête du projet pour T-80008.
Description textuelle du diagramme

La commande python -m assistant analyse T-80008 lance le flux. load_ticket lit le billet dans data/tickets.csv. La fonction build_request crée la requête : modèle chat-small, deux messages, max_completion_tokens 1000. La fonction request_key calcule l’empreinte SHA-256 des champs de la requête. Elle garde les 16 premiers caractères : 3b337102809abc06. Si les enregistrements contiennent une entrée avec cette clé, le fournisseur simulé la renvoie sous forme de Completion. Une Completion contient le texte de réponse enregistré, la raison de fin, les jetons et la durée de l’appel réel. La commande affiche la réponse en JSON et une ligne de résumé. Si aucun enregistrement n’a cette clé, le fournisseur simulé déclenche RecordingNotFound avec le message « No recording for this request » (aucun enregistrement pour cette requête).

Le projet se trouve dans le dépôt des laboratoires du cours, sous forme d’instantanés : des copies au début et à la fin de chaque module. Vous commencez avec start.

  1. Ouvrez un terminal et allez dans votre dossier de projets :

    Fenêtre de terminal
    cd ~/projects
  2. Si vous avez Git, clonez le dépôt des laboratoires :

    Fenêtre de terminal
    git clone https://github.com/Nextia-Intelligence/nextia-learning-labs.git

    Si vous n’avez pas Git, téléchargez le fichier ZIP du dépôt. Décompressez-le dans ~/projects. Son dossier s’appelle nextia-learning-labs-main : utilisez ce nom à l’étape suivante.

  3. Copiez l’instantané start dans un nouveau dossier, ticket-assistant :

    Fenêtre de terminal
    cp -R nextia-learning-labs/C08/snapshots/start ticket-assistant
  4. Allez dans le projet et ouvrez-le dans votre éditeur :

    Fenêtre de terminal
    cd ticket-assistant
    code .

    Si code est introuvable, ouvrez le dossier depuis le menu File (fichier) de l’éditeur.

Vous travaillez dans votre copie, ticket-assistant. Le dossier des laboratoires reste intact pour que vous puissiez copier un instantané à tout moment.

Le projet a besoin de quatre paquets à des versions précises. Vous les installez dans un TermeEnvironnement virtuelUn dossier avec son propre Python et ses propres paquets, pour un seul projet. Les paquets installés là ne changent pas les autres projets.En savoir plus Isoler les dépendancesPython pour l'ingénierie de l'IA en pratique du dossier du projet, comme dans le cours de Python.

  1. Créez et activez l’environnement :

    Fenêtre de terminal
    python3 -m venv .venv
    source .venv/bin/activate

    L’invite commence maintenant par (.venv). À partir d’ici, tapez python sur tous les systèmes.

  2. Installez les paquets de requirements.txt :

    Fenêtre de terminal
    python -m pip install -r requirements.txt

    La dernière ligne de la sortie :

    Successfully installed annotated-types-0.8.0 anyio-4.15.1 certifi-2026.7.22 h11-0.16.0 httpcore-1.0.9 httpcore2-2.13.1 httpx-0.28.1 httpx2-2.13.1 idna-3.20 iniconfig-2.3.1 jiter-0.17.0 openai-3.26.1 packaging-26.3 pluggy-1.6.0 pydantic-2.14.0 pydantic-core-2.50.0 pygments-2.21.0 pytest-9.1.1 sniffio-1.3.1 truststore-0.10.4 typing-extensions-4.16.0 typing-inspection-0.4.4

    Vous avez demandé quatre paquets, et pip a aussi installé les paquets dont ils ont besoin. Vous pouvez ignorer sans risque l’avis concernant une nouvelle version de pip.

requirements.txt fixe les versions testées dans le cours : openai==3.26.1, pydantic==2.14.0, httpx==0.28.1 et pytest==9.1.1. Le fournisseur simulé n’utilise pas encore openai. La leçon 3 de ce module utilise httpx, et la leçon 4 utilise openai.

Deux vérifications prouvent que l’installation fonctionne : les tests, puis un billet.

  1. Exécutez les tests :

    Fenêtre de terminal
    python -m pytest

    La sortie (le chemin de votre dossier sera différent) :

    ============================= test session starts ==============================
    platform darwin -- Python 3.14.6, pytest-9.1.1, pluggy-1.6.0
    rootdir: /Users/amira/projects/ticket-assistant
    configfile: pytest.ini
    testpaths: tests
    plugins: anyio-4.15.1
    collected 2 items
    tests/test_first_run.py .. [100%]
    ============================== 2 passed in 0.01s ===============================

    Chaque point représente un test réussi. La partie importante est 2 passed (2 tests réussis).

  2. Analysez le billet T-80008 :

    Fenêtre de terminal
    python -m assistant analyse T-80008

    La sortie :

    {
    "language": "en",
    "team": "delivery",
    "needs_human": false,
    "reason": "The customer is asking for the delivery date of an order that has shipped, so delivery is the appropriate team and no human-escalation condition is present.",
    "confidence": "high",
    "order": {
    "order_id": "LK-581106",
    "status": null
    },
    "reply": "I’m sorry you don’t have a delivery date yet. Our delivery team can check the latest tracking information for order LK-581106 and share the estimated arrival date. Please allow 3–5 business days for standard delivery in Canada."
    }
    gpt-6-luna-2026-09-22 | finish_reason: stop | 1032 tokens in, 241 out | 2.678 s when it was recorded

Votre sortie doit être identique, caractère par caractère. Le fournisseur simulé rejoue un enregistrement, donc rien n’est aléatoire. La dernière ligne est le résumé. gpt-6-luna-2026-09-22 est le modèle qui a rédigé la réponse. finish_reason: stop signifie qu’il a terminé normalement. Les jetons représentent l’utilisation, et l’appel réel a pris 2,678 s. Votre exécution a pris une fraction de seconde : rien n’a circulé sur le réseau.

Le schéma montre quoi faire si une vérification échoue.

Un flux de décision. Exécuter python -m pytest. Si le résultat n'est pas 2 passed : vérifier que l'invite affiche .venv et réinstaller les dépendances, puis relancer les tests. Si le résultat est 2 passed : exécuter python -m assistant analyse T-80008. Si la dernière ligne se termine par 1032 tokens in, 241 out : tout est prêt, l'installation fonctionne. Sinon : réinitialiser, recopier l'instantané start avec un nouvel environnement .venv, puis relancer les tests.
La vérification de l'installation. Deux tests réussis et la ligne attendue pour T-80008 indiquent que vous êtes prêt.
Description textuelle du diagramme

Exécutez d’abord python -m pytest. Si vous ne voyez pas « 2 passed », vérifiez que l’invite commence par (.venv), réinstallez les dépendances et relancez les tests. Quand vous voyez « 2 passed », exécutez python -m assistant analyse T-80008. Si la dernière ligne se termine par « 1032 tokens in, 241 out » (1 032 jetons d’entrée, 241 de sortie), l’installation fonctionne. Sinon, réinitialisez : recopiez l’instantané start dans un nouveau dossier, créez un nouvel environnement .venv et recommencez les vérifications.

Chemin Son rôle
assistant/__main__.py La ligne de commande : python -m assistant analyse TICKET.
assistant/data.py Lit les 69 billets de data/tickets.csv.
assistant/context.py Construit la requête : les instructions de prompts/v1.md, la politique de Grace et le billet.
assistant/prompts/ v1.md, la première requête d’Amira, et policy.md, la politique de soutien de Grace.
assistant/providers.py L’adaptateur : le seul code qui communique avec un fournisseur de modèles. Pour l’instant, il contient le fournisseur simulé.
recordings/eval_text.jsonl 276 vraies réponses : 69 billets, deux versions de requête, deux modèles hébergés.
tests/ Les deux tests que vous avez exécutés.

Le cœur du fournisseur simulé est court. Il lit chaque enregistrement dans un dictionnaire, par clé. Pour répondre à une requête, il calcule la clé et la cherche :

assistant/providers.py (part)
def _entry(self, request: dict) -> dict:
key = request_key(request)
if key not in self.recordings:
raise RecordingNotFound(
f"No recording for this request (key {key}). The mock replays only the requests that were "
"recorded for the course: check the ticket ID, the prompt version and the model.")
...

Le reste de l’assistant ne sait pas que la réponse est un enregistrement. Il appelle complete(request) et reçoit une Completion, avec le texte, la raison de fin et les jetons. La leçon 4 de ce module ajoute un deuxième fournisseur qui appelle un vrai modèle avec le même complete(request). Rien d’autre ne doit changer.

Utilisez le fournisseur simulé pour apprendre, pour tous les tests et pour la plupart des travaux de développement. Il est gratuit, rapide et identique à chaque fois. Il peut aussi rejouer un échec, comme une erreur de fournisseur, aussi souvent que nécessaire.

Un fournisseur simulé ne peut pas vous dire comment un modèle répond à une nouvelle requête : nouveau billet, nouvelles instructions ou nouveau modèle. Il connaît seulement le passé. Avant une mise en production, vous vérifiez donc aussi un petit ensemble de billets avec un modèle réel. Le module 6 ajoute cette vérification comme test facultatif. Le coût de la simulation est le travail d’enregistrement des réponses, puis leur nouvel enregistrement quand une requête change.

  1. Analysez le billet T-80001 :

    Fenêtre de terminal
    python -m assistant analyse T-80001

    Tom pose une question sur la commande de son voisin, LK-615204. La réponse contient "needs_human": true (intervention humaine nécessaire) et indique que l’équipe ne peut pas partager les détails de livraison d’autrui. La dernière ligne se termine par 1054 tokens in, 211 out | 2.523 s when it was recorded (1 054 jetons d’entrée, 211 de sortie; 2,523 s lors de l’enregistrement).

  2. Analysez le billet T-80006. Ce billet ne contient aucun texte, seulement une pièce jointe, IMG_2041.jpg.

    La réponse contient "needs_human": true et "confidence": "low" (confiance faible). La raison nomme la règle concernant l’absence de demande lisible.

  3. Analysez le billet T-80005, un billet en français au sujet d’un hamac.

    La réponse contient "language": "fr" (langue française), et le texte de réponse est en français.

  4. Analysez un billet qui n’existe pas : python -m assistant analyse T-99999.

    La sortie est No ticket T-99999 in tickets.csv (aucun billet T-99999 dans tickets.csv). Rien d’autre ne s’affiche.

Afficher la sortie complète de l’étape 2
{
"language": "en",
"team": "account",
"needs_human": true,
"reason": "The ticket contains no readable request, so the team cannot be determined and a person must review it under the no-readable-request rule.",
"confidence": "low",
"order": null,
"reply": "We received your attachment, but we can’t view it here and your message didn’t include any details. Please describe what you need help with, and we’ll direct your request to the right team."
}
gpt-6-luna-2026-09-22 | finish_reason: stop | 1020 tokens in, 285 out | 2.473 s when it was recorded

Le modèle devait choisir une équipe; il a donc choisi account (compte), avec une confiance faible. Le TermeJeu de testUn ensemble fixe d’exemples dont on connaît les bonnes réponses. Chaque version d’un prompt ou d’un modèle passe sur le même ensemble, pour comparer les résultats équitablement.En savoir plus Créer un jeu de test représentatifLes LLM : comment ils fonctionnent et comment en choisir un de TermeGraceLa responsable du service d’assistance de Larkfield. Elle écrit la politique de support et décide ce qu’est une bonne réponse à un client. n’attribue aucune équipe à ce billet : une personne décide.

Ouvrez assistant/prompts/v1.md. Dans la première ligne après [system], remplacez « the customer’s ticket. » par « the customer’s ticket carefully. ». Enregistrez le fichier. Avant toute exécution, faites une prédiction : qu’affiche maintenant python -m assistant analyse T-80008? Et les tests?

Afficher la réponse

La commande s’arrête avec une erreur. La dernière ligne est :

assistant.providers.RecordingNotFound: No recording for this request (key 27a68d8d70e9b11a). The mock replays only the requests that were recorded for the course: check the ticket ID, the prompt version and the model.

Le message système a changé, donc la requête a changé, donc la clé a changé : 27a68d8d70e9b11a au lieu de 3b337102809abc06. Aucun enregistrement n’a cette clé. python -m pytest indique 1 failed, 1 passed (1 test échoué, 1 réussi) : le test du premier essai échoue pour la même raison.

C’est la doublure face à une réplique absente du texte. C’est utile : le fournisseur simulé vous indique immédiatement que la requête n’est pas celle qui a été enregistrée. Annulez la modification, enregistrez et relancez la commande. La ligne attendue est de retour.

Erreur courante

No module named assistant (aucun module nommé assistant)

Symptôme : vous exécutez python -m assistant analyse T-80008 et voyez :

/Users/amira/projects/ticket-assistant/.venv/bin/python: No module named assistant

Cause : le terminal n’est pas dans le dossier du projet. python -m assistant cherche le paquet assistant dans le dossier courant. Ici, la commande s’est exécutée depuis ~/projects, un niveau trop haut. Un message semblable, No module named pytest (aucun module nommé pytest), signifie que l’environnement n’est pas actif : le Python de l’ordinateur n’a pas pytest.

Solution :

  1. Allez dans le projet : cd ~/projects/ticket-assistant.
  2. Vérifiez que l’invite commence par (.venv). Sinon, activez de nouveau l’environnement (étape 2).
  3. Relancez la commande.

Si elle échoue encore, réinitialisez le projet.

Si le projet cesse de fonctionner et que vous ne trouvez pas pourquoi, recommencez à partir de l’instantané. Votre ancien dossier reste, sous un nouveau nom, donc vous ne perdez rien.

  1. Désactivez l’environnement et allez dans votre dossier de projets :

    Fenêtre de terminal
    deactivate
    cd ~/projects
  2. Renommez votre projet :

    Fenêtre de terminal
    mv ticket-assistant ticket-assistant-old
  3. Recopiez l’instantané, comme à l’étape 1, point 3.

  4. Créez un nouvel environnement et installez les paquets, comme à l’étape 2.

  5. Exécutez les deux vérifications de l’étape 3.

Les modules suivants utilisent les mêmes étapes avec leur propre instantané, par exemple end-of-m01 au début du module 2.

Vérifiez votre compréhension

Qu'est-ce qu'un fournisseur simulé, et pourquoi le cours en utilise-t-il un pour chaque test?

Afficher la réponse

Un fournisseur simulé imite un vrai fournisseur. Il n’appelle pas de modèle : il renvoie une vraie réponse enregistrée pour exactement la même requête. Le cours l’utilise pour les tests parce qu’il est gratuit, sans compte ni réseau, et donne toujours la même réponse. Un vrai modèle répond différemment à une même requête, donc un test ne pourrait pas vérifier une sortie exacte.

Vérifiez votre compréhension

Faites une prédiction : vous remplacez chat-small par chat-strong dans la requête et exécutez T-80008 avec le fournisseur simulé. Que se passe-t-il, et pourquoi?

Afficher la réponse

Le fournisseur simulé renvoie une autre réponse enregistrée, provenant de chat-strong. Le nom du modèle fait partie de la clé de requête, donc la clé change. Le cours a enregistré les 69 billets avec chat-small et chat-strong; un enregistrement avec la nouvelle clé existe donc. Avec un nom de modèle jamais enregistré, le fournisseur simulé déclenche RecordingNotFound.

Vérifiez votre compréhension

Votre premier essai affiche une réponse JSON pour T-80008, mais la dernière ligne indique 1 641 jetons d'entrée. Qu'est-ce que cela vous apprend?

Afficher la réponse

La requête n’est pas celle de l’instantané de départ. Plus de jetons d’entrée signifie une requête plus longue : par exemple, une version ultérieure de la requête. Le projet est probablement un instantané plus récent, ou le code a changé. Vérifiez que vous avez copié start, ou réinitialisez le projet.

Récapitulatif

  • Le projet ticket-assistant provient du dépôt des laboratoires sous forme d’instantanés. Vous copiez start et travaillez dans votre copie.
  • Un objet simulé imite un vrai composant. Le fournisseur simulé renvoie de vraies réponses enregistrées, trouvées grâce à une clé de requête : un hachage du modèle, des messages et des paramètres.
  • Le premier essai avec une sortie connue : python -m pytest donne 2 passed, et python -m assistant analyse T-80008 se termine par 1032 tokens in, 241 out | 2.678 s when it was recorded (1 032 jetons d’entrée, 241 de sortie; 2,678 s lors de l’enregistrement).
  • Un seul caractère modifié dans une requête donne une nouvelle clé et RecordingNotFound. Cela montre immédiatement qu’une requête a changé.
  • Si une vérification échoue, examinez d’abord le dossier et l’invite (.venv). Si elle échoue encore, renommez votre projet et recopiez l’instantané.

Ensuite, vous ouvrez la requête et la réponse, champ par champ.

Leçon suivante : Les éléments d'une requête