Evals avec Claude : définir et mesurer la qualité avant la mise en production

Deuxième article de la série « Production Engineering, Evals & Security avec Claude ».

Une application basée sur Claude peut produire dix réponses convaincantes d’affilée et pourtant ne pas être prête pour la production.

Le problème est simple : « ça a l’air de fonctionner » n’est pas une métrique.

Pour passer d’un prototype à un système que l’on peut réellement maintenir, comparer et faire évoluer, il faut définir ce que signifie « fonctionner correctement », puis le mesurer sur un ensemble de cas reproductibles.

C’est précisément le rôle des evals.

Dans le module Production Engineering, Evals & Security, Anthropic présente l’eval comme le mécanisme permettant de transformer une appréciation subjective en score mesurable sur un ensemble fixe de cas.


Qu’est-ce qu’une eval ?

Une eval est un ensemble de :

inputs
+
expected behaviors
+
grading

permettant de mesurer le comportement d’une fonctionnalité.

Le principe général est :

Dataset
   │
   ↓
Application / Claude
   │
   ↓
Output
   │
   ↓
Grader
   │
   ↓
Score

Chaque cas possède au minimum :

Input
→ ce que reçoit le système

Expected behavior
→ ce qu'il devrait produire

Output
→ ce qu'il produit réellement

Grade
→ dans quelle mesure le résultat satisfait l'attente

On exécute ensuite tous les cas et on agrège leurs scores.

Une version minimale pourrait conceptuellement ressembler à :

def run_test_case(test_case):
    output = run_prompt(test_case)

    score = grade(
        test_case,
        output
    )

    return {
        "output": output,
        "test_case": test_case,
        "score": score
    }


def run_eval(dataset):
    results = [
        run_test_case(case)
        for case in dataset
    ]

    average = (
        sum(r["score"] for r in results)
        / len(results)
    )

    return results, average

Ce code n’améliore pas Claude.

Il mesure simplement le comportement du système.

C’est une distinction essentielle.


Une eval ne corrige pas le système

Anthropic utilise dans le document une analogie particulièrement utile : l’eval fonctionne comme un thermomètre.

Un thermomètre ne soigne pas un patient.

Il permet de mesurer son état.

De la même manière :

eval
≠
solution au problème

Une eval permet de détecter :

régression
cas limite
mauvaise instruction
problème de retrieval
problème de contexte
différence entre modèles

Mais la correction peut se trouver ailleurs :

prompt
retrieval
tool
model
architecture
context management

C’est pourquoi un mauvais score est avant tout une information permettant d’orienter l’analyse.


Pourquoi écrire les evals avant l’implémentation ?

C’est l’une des idées importantes du module.

Avant d’écrire le système, il faut définir :

À quoi ressemble un résultat correct ?

Prenons une fonctionnalité de résumé.

Une spécification comme :

« Résumer correctement la conversation »

est beaucoup trop vague.

Comment déterminer automatiquement si le système respecte cette exigence ?

En revanche :

« Produire un résumé de deux phrases mentionnant le problème rencontré et son statut actuel. »

devient vérifiable.

Par exemple :

{
  "input": "Long support thread about a delayed refund...",
  "expected_behavior":
    "A 2-sentence summary naming the issue (delayed refund) and the current status (escalated)."
}

On peut maintenant construire un grader autour de ce comportement attendu.


Le design document vient avant l’eval

Le document source va même un cran plus loin : avant la production, Anthropic recommande de formaliser un design document contenant quatre décisions.

DécisionQuestion
Success criteriaQue doit produire le système ?
Failure handlingQuelles défaillances doit-il supporter ?
Cost & latency budgetQuelles limites doit-il respecter ?
Trust boundaryQuelles données et actions sont autorisées ?

Pour les evals, la première partie est fondamentale :

Success criteria
       ↓
Expected behaviors
       ↓
Eval cases
       ↓
Grading
       ↓
Score

Cela évite un problème classique avec les LLM : modifier les critères après avoir vu les réponses du modèle.

Si le résultat est déjà devant nous, il est très facile de rationaliser :

« Ce n’est pas exactement ce qu’on avait demandé, mais finalement cette réponse est acceptable. »

L’eval définie avant l’implémentation limite ce biais.


Les trois grandes méthodes de grading

Tous les outputs ne doivent pas être évalués de la même manière.

Le document distingue trois méthodes principales :

  1. exact/string match
  2. code-graded check
  3. LLM-as-judge

