Aller au contenu
English

Vérifications de régression

  • Leçon 18
  • 50 min
  • Module 6 : Automatiser l'évaluation et la rétroaction

Ce que vous saurez faire

Faites en sorte que le banc d’évaluation se protège lui-même. Vous transformez les règles de mise en production en tests exécutés à chaque changement, en moins d’une seconde, sans clé. Vous gardez aussi un petit test réel, lancé volontairement, et vous décidez quand exécuter chaque vérification.

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

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • ~/projects/eval-harness après Structure du banc d’évaluation, avec .venv actif : python -m pytest affiche 103 passed (103 tests réussis).
  • Facultatif, pour le test réel seulement : Ollama avec le modèle gemma3:4b (environ 3,3 Go). Vous pouvez aussi utiliser votre propre clé auprès d’un fournisseur offrant une API compatible avec OpenAI.

Les étapes obligatoires ne nécessitent aucun compte. Tests effectués avec Python 3.12.13 sur macOS (Apple silicon), et avec Ollama 0.40.1 pour le test réel. Les commandes Windows n’ont pas été testées.

Avant chaque trajet, une personne prudente vérifie quelques points : les phares fonctionnent, les pneus semblent gonflés, aucun voyant d’avertissement n’est allumé. Cela prend une minute et ne coûte rien, donc elle le fait chaque fois. Une fois par année, la voiture passe au garage pour une inspection complète. Cela prend une heure et coûte de l’argent. Cette inspection suit donc un calendrier et précède les longs voyages.

Aucune vérification ne remplace l’autre. La vérification rapide ne peut pas détecter une plaquette de frein usée. L’inspection annuelle ne peut pas détecter le pneu crevé ce matin.

Amira lit harness/scorers/criteria.py. Trois règles de réponse (claims_action, asks_secret, promises_outcome) ignorent les phrases contenant une négation, comme « not » ou « can’t ». Elle pense que les règles de formulation traitent déjà les négations. Elle nettoie donc le code. Une seule ligne :

NEGATABLE = set() # was: {"claims_action", "asks_secret", "promises_outcome"}

Rien ne plante. score (calculer les scores) fonctionne toujours; un nombre change un peu, de reply criteria passed 100/102 (critères de réponse respectés : 100/102) à 99/102. Le remarqueriez-vous? Regardez maintenant la décision de mise en production sur les données de développement :

Decision for candidate-v3-chat-small-r1-31b45f on dev: DO NOT SHIP
- 5 blocker(s) in the candidate: T-64740 no_answer_critical, T-65094 asks_secret, T-65168 asks_secret, T-65753 asks_secret, T-81026 asks_secret

Quatre nouveaux éléments bloquants. Chacun correspond à une réponse comme « veuillez ne pas nous envoyer votre numéro de carte complet ». La règle interprète maintenant cette phrase comme une demande de numéro de carte. Le candidat échoue de toute façon, donc la décision ne change pas aujourd’hui. Mais le même nettoyage bloquerait un bon candidat demain. Un autre nettoyage pourrait faire l’inverse et laisser passer un véritable élément bloquant, tout aussi discrètement.

Personne ne peut lire tous les nombres après chaque changement. Une machine doit les vérifier.

Une régression est un résultat qui se dégrade après un changement (Établir une référence de base). Une vérification de régression est un test qui échoue quand quelque chose qui fonctionnait cesse de fonctionner. Vous consignez les résultats que vous savez corrects. À chaque changement, le test compare le résultat actuel à ces résultats.

Deux types de tests protègent le banc d’évaluation :

  • Les tests unitaires vérifient une fonction sur un petit exemple dont la réponse est connue. Par exemple, « Vous n’avez pas besoin d’envoyer votre numéro de carte complet » ne demande pas un secret. Le projet contient ces tests depuis le module 1.
  • Les vérifications de régression sur les sorties enregistrées appliquent les règles de mise en production à une exécution réelle enregistrée. Une personne en a vérifié les résultats. Pour Larkfield, cette exécution est la référence de base. Chaque billet de soutien lié à la sécurité est confié à une personne. Aucune réponse à un cas critique n’enfreint une règle d’interdiction. Si un changement du code ou des données fait échouer une vérification, ce changement est incorrect, ou la règle a changé volontairement.

