Retour au blog

IA pour débutantsGuide

Testez votre prompt sur 20 cas : notation par correspondance exacte en Python

Construisez un jeu de test de 20 cas, notez un prompt par correspondance exacte avec un court script Python, et voyez si un changement de prompt a réellement aidé.

Par CheapTokens TeamPublié le 7 min de lecture

Couverture : un extrait de code comparant une réponse de modèle à l'étiquette attendue, intitulé Testez votre prompt sur 20 cas
Sur cette page
  1. Construire le jeu de test : 20 messages et la réponse attendue
  2. Le script : envoyer chaque cas, comparer, afficher les ratés
  3. Changez une chose, exécutez à nouveau
  4. Même ensemble, autre modèle : le score tient-il ?
  5. Où la correspondance exacte cesse de fonctionner

Votre prompt a fonctionné sur les deux messages que vous avez essayés. Est-ce que cela signifie qu'il fonctionne ? Pas encore. Exécutez-le sur 20 messages réels avec des réponses connues, comptez combien il en obtient correctement, et lisez ceux qu'il rate. Un court script Python fait le comptage, et lorsque vous modifiez le prompt, le même script vous dit si le changement a aidé au lieu de laisser cela à votre intuition.

La documentation d'Anthropic sur la définition de critères de réussite et la construction d'évaluations (consultée le 7 novembre 2026) le formule à sa manière : rendez les tests spécifiques à votre tâche, incluez les cas délicats, et préférez de nombreuses questions notées automatiquement à quelques-unes notées à la main. Voici la plus petite version de cela que vous pouvez exécuter aujourd'hui.

Quatre étapes : 20 cas sont envoyés au modèle, les réponses sont comparées par correspondance exacte, et vous obtenez un score de précision plus les ratés
La méthode complète : des cas en entrée, un nombre et une liste de ratés en sortie

Construire le jeu de test : 20 messages et la réponse attendue#

Supposons que vous triiez les messages clients en trois catégories : positif, négatif ou mixte. Ouvrez un fichier appelé cases.csv et notez 20 messages que vous pourriez réellement recevoir, chacun avec l'étiquette que vous lui donneriez. Écrivez les étiquettes avant d'exécuter quoi que ce soit. Si vous copiez les réponses du modèle comme « correctes », le test ne peut que être d'accord avec le modèle.

csv
text,label
"Arrived a day early and works perfectly. Thank you!",positive
"The charger stopped working after two days.",negative
"Great screen, but the battery barely lasts until lunch.",mixed
"Support answered in five minutes and fixed it.",positive
"I waited three weeks and nobody replied.",negative
"Oh great, another update that deletes my settings.",negative
"Nice design. Pity about the price.",mixed
"Exactly what I ordered.",positive
"The box was crushed, but the headphones inside are fine and sound great.",mixed
"Refund took 10 days. Never again.",negative
"Love it!!",positive
"Cheaply made, but honestly it does the job for the price.",mixed
"Worst purchase of the year.",negative
"Five stars. Would buy again.",positive
"Fast delivery, wrong colour.",mixed
"It's fine. Not amazing, not terrible.",mixed
"Zero issues in six months of daily use.",positive
"The app crashes every time I open the camera.",negative
"Thanks for nothing.",negative
"Setup was a pain, but once it ran, it's been rock solid.",mixed

