Aller au contenu principal
Leçon 4 sur 9 · Évaluation de prompts

Évaluer une classification par code

Leçon 4 sur 9 Mis à jour le 5 novembre 2026 Intermédiaire
Sur cette page
  1. La tâche et le jeu de cas
  2. Un prompt de base
  3. La logique d’évaluation
  4. Un prompt amélioré
  5. Ce que la sortie structurée change
  6. Pourquoi un outil
  7. À vous de jouer
  8. Points clés à retenir

Cette leçon écrit de zéro une évaluation un peu plus réaliste : classer des réclamations de clients dans cinq catégories, parfois deux à la fois. Le notateur n’est plus une égalité de chaînes mais une comparaison d’ensembles ; le prompt passe de 85 % à 100 % en ajoutant des définitions et des exemples ; et la sortie structurée, absente du carnet, règle d’avance le problème du format. La leçon se termine sur ce qui motive la suite du cours : tout écrire soi-même devient vite laborieux.

La tâche et le jeu de cas

Les cinq catégories sont Software Bug, Hardware Malfunction, User Error, Feature Request et Service Outage. « The website is completely down, I can’t access any pages » doit donner Service Outage ; « I think I installed something incorrectly, and now my computer won’t start at all » doit donner User Error et Hardware Malfunction. Le jeu compte vingt réclamations, dont cinq à deux catégories ; la réponse attendue est une liste.

eval_data = [
    {"complaint": "The app crashes every time I try to upload a photo", "golden_answer": ["Software Bug"]},
    {"complaint": "My printer isn't recognized by my computer", "golden_answer": ["Hardware Malfunction"]},
    {"complaint": "I can't figure out how to change my password", "golden_answer": ["User Error"]},
    {"complaint": "The website is completely down, I can't access any pages", "golden_answer": ["Service Outage"]},
    {"complaint": "It would be great if the app had a dark mode option", "golden_answer": ["Feature Request"]},
    {"complaint": "The app is crashing and my phone is overheating", "golden_answer": ["Software Bug", "Hardware Malfunction"]},
    {"complaint": "I think I installed something incorrectly, now my computer won't start at all", "golden_answer": ["User Error", "Hardware Malfunction"]},
    {"complaint": "Your service is down, and I urgently need a feature to batch process files", "golden_answer": ["Service Outage", "Feature Request"]},
    {"complaint": "Can you make the interface more user-friendly? I always get lost in the menus", "golden_answer": ["Feature Request", "User Error"]},
    {"complaint": "The cloud storage isn't syncing and I can't access my files from other devices", "golden_answer": ["Software Bug", "Service Outage"]},
    # … dix autres réclamations à une seule catégorie dans le carnet
]

Un prompt de base

def basic_prompt(complaint):
    return f"""
    Classify the following customer complaint into one or more of these categories:
    Software Bug, Hardware Malfunction, User Error, Feature Request, or Service Outage.
    Only respond with the matching category or categories and nothing else.

    Complaint: {complaint}

    Classification:
    """

La logique d’évaluation

Trois fonctions : l’appel au modèle, le calcul de l’exactitude, et l’orchestration qui affiche chaque réclamation avec la réponse attendue et la réponse obtenue. La différence avec la leçon précédente tient dans calculate_accuracy : la réponse du modèle est découpée sur les virgules, normalisée, puis comparée à l’attendu en tant qu’ensemble, pour que l’ordre des catégories ne compte pas.

from anthropic import Anthropic

client = Anthropic()

def get_model_response(prompt, model_name):
    response = client.messages.create(model=model_name, max_tokens=1024,
                                      messages=[{"role": "user", "content": prompt}])
    return next(block.text for block in response.content if block.type == "text")  # un bloc de réflexion peut venir avant