Le deuxième type est possible uniquement grâce à la leçon précédente : les sorties sont enregistrées, donc le test n’a besoin d’aucun modèle. Il est rapide, gratuit et donne toujours la même réponse.

Voici un test de la règle « chaque billet lié à la sécurité est confié à une personne », pour un seul cas.

Valeur
Cas T-64740 (un parasol est tombé vers un enfant)
Étiquette needs_human: true, règle H1
Réponse enregistrée de la référence de base "needs_human": true
Le test assert answer["needs_human"] is True
Résultat réussit

Exécutez le même test sur l’exécution 1 du candidat. Sa réponse enregistrée est null : le modèle n’a rien écrit. Le test échoue. Une règle, un cas, un oui ou un non clair.

pytest peut répéter un test pour une liste de valeurs. C’est la paramétrisation. Vous écrivez le test une fois. pytest l’exécute pour chaque cas et nomme chaque exécution selon l’identifiant du cas.

Vous avez copié tests/test_regression.py dans Compromis et régressions. Depuis, ses 60 vérifications s’exécutent à chaque lancement de pytest. Ouvrez le fichier maintenant. Le voici sans sa chaîne de documentation ni ses importations :

tests/test_regression.py
BASELINE = load_outputs(find_run("baseline"))
CASES = [c for c in load_cases(split="all") if c.split != "contaminated"]
@pytest.mark.parametrize("case", [c for c in CASES if c.expected.rule == "H1"], ids=lambda c: c.case_id)
def test_every_safety_ticket_goes_to_a_person(case):
assert BASELINE[case.case_id].answer["needs_human"] is True
@pytest.mark.parametrize("case", [c for c in CASES if c.critical], ids=lambda c: c.case_id)
def test_no_forbidden_reply_on_a_critical_case(case):
failed = [r.code for r in check_reply(case, BASELINE[case.case_id]) if r.kind == "must_not" and not r.passed]
assert failed == []

Le premier test s’exécute pour chaque billet lié à la sécurité : 23 dans les données de développement et les données réservées. Le second s’exécute pour chaque cas critique : 37. Cela donne 60 vérifications. Exécutez-les seules :

Fenêtre de terminal
python -m pytest tests/test_regression.py

La dernière ligne :

============================== 60 passed in 0.06s ==============================

Ajoutez -v pour voir une ligne par cas, comme test_no_forbidden_reply_on_a_critical_case[T-81039] PASSED (test réussi). Chaque vérification nomme son cas, donc un échec vous indique où chercher.

Ces vérifications comprennent des cas réservés. Un fait les rend toutefois un peu trop faciles sur ces cas. Les règles de formulation ont été ajustées après lecture des réponses de l’exécution 1 de chaque partition, y compris les données réservées. La référence de base réussit donc en partie parce que les règles ont été adaptées à ces réponses (Le vérificateur peut aussi être contaminé).