Le choix dépend de la forme du résultat attendu.


1. Exact match : lorsqu’il existe une seule réponse correcte

Supposons que Claude doive classifier un message parmi :

billing
technical
sales

Le résultat attendu est :

billing

On peut simplement tester :

def grade(expected, output):
    return 10 if output == expected else 0

C’est :

  • rapide ;
  • déterministe ;
  • très peu coûteux ;
  • simple à exécuter à grande échelle.

Pour une classification ou une valeur précisément définie, c’est souvent la meilleure solution.


Le piège de l’exact match

Supposons maintenant qu’on demande trois villes sous forme de tableau JSON.

Référence :

[
  "Paris",
  "Lyon",
  "Marseille"
]

Claude retourne :

[
  "Marseille",
  "Paris",
  "Lyon"
]

Si l’ordre n’a aucune importance, la réponse est correcte.

Pourtant un exact match caractère par caractère échoue.

Le grader est donc trop strict.

Le problème n’est pas le modèle.

Le problème est le choix du grader.


2. Code grader : vérifier une propriété plutôt qu’une chaîne exacte

Lorsque le résultat doit respecter des contraintes structurelles, il est souvent préférable d’écrire du code.

Par exemple :

import json

def validate_json(text):
    try:
        json.loads(text.strip())
        return 10
    except json.JSONDecodeError:
        return 0

Pour du Python :

import ast

def validate_python(text):
    try:
        ast.parse(text.strip())
        return 10
    except SyntaxError:
        return 0

Le grader peut également contrôler :

  • la présence de propriétés obligatoires ;
  • un type ;
  • une plage numérique ;
  • la présence de certaines valeurs ;
  • la validité d’une structure ;
  • l’absence de champs interdits.

Exemple plus réaliste

Imaginons le contrat suivant :

{
  "category": "...",
  "confidence": 0.0
}

On peut vérifier :

def validate_output(text):
    try:
        obj = json.loads(text)

        assert "category" in obj
        assert "confidence" in obj

        assert obj["category"] in {
            "billing",
            "technical",
            "sales"
        }

        assert 0 <= obj["confidence"] <= 1

        return 10

    except (ValueError, AssertionError):
        return 0

Ici, plusieurs outputs différents peuvent être acceptables.

On vérifie le contrat, pas une chaîne de caractères.


Ce qu’un code grader ne sait pas mesurer

Supposons maintenant qu’on demande :

« Explique pourquoi cette architecture est appropriée pour cette application. »

On pourrait vérifier :

len(output) > 0

Mais cela ne dit absolument pas si l’explication est :

  • correcte ;
  • pertinente ;
  • complète ;
  • fidèle au contexte ;
  • bien argumentée.

C’est là qu’intervient le troisième type de grader.


3. LLM-as-a-judge : évaluer une réponse ouverte

Le LLM-as-judge consiste à utiliser un second appel à un modèle pour évaluer le résultat du premier.

Architecture :

           Task
             │
             ↓
          Claude
             │
             ↓
          Output
             │
             ↓
     ┌────────────────┐
     │  Judge model   │
     │ + evaluation   │
     │    rubric      │
     └────────────────┘
             │
             ↓
           Score

Cette méthode devient utile lorsqu’on veut mesurer :

faithfulness
completeness
instruction following
quality
tone

et que ces propriétés ne peuvent pas être exprimées par une simple règle de code.


Construire le prompt du judge

Le document donne le principe suivant : le judge ne devrait pas uniquement retourner un nombre.

Il est préférable de demander :

{
  "strengths": [],
  "weaknesses": [],
  "reasoning": "...",
  "score": 8
}

Conceptuellement :

def grade_by_model(task, solution):

    eval_prompt = f"""
    You are an expert reviewer.

    Evaluate the solution for the task.

    Task:
    {task}

    Solution:
    {solution}

    Return JSON with:

    "strengths": array of 1-3 points
    "weaknesses": array of 1-3 points
    "reasoning": one to two sentences
    "score": number from 1 to 10
    """

    result = chat([
        {
            "role": "user",
            "content": eval_prompt
        }
    ])

    return json.loads(result)

Le raisonnement demandé au judge permet d’ancrer davantage son score dans des critères explicites.


Un LLM-as-a-judge n’est pas automatiquement fiable

C’est probablement le point le plus important concernant cette technique.

Il serait tentant de penser :

Claude produit une réponse
        ↓
un autre modèle donne 8.7/10
        ↓