Regardez la répartition : 6 positifs, 7 négatifs, 7 mixtes. Les phrases sarcastiques (« Oh super, encore une mise à jour… », « Merci pour rien. ») et celle limite (« C'est bien. Pas génial, pas terrible. ») sont là exprès. Un ensemble composé uniquement de messages évidents obtient 100 % et ne vous apprend rien. Prenez les vrais dans votre propre boîte de réception, vos tickets ou l'export de votre chat ; les cas limites sont ceux que vous savez déjà pénibles.

Pourquoi 20 ? C'est une taille de départ, pas un nombre issu de la documentation (leur exemple utilise 1 000 tweets). Vingt est assez petit pour être écrit à la main en une demi-heure et assez grand pour qu'une réponse chanceuse ne décide pas du score.

Le script : envoyer chaque cas, comparer, afficher les ratés#

Le plan comporte quatre étapes, et le code le suit ligne par ligne.

Remettre en ordre

Mettre la boucle d'évaluation dans l'ordre

  1. Charger les 20 cas depuis le CSV
  2. Envoyer chaque message au modèle avec votre prompt
  3. Comparer la réponse avec votre étiquette
  4. Afficher la précision et les cas qui ont échoué

La boucle ne fonctionne que lorsque les étiquettes existent avant le premier appel au modèle, et les échecs viennent en dernier car ce sont eux que vous lisez et sur lesquels vous agissez.

Installez le SDK avec pip install openai et gardez la clé dans une variable d'environnement appelée CHEAPTOKENS_API_KEY. Toute API compatible OpenAI fonctionne de la même manière ; ici le script pointe vers CheapTokens et GLM-5.3-Flash (les détails de configuration sont dans la documentation).

python
import csv
import os
from openai import OpenAI

client = OpenAI(
    base_url='https://api.cheaptokens.dev/v1',
    api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'zai-org/GLM-5.3-Flash'

PROMPT = (
    'Classify the customer message as positive, negative or mixed. '
    'Answer with one word only.'
)


def ask(text):
    r = client.chat.completions.create(
        model=MODEL,
        temperature=0,
        max_tokens=100,
        messages=[
            {'role': 'system', 'content': PROMPT},
            {'role': 'user', 'content': text},
        ],
    )
    return r.choices[0].message.content or ''


with open('cases.csv', newline='', encoding='utf-8') as f:
    cases = list(csv.DictReader(f))

correct, failed = 0, []
for case in cases:
    got = ask(case['text'])
    ok = got.strip().strip('.').lower() == case['label']
    correct += ok
    if not ok:
        failed.append((case['text'], case['label'], got.strip()))

print(f'Accuracy: {correct}/{len(cases)} = {correct / len(cases):.0%}')
for text, want, got in failed:
    print(f'- {text!r}: expected {want}, got {got!r}')

Trois détails méritent un second regard.

  • temperature=0 garde les réponses aussi stables que possible, afin qu'un changement de score provienne de votre prompt et non du hasard.
  • max_tokens=100 est bien plus que ce dont a besoin une étiquette d'un mot. Si une réponse revient vide ou tronquée, vérifiez finish_reason ; le guide sur finish_reason « length » montre quoi augmenter.
  • La ligne de notation est la recette de la documentation, strip().lower() comparé à la bonne réponse, plus un ajout : elle supprime aussi un point final, car « Négatif. » et « négatif » sont la même réponse pour vous.

Que voyez-vous à l'exécution ? Une ligne de précision, puis une ligne par raté. Supposons que la première exécution affiche ceci :

text
Accuracy: 14/20 = 70%
- 'Oh great, another update that deletes my settings.': expected negative, got 'positive'
- "It's fine. Not amazing, not terrible.": expected mixed, got 'positive'
…

(Les chiffres ici sont une hypothèse pour montrer la forme de la sortie ; les vôtres différeront.) Le sarcasme et les formulations limites sont le genre de messages qu'un prompt court a tendance à rater. L'intérêt est que vous ne devinez plus : vous avez une liste.

Changez une chose, exécutez à nouveau#

Maintenant la partie utile. Lisez les ratés, choisissez une cause, modifiez le prompt à un seul endroit et relancez. Un changement à la fois, sinon vous ne saurez pas quelle modification a fait bouger le score.

Comparer

Prompt v1 → v2 : ajouter une règle et deux exemples

v1

text
Classify the customer message as positive, negative or mixed.
Answer with one word only.

v2

text
Classify the customer message as positive, negative or mixed.
Sarcasm counts as negative. Praise plus a complaint is mixed.
Answer with one word only.

Message: Lovely colour, but it arrived with a scratch.
Answer: mixed

Message: Sure, thanks a lot. Now my order is lost.
Answer: negative

Les deux exemples sont inventés, et c'est délibéré. Ne mettez jamais un message de cases.csv dans le prompt comme exemple : le modèle serait alors noté sur une réponse que vous lui avez fournie, et le score serait gonflé. C'est la technique few-shot ; le jeu de test est ce qui vous dit si elle a payé. Si votre prompt v1 est encore vague, comment écrire un bon prompt est l'endroit où commencer avant de mesurer.

Collez v2 dans PROMPT (les triples guillemets fonctionnent pour plusieurs lignes) et relancez le script. Supposons qu'il affiche Accuracy: 17/20 = 85%. Trois cas de plus sont corrects, donc v2 semble meilleur. À quel point faire confiance à cela ? Chaque cas vaut 5 points dans un ensemble de 20, donc 70 % → 85 % représente trois messages. C'est un bon indice, pas une preuve. Si le score baisse, vous avez appris quelque chose d'aussi précieux et vous vous êtes évité de livrer un prompt moins bon.

Même ensemble, autre modèle : le score tient-il ?#

Le même fichier répond à une deuxième question : payez-vous pour plus de modèle que cette tâche n'en a besoin ? Changez une ligne et relancez :

python
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'

Si la précision sur vos 20 cas correspond, vous avez votre réponse pour cette tâche, à partir de vos propres données plutôt que d'un classement. Si elle baisse, regardez quels messages ont échoué avant de décider quoi que ce soit.

Combien tout cela coûte-t-il ? Supposez environ 150 tokens d'entrée par cas (l'instruction plus le message) et environ 5 tokens de sortie pour une étiquette d'un mot. Cela fait 3 000 tokens d'entrée et 100 de sortie par exécution de 20 cas, soit $0.000064 sur GLM-5.3-Flash. Dix ré-exécutions de l'ensemble représentent 200 requêtes ; le tableau ci-dessous montre cette charge de travail pour chaque modèle, avec OpenRouter à côté. À cette charge, en comptant l'entrée et la sortie ensemble, chaque modèle du tableau coûte moins que le prix de référence d'OpenRouter.

Modèle Par requête 200 requêtes OpenRouter, 200 requêtes
GLM-5.3-Flash $0.0000032 $0.00064 $0.0011
DeepSeek-V4-Flash $0.0000028 $0.00055 $0.0022
MiniMax-M2.7 $0.0000083 $0.0017 $0.0198

150 tokens d'entrée et 5 tokens de sortie par requête. Les prix par million de tokens sont actuels et évoluent avec nos tarifs ; la colonne OpenRouter indique des prix de référence pour la même charge de travail.

Deux d'entre eux sont utilisés dans cet article : GLM-5.3-Flash a un contexte de 390K et jusqu'à 8 192 tokens de sortie par réponse ; DeepSeek-V4-Flash a un contexte de 380K et jusqu'à 32 768 tokens de sortie, un prix unique à toute heure de la journée, et le même solde que tous les autres modèles. Les prix actuels sont sur la page de tarification, la liste complète est dans models.

Où la correspondance exacte cesse de fonctionner#

La correspondance exacte fonctionne parce que la bonne réponse est un mot d'une liste fixe. Pour une sortie ouverte comme des résumés, des réécritures ou des explications, il n'y a pas une seule chaîne à comparer. La documentation décrit une autre voie, la notation par un modèle, et recommande d'utiliser un modèle différent comme correcteur de celui qui a écrit la réponse. Commencez quand même par la correspondance exacte : partout où vous pouvez forcer une réponse courte et fixe, c'est le test le moins cher et le plus clair que vous puissiez exécuter. La règle empirique de la documentation est que plus de questions notées automatiquement valent mieux que moins de questions notées à la main.

Une habitude de plus : quand v2 cesse de s'améliorer, ne continuez pas à peaufiner contre les mêmes 20 messages. Ajoutez 5 à 10 nouveaux, idéalement de vrais ratés de production, et relancez.

Vérification rapide

v2 obtient 17/20 et v1 obtenait 15/20 sur les mêmes cas. Quelle est la conclusion la plus sûre ?

Afficher la réponse

Réponse: v2 semble meilleur, mais deux cas sur 20 est un petit écart : ajoutez de nouveaux cas et relancez

Chaque cas vaut 5 points, donc un écart de deux cas est un signal pour regarder de plus près, pas un verdict. De nouveaux cas que v2 n'a jamais vus sont la prochaine vérification.