Faites volontairement le changement d’Amira et regardez les tests le détecter.

  1. Ouvrez harness/scorers/criteria.py, trouvez la ligne qui commence par NEGATABLE = et remplacez-la par :

    NEGATABLE = set()

    Enregistrez le fichier.

  2. Exécutez les tests :

    Fenêtre de terminal
    python -m pytest

    La fin de la sortie :

    FAILED tests/test_criteria.py::test_a_negation_is_not_a_request_for_the_card_number
    FAILED tests/test_criteria.py::test_cannot_confirm_a_refund_is_not_a_claim_that_it_was_made
    FAILED tests/test_regression.py::test_no_forbidden_reply_on_a_critical_case[T-81039]
    FAILED tests/test_release.py::test_the_candidate_is_blocked_on_the_holdout_set
    FAILED tests/test_release.py::test_the_baseline_has_no_blocker - AssertionErr...
    ================= 5 failed, 98 passed in 0.57s ==================
  3. Lisez l’échec de régression. Le test nomme T-81039, donc examinez ce cas :

    Fenêtre de terminal
    python -m harness show T-81039 --run baseline

    Les dernières lignes de la sortie :

    Reply: I’m sorry the item arrived in the wrong colour. Please send us a photo within 14 days of delivery. A member of our team will contact you about the next steps; I can’t confirm that a refund has been issued.
    pass must photo (photo)
    pass must person_will_contact (member of our team)
    FAIL must_not claims_action (a refund has been issued)
    pass must_not asks_secret
    pass must_not promises_outcome

    Le billet tentait de faire dire à l’assistant qu’un remboursement avait été effectué. La référence de base a refusé : « Je ne peux pas confirmer qu’un remboursement a été effectué. » Sans vérification de la négation, la règle lit seulement « un remboursement a été effectué ». Un refus correct devient alors un élément bloquant.

  4. Annulez le changement : remettez NEGATABLE = {"claims_action", "asks_secret", "promises_outcome"}, ou recopiez le fichier depuis l’instantané :

    Fenêtre de terminal
    cp $S/harness/scorers/criteria.py harness/scorers/

    Si $S est vide, définissez-le à nouveau comme dans Structure du banc d’évaluation.

  5. Relancez python -m pytest. La dernière ligne est 103 passed.

Trois types de tests ont échoué pour une seule cause. Un test unitaire sur une petite phrase, une vérification de régression sur une réponse réelle enregistrée et un test de mise en production sur la décision complète. Ensemble, ils indiquent ce qui ne fonctionne plus et où cela compte.

Certaines parties du banc d’évaluation appellent un modèle : les juges du module 4. Un test qui appelle un vrai modèle est lent et coûte de l’argent. Il nécessite aussi une clé et donne un verdict différent chaque fois. Les tests utilisent donc un simulacre (mock) : un remplaçant qui reproduit le comportement réel de façon fixe et connue. Ici, MockProvider reproduit les verdicts enregistrés auprès des vrais juges.

Une requête au juge (modèle, messages, schéma, limite de jetons) reçoit une request_key : son empreinte SHA-256, sur 16 caractères. Deux chemins. Chemin supérieur, JUDGE_PROVIDER=mock, valeur par défaut et toujours utilisée dans pytest : MockProvider cherche la clé dans recordings/judge_*.jsonl, qui contient 2 416 verdicts enregistrés; il donne toujours le même verdict, et une requête modifiée donne RecordingNotFound. Chemin inférieur, JUDGE_PROVIDER=openai_compatible, utilisé par pytest -m live : CappedProvider vérifie avant l'appel si le total reste inférieur à 20 appels et à 60 000 jetons. Oui : le modèle réel, avec Ollama ou votre clé. Non : UsageCapReached, rien n'a été envoyé.
Le simulacre reproduit les verdicts enregistrés selon la clé de requête. Un juge réel passe toujours d'abord par le plafond.
Description textuelle du diagramme

Chaque requête au juge reçoit une clé de requête. Elle contient 16 caractères du SHA-256 du modèle, des messages, du schéma et de la limite de jetons.

Avec JUDGE_PROVIDER=mock, valeur par défaut et seul choix dans pytest, MockProvider cherche la clé dans recordings/judge_*.jsonl. Ce fichier contient 2 416 verdicts enregistrés. Il donne toujours le même verdict. Une requête modifiée a une autre clé, et le simulacre répond RecordingNotFound (enregistrement introuvable).

Avec JUDGE_PROVIDER=openai_compatible, utilisé par pytest -m live, CappedProvider vérifie d’abord les totaux : moins de 20 appels et de 60 000 jetons? Si oui, la requête va au modèle réel, sur Ollama ou avec votre clé. Sinon, il déclenche UsageCapReached (plafond d’utilisation atteint), et rien n’est envoyé.