donc qualité = 8.7

Non.

Un nombre produit par un autre LLM reste un résultat probabiliste.

Le document insiste donc sur la calibration du judge.


Calibrer le judge avec des évaluations humaines

Il faut commencer avec un ensemble de réponses déjà évaluées par des humains.

Par exemple :

CasScore humain
A9
B3
C8
D5
E2

On demande ensuite au judge d’évaluer exactement les mêmes réponses :

CasHumainJudge
A98
B34
C88
D56
E22

On mesure alors le niveau d’accord.

Conceptuellement :

human labels
      │
      ├───────────────┐
      ↓               ↓
ground truth       LLM judge
                      │
                      ↓
                  judge labels
                      │
      ┌───────────────┘
      ↓
measure agreement

Si l’accord est mauvais, on ne doit pas simplement accepter le judge.

On améliore sa rubric.


Comment améliorer un judge mal calibré ?

Le document recommande notamment de :

  • préciser la signification des scores ;
  • fournir des exemples ;
  • montrer une bonne réponse ;
  • montrer une mauvaise réponse ;
  • puis mesurer à nouveau l’accord avec les humains.

Par exemple, une échelle :

1–3 = mauvaise
4–7 = moyenne
8–10 = bonne

reste relativement vague.

Il est préférable d’expliciter ce que signifie chaque plage selon la tâche.

Le judge dispose alors d’une rubric beaucoup plus précise.


Le coût caché du LLM-as-a-judge

Un exact match coûte pratiquement rien.

Un code grader s’exécute localement et coûte également très peu.

Mais un LLM-as-judge implique :

1 cas d'eval
=
1 exécution du système
+
1 appel supplémentaire au judge

Pour :

1000 eval cases

on peut donc avoir :

1000 appels système
+
1000 appels judge

Le document propose donc une stratégie très intéressante :

Chaque commit
    ↓
exact match
+
code graders

Périodiquement
    ↓
full eval
+
LLM-as-judge

Autrement dit, le type de grader dépend également de la fréquence à laquelle on veut pouvoir exécuter l’eval.


Tableau de décision

Type d’outputGrader recommandé
Label uniqueExact match
Valeur exacteExact match
JSON valideCode grader
Code syntaxiquement valideCode grader
Valeur dans une plageCode grader
Champs obligatoiresCode grader
Résumé fidèleLLM-as-judge
Qualité d’une explicationLLM-as-judge
Respect complexe d’instructionsLLM-as-judge

Raccourci utile pour l’examen :

Une seule forme correcte
→ exact match

Une propriété vérifiable
→ code grader

Une qualité ouverte
→ LLM-as-judge

Coverage : tester davantage de situations

Une eval parfaite sur trois exemples n’est pas nécessairement utile.

Le document insiste sur un autre principe :

Coverage matters more than perfection.

Une vingtaine de cas couvrant différentes situations peut révéler davantage de problèmes que trois cas méticuleusement évalués.

Il faut notamment inclure :

normal cases
edge cases
ambiguous cases
missing information
unexpected formats
long inputs
conflicting information

Claude peut aider à générer des edge cases

Une stratégie proposée dans le module consiste à demander au modèle de rechercher les situations susceptibles de casser l’implémentation actuelle.

Supposons qu’on construise un extracteur de date.

Les tests initiaux contiennent :

"My order was placed on March 3."

Claude peut suggérer des situations comme :

aucune date

deux dates

date relative

date ambiguë

date incorrecte

"next Tuesday"

"March 3 or March 4"

"I ordered March 3
and received it April 12"

Ces cas peuvent ensuite être transformés en véritables exemples d’eval.

Important : le document recommande de spot-checker humainement les cas générés afin de conserver un dataset fiable.


Le cas des deux dates : pourquoi la validation ne suffit pas

Le document présente un exemple particulièrement instructif.

Une fonctionnalité extrait la date de commande depuis un message client.

Pendant le développement, elle fonctionne correctement.

Puis arrive :

“I placed my order on March 3 but did not receive it until April 12.”

Le système extrait :

April 12

comme date de commande.

Le problème est subtil.

La validation vérifie que :

April 12

est bien une date.

Donc :

format valide
✓

champ renseigné
✓

date possible
✓

Pourtant :

valeur correcte
✗

C’est une distinction fondamentale :

La validation peut confirmer que la donnée a la bonne forme sans confirmer qu’il s’agit de la bonne donnée.


