Classification avec promptfoo et assertions intégrées
Sur cette page
Cette leçon porte dans promptfoo l’évaluation de classification des réclamations de la leçon 4. La nouveauté est la notation : plus d’égalité exacte, mais une assertion intégrée qui vérifie que la sortie contient toutes les catégories attendues, dans n’importe quel ordre. Promptfoo en propose des dizaines ; la leçon montre comment les écrire dans le CSV et où trouver la liste complète.
Mise en place
Même départ qu’à la leçon 5 : npx promptfoo@latest init, un fichier de configuration vidé, le fournisseur économique, la clé dans l’environnement.
description: "Complaint Classification Eval"
providers:
- anthropic:messages:claude-haiku-4-5
Les deux prompts de la leçon 4, basic_prompt et improved_prompt, vont dans prompts.py avec la signature documentée par promptfoo (la réclamation se lit dans context["vars"]["complaint"]), et se déclarent par file://prompts.py:basic_prompt et file://prompts.py:improved_prompt.
Des assertions plutôt qu’une égalité
Reprenons un cas du jeu :
{"complaint": "The cloud storage isn't syncing and I can't access my files from other devices",
"golden_answer": ["Software Bug", "Service Outage"]}
Il faut vérifier que la sortie contient « Software Bug » et « Service Outage ». Une égalité exacte échouerait dès que le modèle inverse l’ordre. Promptfoo fournit pour cela des assertions déterministes, parmi lesquelles :
contains: la sortie contient une sous-chaîne ;icontainsignore la casse.contains-all: la sortie contient toutes les sous-chaînes listées ;contains-any, au moins une.equals: égalité exacte ;starts-with: la sortie commence par la chaîne.regex: la sortie correspond à une expression régulière.is-jsonetcontains-json: JSON valide, avec un schéma optionnel ;is-sql,is-xml,contains-sql,contains-xmlpour d’autres formats.javascriptetpython: une fonction à vous, objet de la leçon 7 ;latencyetcostpour des seuils de temps et de prix.
Dans un CSV, la colonne __expected accepte n’importe laquelle, sous la forme type:valeur ; pour contains-all et contains-any, les valeurs sont séparées par des virgules, et une valeur qui contient elle-même une virgule s’entoure de guillemets doublés. Extrait du fichier, dix des vingt lignes :
complaint,__expected
The app crashes every time I try to upload a photo,contains-all:Software Bug
My printer isn't recognized by my computer,contains-all:Hardware Malfunction
I can't figure out how to change my password,contains-all:User Error
The website is completely down I can't access any pages,contains-all:Service Outage
It would be great if the app had a dark mode option,contains-all:Feature Request
"The app is crashing and my phone is overheating","contains-all:Software Bug,Hardware Malfunction"
"I think I installed something incorrectly now my computer won't start at all","contains-all:User Error,Hardware Malfunction"
"Your service is down and I urgently need a feature to batch process files","contains-all:Service Outage,Feature Request"
"Can you make the interface more user-friendly? I always get lost in the menus","contains-all:Feature Request,User Error"
"The cloud storage isn't syncing and I can't access my files from other devices","contains-all:Software Bug,Service Outage"
Une ligne comme la dernière dit : pour cette réclamation, vérifier que la sortie contient à la fois « Software Bug » et « Service Outage ». Plusieurs assertions par ligne sont possibles avec des colonnes __expected1, __expected2…
description: "Complaint Classification Eval"
prompts:
- file://prompts.py:basic_prompt
- file://prompts.py:improved_prompt
providers:
- anthropic:messages:claude-haiku-4-5
tests: file://dataset.csv
Exécuter
npx promptfoo@latest eval
npx promptfoo@latest view
Dans le carnet, basic_prompt obtenait 80 % et improved_prompt 100 % : les exemples ont appris au modèle les situations où deux catégories s’imposent. Le tableau de bord montre, cas par cas, quelle assertion a échoué et sur quelle sortie. Le carnet répète son avertissement : des jeux pédagogiques de vingt lignes ne représentent pas une évaluation réelle, pour laquelle il recommande au moins cent lignes.
Ce que contains-all ne vérifie pas
L’assertion est plus tolérante que la comparaison d’ensembles de la leçon 4 : une sortie qui liste les deux bonnes catégories et une troisième passe contains-all. Si votre critère de réussite exige exactement les bonnes catégories, deux voies : une assertion python qui recompose la comparaison d’ensembles (leçon 7), ou une sortie structurée avec des valeurs autorisées, que promptfoo sait demander au fournisseur, puis une assertion javascript ou python sur le JSON. Choisir l’assertion, c’est traduire le critère de la leçon 2 ; une assertion trop large donne de beaux scores et de mauvaises surprises.
À vous de jouer
Mesurer la tolérance. Ajoutez au jeu trois réclamations ambiguës dont la réponse attendue est une seule catégorie, et observez si improved_prompt en ajoute une seconde. Comptez combien de ces cas passent contains-all alors qu’ils échoueraient à une égalité d’ensembles.
Changer d’assertion. Remplacez contains-all par icontains-all et par regex sur deux lignes, et notez ce que chaque forme tolère. Terminez par un cas où la sortie contient le bon mot dans une phrase fausse (« ce n’est pas un Software Bug ») : lequel de vos notateurs le laisse passer ?
Sources officielles : 06_prompt_foo_code_graded_classification/lesson.ipynb (anthropics/courses, archivé) · Deterministic metrics et Test cases (documentation promptfoo, relue le 5 novembre 2026)
Points clés à retenir
- Une assertion intégrée remplace l’égalité exacte quand la réponse a plusieurs formes valides ;
contains-allvérifie plusieurs sous-chaînes sans ordre. - Dans un CSV,
__expectedprendtype:valeur; les valeurs multiples se séparent par des virgules, les guillemets se doublent. - Promptfoo fournit des assertions de contenu, de format (JSON, SQL, XML), de temps et de coût, et des fonctions à soi.
- Une assertion doit traduire le critère de réussite :
contains-alltolère les catégories en trop, une égalité d’ensembles non. - Cent lignes au moins pour une évaluation réelle ; vingt pour apprendre.