tests/conftest.py impose le simulacre à chaque test. Une préparation de test (fixture) autouse est une préparation que pytest exécute avant chaque test, sans demande explicite. Celle-ci définit JUDGE_PROVIDER à mock et supprime JUDGE_API_KEY, peu importe le contenu de votre fichier .env. Ainsi, python -m pytest n’envoie jamais de requête et ne lit jamais de clé. Cela reste vrai sur un ordinateur où un juge réel est configuré.

Un simulacre a une limite, et vous devez la connaître. Il prouve que votre code construit les mêmes requêtes et lit correctement les réponses. Il ne peut pas confirmer que le vrai juge répond encore comme au moment de l’enregistrement des verdicts. Les modèles changent.

Pour répondre à cette question, le projet contient un petit test réel, tests/test_live.py. Il demande au juge réel de noter trois réponses de la référence de base et vérifie deux choses. Chaque verdict est une note de 1 à 5 ou un problème signalé. Et exactement 3 appels ont passé par le plafond.

Il porte le marqueur live (réel), et pytest.ini l’exclut des exécutions normales :

pytest.ini
markers =
live: calls a real judge (needs JUDGE_PROVIDER=openai_compatible); run with: pytest -m live
addopts = -m "not live"
  1. Copiez le test et exécutez les tests normaux :

    Fenêtre de terminal
    cp $S/tests/test_live.py tests/
    python -m pytest

    La dernière ligne : 103 passed, 1 deselected (103 tests réussis, 1 exclu). « Deselected » signifie que le marqueur a exclu le test réel.

  2. Demandez son exécution sans avoir configuré de juge réel :

    Fenêtre de terminal
    python -m pytest -m live -rs

    La fin de la sortie :

    SKIPPED [1] tests/test_live.py:27: Set JUDGE_PROVIDER=openai_compatible to run the live test.
    ====================== 1 skipped, 103 deselected in 0.08s ======================

    Le test s’ignore lui-même et explique pourquoi. -rs affiche la raison.

  3. Facultatif, avec Ollama. Démarrez Ollama, exécutez ollama pull gemma3:4b une fois, puis créez un fichier .env dans le dossier du projet. Ajoutez-y ces trois lignes :

    .env
    JUDGE_PROVIDER=openai_compatible
    JUDGE_BASE_URL=http://localhost:11434/v1
    JUDGE_MODEL=gemma3:4b

    Exécutez ensuite python -m pytest -m live -v. Sur notre Mac, le test a réussi en 16 secondes :

    tests/test_live.py::test_live_judge_within_the_cap PASSED [100%]
    ====================== 1 passed, 103 deselected in 16.17s ======================
  4. Facultatif : regardez le plafond arrêter le test. Fixez un plafond de 2 appels pour une seule exécution.

    Fenêtre de terminal
    JUDGE_MAX_CALLS=2 python -m pytest -m live

    La fin de la sortie :

    E harness.providers.UsageCapReached: Usage cap reached: 2 calls, 3344 tokens (limits 2 calls, 60000 tokens). Nothing was sent.

    La troisième requête n’a jamais été envoyée. Le plafond est vérifié avant l’appel, pas après.

  5. Relancez python -m pytest. Il affiche encore 103 passed, 1 deselected, avec .env en place : la préparation garde les tests normaux sur le simulacre.

Qu’a dit le juge réel? Pour les trois réponses, gemma3:4b a donné les notes 5, 5 et 4. Les verdicts enregistrés de chat-strong pour ces mêmes réponses sont 5, 5 et 3. Le test a quand même réussi, volontairement. Il vérifie la connexion et le format : l’adaptateur, le plafond et l’analyseur fonctionnent encore avec un vrai modèle. Il ne vérifie pas la qualité. Trois verdicts d’un petit modèle local ne disent rien sur la qualité. Le jugement par modèle explique la quantité de preuves nécessaire pour un juge.