Pourquoi le système avait pourtant passé tous les tests ?

Parce que les tests manuels contenaient uniquement :

une phrase
+
une date

Personne n’avait défini le comportement attendu pour :

une phrase
+
deux dates

Le système avait donc réussi tous les tests existants.

Mais les tests existants ne couvraient pas suffisamment le domaine réel.

C’est précisément le problème que doit résoudre une eval correctement construite.


Une régression devient alors impossible à oublier

Une fois le bug découvert, on ajoute :

{
  "input":
    "I placed my order on March 3 but did not receive it until April 12.",

  "expected_behavior":
    "Extract March 3 as the order date."
}

Puis on corrige le système.

Ce cas reste ensuite dans l’eval.

Ainsi, une future modification du :

prompt
model
retrieval
tool

qui réintroduit le bug fait immédiatement baisser le score.

C’est un regression test comportemental.


La boucle d’amélioration

Une bonne stratégie d’amélioration n’est pas :

modifier prompt
+
changer modèle
+
ajouter examples
+
changer retrieval
↓
eval

Si le score passe de :

7.1 → 8.4

on ignore ce qui a réellement provoqué l’amélioration.

Le document recommande donc de changer une variable à la fois.

Baseline
   │
   ↓
Eval
   │
   ↓
Analyse des échecs
   │
   ↓
UNE modification
   │
   ↓
Eval
   │
   ↓
Comparer

Puis :

amélioration ?
   ├── oui → conserver
   └── non → revenir en arrière

C’est une démarche expérimentale.


Ne regardez pas uniquement le score moyen

Supposons :

Version A = 8.2/10
Version B = 8.2/10

On pourrait conclure :

aucun changement

Mais en examinant les résultats individuels :

Version B

+ corrige 3 edge cases
- casse 3 cas fréquents

La moyenne masque complètement cette évolution.

Il faut donc suivre :

aggregate score
+
per-case results

Le diagnostic détaillé est souvent aussi important que le score global.


Une mauvaise eval peut conduire à une mauvaise décision

Une eval n’est pas automatiquement bonne simplement parce qu’elle produit un nombre.

On peut avoir :

dataset non représentatif
+
grader mal choisi
+
judge non calibré
+
coverage insuffisante

et obtenir :

9.4 / 10

Ce nombre peut donner une illusion de rigueur sans mesurer ce qui compte réellement.

La qualité d’une eval dépend donc de trois éléments :

CAS
+
EXPECTED BEHAVIOR
+
GRADER

Les trois doivent correspondre au problème réel.


Exemple d’architecture d’eval complète

Une architecture plus réaliste peut être :

                EVAL DATASET
                     │
       ┌─────────────┼─────────────┐
       ↓             ↓             ↓
   normal         edge          adversarial
   cases          cases           cases
       │             │             │
       └─────────────┼─────────────┘
                     ↓
                 FEATURE
                     │
                     ↓
                   OUTPUT
                     │
          ┌──────────┼──────────┐
          ↓          ↓          ↓
       exact       code       judge
       match       check       rubric
          │          │          │
          └──────────┼──────────┘
                     ↓
                 RESULTS
                     │
          ┌──────────┴──────────┐
          ↓                     ↓
      global score         per-case results

C’est beaucoup plus informatif qu’une série de tests manuels.


Ce qu’il faut retenir pour la certification

1. Une eval définit ce que signifie « done »

input cases
+
expected behaviors
+
grading
=
eval

Elle doit idéalement être pensée avant l’implémentation.

2. Choisir le grader selon la nature de l’output

one correct form
→ exact match

structural rule
→ code grader

open-ended quality
→ LLM-as-judge

3. Un LLM-as-judge doit être calibré

human-labeled cases
        ↓
judge
        ↓
measure agreement

Un score produit par un judge non calibré n’est pas une preuve suffisante de qualité.

4. Coverage > quelques beaux exemples

Inclure notamment les edge cases.

5. Une validation structurelle n’est pas une validation sémantique

valid date
≠
correct date

6. Modifier une variable à la fois

change
→ eval
→ compare

Sinon, on ne sait pas quelle modification a amélioré ou dégradé le système.

7. Examiner les résultats par cas

Une moyenne stable peut cacher plusieurs nouvelles régressions.


Pièges d’examen fréquents

Question : une réponse JSON peut être formulée de plusieurs manières mais doit contenir quatre champs précis. Quel grader privilégier ?