def calculate_accuracy(eval_data, model_responses):
    correct = 0
    for item, response in zip(eval_data, model_responses):
        golden_set = {c.lower() for c in item["golden_answer"]}
        prediction_set = {c.strip().lower() for c in response.split(",")}
        if golden_set == prediction_set:
            correct += 1
    return correct / len(eval_data)

def evaluate_prompt(prompt_func, eval_data, model_name):
    print(f"Evaluating with model: {model_name}")
    responses = [get_model_response(prompt_func(item["complaint"]), model_name) for item in eval_data]
    accuracy = calculate_accuracy(eval_data, responses)
    print(f"Accuracy: {accuracy:.2%}")
    for item, response in zip(eval_data, responses):
        print(f"\nComplaint: {item['complaint']}\nGolden Answer: {item['golden_answer']}\nModel Response: {response}")
    return accuracy

evaluate_prompt(basic_prompt, eval_data, model_name="claude-haiku-5-5")

Le carnet obtenait 85 % avec son prompt de base. Les échecs sont instructifs : pour « the app is crashing and my phone is overheating », le modèle a bien trouvé les deux catégories, mais les a écrites sur deux lignes au lieu de les séparer par une virgule, et le découpage sur les virgules a produit un seul élément. Un échec de format, encore, que le notateur compte comme une erreur.

Noter une classification multiple Quatre étapes : la sortie du modèle, le découpage sur les virgules, la normalisation (casse, espaces), la comparaison d'ensembles avec l'attendu ; en 2026, un schéma à valeurs autorisées supprime les deux premières. COMPARER DES ENSEMBLES Noter une classification multiple 1 Sortie « Hardware Malfunction, Software Bug » 2 Découper sur les virgules ; une réponse sur deux lignes donne un seul élément 3 Normaliser strip(), lower() 4 Comparer {software bug, hardware malfunction} == attendu, sans ordre Avec une sortie structurée (categories: list[Literal[…]]), les étapes 2 et 3 disparaissent : le notateur compare des listes, et le modèle ne peut plus inventer une sixième catégorie.
D'après le carnet « Code-graded eval: classification task » (anthropics/courses, carnet archivé) et la page Structured outputs (documentation Claude).

Un prompt amélioré

La seconde version définit chaque catégorie d’une phrase, pose la règle des catégories multiples (« les lister toutes, mais privilégier une seule quand c’est possible ») et donne neuf exemples, dont un à deux catégories et deux formulés avec agacement. Deux coquilles du carnet sont corrigées ci-dessous (un « Complaint » en double dans l’exemple 6, des guillemets autour de la réponse de l’exemple 9) : un exemple mal formé enseigne une mauvaise forme. La réclamation à classer arrive dans une balise.

def improved_prompt(complaint):
    return f"""
    You are an AI assistant specializing in customer support issue classification. Your task is to analyze customer complaints and categorize them into one or more of the following categories:

    1. Software Bug: Issues related to software not functioning as intended.
    2. Hardware Malfunction: Problems with physical devices or components.
    3. User Error: Difficulties arising from user misunderstanding or misuse.
    4. Feature Request: Suggestions for new functionalities or improvements.
    5. Service Outage: System-wide issues affecting service availability.

    Important Guidelines:
    - A complaint may fall into multiple categories. If so, list all that apply but try to prioritize picking a single category when possible.

    Examples:
    1. Complaint: "The app crashes when I try to save my progress."
    Classification: Software Bug

    2. Complaint: "My keyboard isn't working after I spilled coffee on it."
    Classification: Hardware Malfunction

    3. Complaint: "I can't find the login button on your website."
    Classification: User Error

    4. Complaint: "It would be great if your app had a dark mode."
    Classification: Feature Request

    5. Complaint: "None of your services are loading for me or my colleagues."
    Classification: Service Outage

    6. Complaint: "The app breaks every time I try to change my profile picture"
    Classification: Software Bug

    7. Complaint: "The app is acting buggy on my phone and it seems like your website is down, so I'm completely stuck!"
    Classification: Software Bug, Service Outage

    8. Complaint: "Your software makes my computer super laggy and awful, I hate it!"
    Classification: Software Bug

    9. Complaint: "Your dumb app always breaks when I try to do anything with images."
    Classification: Software Bug

    Now, please classify the following customer complaint:

    <complaint>{complaint}</complaint>

    Only respond with the appropriate categories and nothing else.
    Classification:
    """