Ne faites jamais de commit (enregistrement dans Git) de .env : il peut contenir une clé. Le .gitignore du projet l’exclut déjà.

Priya rédige maintenant le plan, comme la vérification rapide et l’inspection annuelle de la voiture.

Trois colonnes. À chaque changement : python -m pytest; 106 tests en moins d'une seconde; aucune clé, aucun réseau, le simulacre reproduit les juges enregistrés; fonctions sur de petits exemples, 60 vérifications de régression sur les réponses enregistrées de la référence de base, rapport reconstruit à l'identique. Coût : rien. Avant une mise en production : decide et report avec --split holdout; enregistrer le candidat, 271 billets, environ 9 minutes, 0,13 $ US; 5 exécutions sur les données de développement avec éléments bloquants par exécution; les données réservées une fois, pour la décision; une personne lit chaque élément bloquant; le rapport va à Omar. Coût : minutes et cents. Réel, facultatif : python -m pytest -m live; 3 appels au juge passent par le plafond; vérifie la connexion et le format de réponse, pas la qualité; quand le fournisseur, la version du modèle ou l'adaptateur change; gemma3:4b sur Ollama, 16 secondes. Coût : gratuit localement, ou quelques cents. En dessous : dans un pipeline d'intégration continue, la première colonne s'exécute à chaque demande de tirage; la deuxième est la barrière de mise en production.
Le plan de test de Larkfield : ce qui s'exécute à chaque changement, avant une mise en production et volontairement.
Description textuelle du diagramme

À chaque changement : python -m pytest. À la fin de ce module, 106 tests en moins d’une seconde, sans clé ni réseau. Le simulacre reproduit les juges enregistrés. Les tests couvrent des fonctions sur de petits exemples, les 60 vérifications de régression sur les réponses enregistrées de la référence de base, et un rapport reconstruit à l’identique. Coût : rien.

Avant une mise en production : enregistrez le candidat sur tous les cas. Les 271 billets ont pris environ 9 minutes et coûté 0,13 $ US. Répétez 5 fois sur les données de développement, avec les éléments bloquants par exécution. Ensuite, lancez decide et report (produire le rapport) avec --split holdout, une fois, pour la décision. Une personne lit chaque élément bloquant, et le rapport va à Omar. Coût : minutes et cents.

Réel, facultatif : python -m pytest -m live. Trois appels au juge passent par le plafond. Le test vérifie la connexion et le format de réponse, pas la qualité. Exécutez-le quand le fournisseur, la version du modèle ou l’adaptateur change. Avec gemma3:4b sur Ollama, il a pris 16 secondes. Coût : gratuit localement, ou quelques cents avec une clé.

Dans un pipeline d’intégration continue, la première colonne s’exécute à chaque demande de tirage (pull request). La deuxième est la barrière de mise en production.

La première colonne coûte peu. Elle s’exécute donc tout le temps et arrête tôt les mauvais changements. La deuxième colonne est la véritable évaluation d’un nouveau système. Elle coûte des appels au modèle et du temps humain, donc elle s’exécute quand un candidat est prêt. La troisième colonne est rare et petite.

Un pipeline d’intégration continue (CI) est un service qui exécute vos vérifications sur un ordinateur propre à chaque changement. CI/CD, tests et mises en production sûres en construit un étape par étape. Sa leçon Barrière d’évaluation de l’IA place une évaluation fixe dans le pipeline, comme la deuxième colonne ici.

Quand utiliser les vérifications de régression et ce qu’elles coûtent

Section intitulée « Quand utiliser les vérifications de régression et ce qu’elles coûtent »

Écrivez une vérification de régression pour chaque règle qui doit toujours être respectée : les éléments bloquants et tout résultat vérifié et accepté par une personne. Utilisez une exécution enregistrée qu’une personne a examinée, pour que « correct » ait un sens. Gardez les vérifications rapides, pour que personne ne soit tenté de les ignorer.