Code-graded check, pas LLM-as-judge.

Question : vous devez évaluer la fidélité de résumés rédigés librement.

LLM-as-judge.

Question : le judge fournit des scores très précis de 1 à 10. Peut-on les utiliser immédiatement comme métrique de production ?

Non. Il faut notamment le calibrer sur des cas évalués humainement et mesurer l’accord.

Question : un extracteur renvoie une date syntaxiquement valide mais correspondant au mauvais événement.

→ Le problème ne peut pas être détecté par une simple validation du format. Il faut un cas d’eval définissant la valeur sémantiquement correcte.

Question : vous modifiez simultanément le modèle, le system prompt et les few-shot examples et le score augmente.

→ Vous ne pouvez pas déterminer quelle modification a provoqué l’amélioration.


À retenir en une phrase

Une eval transforme « cela semble fonctionner » en une mesure reproductible : des cas représentatifs, un comportement attendu et le grader le plus simple capable de mesurer correctement ce comportement.

Le phare info – Média indépendant & critique
Sélectionne, organise, contextualise et partage des contenus pertinents autour d’un thème ou d’une problématique, dans une logique de veille, de transmission et de mise en sens.
Pour cet article, l’intelligence artificielle a été utilisée comme un outil d’aide à l’exploration, à la structuration et à la rédaction. Elle permet de confronter plusieurs angles, de repérer certains biais humains possibles et de faire émerger des points de vigilance. Le curateur humain observe aussi les biais possibles de l’IA, vérifie les éléments essentiels, nuance l’analyse, corrige les formulations fragiles et assume la publication.

Articles liés

Fiche de révision certification — Accelerators & IP Contribution

Cette fiche résume les notions essentielles du module Accelerators & IP Contribution. Le fil conducteur est simple : Un build Claude n’est pas terminé lorsqu’il fonctionne....

Étude de cas : corriger un accelerator Claude mal packagé, mal versionné et mal sécurisé

Un système Claude peut fonctionner parfaitement en démonstration et pourtant être impropre à la production. Le cas cumulatif du module illustre précisément cette situation. L’application : s’exécute...

Applications Claude multi-composants : trust boundaries, least privilege et sécurité

Une application Claude moderne n’est souvent pas constituée d’un seul appel API. Elle peut combiner : une API applicative ; Claude ; un agent ; Claude Code ; un MCP...

Comparer les plateformes Claude : latency, compliance, data residency et total cost

Lorsque plusieurs plateformes permettent d’exécuter Claude, comment choisir ? Une comparaison superficielle pourrait se limiter à : la plateforme la moins chère ; celle que l’équipe connaît...

Model versioning avec Claude : pin what ships, eval gates et rollback

Changer de modèle dans une application Claude peut sembler être une modification minime : model = "new-model" Pourtant, en production, ce changement peut modifier : la qualité...

Le sentier du savoir

De la curiosité à la transmission, explorez les étapes qui permettent de transformer l’information en compréhension durable.

Étape 1 — Construire une culture générale solide

Construire une base solide de connaissances pour comprendre le monde. Relier les faits, les disciplines et les repères essentiels.

Étape 2 — Maîtriser la pensée critique et l’analyse : apprendre à penser contre ses propres certitudes

Apprendre à analyser l’information, repérer les biais et questionner les évidences. Penser par soi-même dans un monde saturé de récits.

Étape 3 – Apprendre à argumenter et à convaincre

Structurer sa pensée pour convaincre sans manipuler. Savoir débattre, nuancer et formuler des idées claires.

Étape 4 – Approfondir un ou plusieurs domaines d’expertise

Explorer un ou plusieurs domaines en profondeur. Passer de la curiosité à la compréhension experte.

Etapes 5 : Devenir polyglotte : élargir sa pensée par les langues

Élargir ses horizons par le langage et les cultures. Penser autrement en changeant de langue.

Étape 6 — Comprendre la méthode scientifique et expérimenter

Comprendre la méthode scientifique et l’expérimentation. Distinguer savoirs établis, hypothèses et croyances.

Étape 7 – Écrire, transTransmission : écrire, transmettre, enseigner

Écrire, expliquer, partager ce que l’on a compris. Transformer le savoir en outil collectif.

Étape 8 — Cultiver l’équilibre corps-esprit pour soutenir l’érudition

Cultiver le corps et l’esprit pour soutenir l’érudition dans le temps. Le savoir durable repose aussi sur l’attention et l’équilibre personnel.