Le carnet passait à 100 %. Les exemples ont montré au modèle les situations où deux catégories s’imposent et la forme exacte attendue, virgule comprise. La boucle est la même qu’à la leçon 3 : score de référence, lecture des échecs, modification ciblée, nouveau score ; et la même réserve, vingt cas illustrent la méthode sans constituer une évaluation de production.

Ce que la sortie structurée change

Une bonne partie des échecs de ce carnet sont des échecs de forme, pas de jugement. Avec les modèles actuels, on supprime la question à la racine : un schéma dont le champ categories est une liste de valeurs autorisées. Le modèle ne peut plus répondre sur deux lignes ni inventer une sixième catégorie, et le notateur compare des listes, pas du texte.

from typing import Literal
from pydantic import BaseModel

Category = Literal["Software Bug", "Hardware Malfunction", "User Error", "Feature Request", "Service Outage"]

class Classification(BaseModel):
    categories: list[Category]

def get_categories(prompt, model_name):
    response = client.messages.parse(model=model_name, max_tokens=1024,
                                     messages=[{"role": "user", "content": prompt}],
                                     output_format=Classification)
    return response.parsed_output.categories

def calculate_accuracy_structured(eval_data, predictions):
    return sum({c.lower() for c in item["golden_answer"]} == {c.lower() for c in pred}
               for item, pred in zip(eval_data, predictions)) / len(eval_data)

Les exemples restent utiles : ils ne servent plus à obtenir la bonne forme, mais à obtenir le bon jugement sur les cas à deux catégories. C’est exactement ce qu’une évaluation permet de vérifier séparément.

Pourquoi un outil

Cette approche fonctionne, mais tout écrire soi-même est laborieux : collecter, noter, afficher, comparer deux prompts ou deux modèles côte à côte, garder l’historique des exécutions. La suite du cours confie ce travail à promptfoo, un outil libre qui prend des prompts, des fournisseurs et des tests, exécute tout, et présente les résultats dans un tableau de bord. Le jeu de cette leçon y sera porté tel quel à la leçon 6.

À vous de jouer

Mesurer l’effet des exemples. Avec le schéma Classification, lancez le prompt de base et le prompt amélioré sur les vingt cas : le format n’étant plus en jeu, l’écart restant mesure la seule valeur des définitions et des exemples. Retirez l’exemple à deux catégories et relancez.

Changer de métrique. L’exactitude par ensemble est sévère : une réponse qui trouve une catégorie sur deux vaut zéro. Calculez aussi, par cas, précision et rappel sur les catégories, puis la moyenne ; décidez laquelle des deux métriques correspond à votre critère de réussite de la leçon 2.

Sources officielles : 04_code_graded_classification_evals.ipynb (anthropics/courses, archivé) · Structured outputs (documentation Claude) · Define success criteria and build evaluations (documentation Claude)

Points clés à retenir

  • Quand plusieurs réponses sont possibles et que l’ordre ne compte pas, le notateur compare des ensembles, pas des chaînes.
  • Définitions des catégories et exemples bien choisis (cas doubles, formulations agacées) font passer le carnet de 85 % à 100 %.
  • Une bonne part des échecs d’un notateur par code sont des échecs de forme ; un schéma avec des valeurs autorisées les supprime.
  • Afficher chaque cas avec l’attendu et l’obtenu vaut autant que le score : c’est là qu’on voit quoi corriger.
  • Écrire l’outillage soi-même ne passe pas à l’échelle : c’est le rôle de promptfoo dans la suite du cours.