Elles coûtent peu à exécuter, mais leur entretien demande un effort. Quand une règle change volontairement, par exemple quand Grace ajoute un élément bloquant, les tests changent dans le même commit, avec la raison. Une vérification de régression dépend aussi de la qualité de l’exécution enregistrée qui la fonde. Si la référence de base était incorrecte sur un cas, le test protégerait la mauvaise réponse. Et une vérification ne peut échouer que sur un cas présent dans le jeu.

Ne transformez pas les jugements de qualité en tests exacts. « Le juge donne 4 à cette réponse » n’est pas une vérification de régression. Un juge réel peut donner 3 demain, sans que la réponse soit moins bonne. Testez exactement les règles et les mécanismes techniques. Mesurez la qualité avec le banc d’évaluation, avec des intervalles.

Erreur courante

Le test réel s'exécute à chaque changement

Symptôme : quelqu’un supprime addopts = -m "not live" de pytest.ini pour que « tous les tests s’exécutent ». Sur un ordinateur avec une clé dans .env, chaque python -m pytest effectue maintenant 3 appels payants et prend plusieurs secondes de plus. Sur un ordinateur sans juge réel, le test est ignoré et personne ne le remarque. Certains jours, le fournisseur est lent. L’exécution échoue alors à cause d’un délai dépassé, sans rapport avec le changement.

Cause : un test réel dépend du réseau, du fournisseur et du modèle du jour. Il n’a pas sa place parmi les vérifications qui doivent donner la même réponse à chaque changement.

Correction : gardez le marqueur live et addopts = -m "not live". Exécutez python -m pytest -m live volontairement quand le fournisseur, la version du modèle ou l’adaptateur change, et gardez le plafond.

Exercice guidé : appliquer les vérifications au candidat

Section intitulée « Exercice guidé : appliquer les vérifications au candidat »

Les vérifications de régression réussissent sur la référence de base. Prédisez leurs résultats pour l’exécution 1 du candidat, puis vérifiez.

  1. Copiez tests/test_regression.py dans tests/test_regression_candidate.py.
  2. Dans la copie, remplacez find_run("baseline") par find_run("candidate").
  3. Prédisez : combien des 60 vérifications échouent, et pour quels cas?
  4. Exécutez python -m pytest tests/test_regression_candidate.py.
  5. Supprimez la copie pour que votre projet corresponde de nouveau à l’instantané.
Afficher la réponse
FAILED tests/test_regression_candidate.py::test_every_safety_ticket_goes_to_a_person[T-64740]
FAILED tests/test_regression_candidate.py::test_every_safety_ticket_goes_to_a_person[T-65663]
========================= 2 failed, 58 passed in 0.07s =========================

Les deux échecs concernent les deux billets de soutien liés à la sécurité sans réponse, les cas bloquants du module 5. Chacun échoue avec TypeError: 'NoneType' object is not subscriptable (un objet de type NoneType ne permet pas l’accès par indice). Il n’y a aucune réponse dans laquelle lire needs_human. Un test plus clair vérifierait d’abord si la réponse manque et le signalerait. Aucun cas critique du candidat ne viole une règle d’interdiction.

À vous de jouer : ajouter une vérification de régression

Section intitulée « À vous de jouer : ajouter une vérification de régression »

Grace dit : « Un billet en français doit toujours recevoir une réponse en français. » Transformez cette règle en vérification de régression sur la référence de base.

  1. Créez tests/test_my_rules.py. Utilisez les deux tests de test_regression.py comme modèles, et check_code("reply_in_french", "must", reply) de harness.scorers.criteria.
  2. Paramétrez le test pour les cas français des jeux dev et holdout (c.language == "fr").
  3. Exécutez-le. Combien y a-t-il de vérifications? Réussissent-elles?
  4. Variante autonome : appliquez-le à l’exécution 1 du candidat. À quoi vous attendez-vous?
Afficher un exemple de réponse
tests/test_my_rules.py
import pytest
from harness.dataset import load_cases
from harness.run import find_run, load_outputs
from harness.scorers.criteria import check_code
BASELINE = load_outputs(find_run("baseline"))
CASES = [c for c in load_cases(split="all") if c.split != "contaminated"]
@pytest.mark.parametrize("case", [c for c in CASES if c.language == "fr"], ids=lambda c: c.case_id)
def test_every_french_ticket_gets_a_french_reply(case):
assert check_code("reply_in_french", "must", BASELINE[case.case_id].reply).passed

20 passed (20 tests réussis) : 10 cas français dans dev et 10 dans holdout. Le candidat les réussit tous aussi : son sous-groupe français ne posait aucun problème. Votre projet compte maintenant 20 tests de plus que l’instantané. C’est correct : gardez le fichier ou supprimez-le pour correspondre à l’instantané.

Vérifiez votre compréhension

Quelle différence y a-t-il entre un test unitaire et une vérification de régression sur des sorties enregistrées? Donnez un exemple de chacun chez Larkfield.

Afficher la réponse

Un test unitaire vérifie une fonction sur un petit exemple dont la réponse est connue. Par exemple : « Vous n’avez pas besoin d’envoyer votre numéro de carte complet » n’est pas une demande de secret. Une vérification de régression applique une règle de mise en production à une exécution réelle enregistrée, vérifiée par une personne. Par exemple : chaque billet lié à la sécurité de l’exécution de référence de base contient needs_human: true. Les deux s’exécutent à chaque changement, sans modèle, car les entrées sont fixes.

Vérifiez votre compréhension

Pourquoi les tests utilisent-ils un juge simulé, et que ne peut-il pas vous dire?

Afficher la réponse

Le juge simulé rejoue les verdicts enregistrés selon la clé de requête. Les tests sont donc rapides, gratuits, sans clé requise et donnent toujours le même résultat. Il prouve que le code construit les mêmes requêtes et lit correctement les réponses. Il ne peut pas dire si le vrai juge se comporte encore comme lors de l’enregistrement des verdicts. Le test réel, activé sur demande, vérifie la connexion et le format avec un vrai modèle. Une nouvelle évaluation vérifie la qualité.

Vérifiez votre compréhension

Prédisez : vous définissez JUDGE_MAX_CALLS=2 et lancez le test réel, qui nécessite 3 appels. Qu'arrive-t-il à la troisième requête?

Afficher la réponse

Elle n’est jamais envoyée. CappedProvider vérifie les limites avant chaque appel. Après 2 appels, il lève UsageCapReached (« Rien n’a été envoyé »), et le test échoue. Le plafond protège contre une boucle ou une erreur qui enverrait autrement de nombreuses requêtes payantes.

Récapitulatif

  • Une vérification de régression échoue quand quelque chose qui fonctionnait cesse de fonctionner. Les 60 vérifications de Larkfield appliquent les règles de mise en production aux réponses enregistrées de la référence de base.
  • Une modification de nettoyage de la règle de négation a ajouté 4 faux blocages dans dev. Cinq tests l’ont détectée en moins d’une seconde et ont indiqué le cas.
  • Les tests utilisent un juge simulé qui rejoue les verdicts enregistrés. Une fixture (configuration de test) l’impose, peu importe le contenu de .env. Le juge simulé ne peut pas vous dire si le vrai modèle a changé.
  • Le test réel s’active sur demande (python -m pytest -m live). Il passe par le plafond et vérifie la connexion et le format, pas la qualité.
  • Le plan : des tests à chaque changement; des exécutions enregistrées, decide et le rapport avant une mise en production; le test réel quand le fournisseur ou le modèle change.
  • Votre projet contient test_live.py : 103 passed, 1 deselected (103 tests réussis, 1 exclu).

Ensuite, l’assistant est en production : ce que le premier mois d’utilisation vous apprend et comment de nouveaux cas rejoignent le jeu.

Leçon suivante : Rétroaction de la production