Aller au contenu principal

Tester ses prompts comme du code : un jeu d'essai plutôt que trois essais à la main

Un prompt validé sur trois exemples dans une interface de chat se comporte souvent autrement une fois branché dans une application. Cet article montre comment construire un petit jeu d'essai en Python, imposer une sortie structurée, mesurer l'effet d'une modification de prompt, et éviter les pièges qui donnent de faux bons scores.

Guides & tutoriels ·
Adel LATIBI
Adel LATIBI

Le Briefing Dev - les ressources et actus de la semaine, droit dans ta boîte chaque vendredi gratuitement.

En vous inscrivant, vous acceptez de recevoir notre newsletter. Désinscription possible à tout moment.

Les grands modèles de langage s'utilisent aujourd'hui dans des outils de support client, des extracteurs de factures, des assistants internes. Derrière chacun de ces outils, il y a un texte d'instructions, le prompt, écrit le plus souvent dans une fenêtre de chat, essayé sur deux ou trois exemples, puis copié dans le code.

Le jour de la mise en ligne, les vrais messages arrivent. Ils sont plus longs, plus flous, mal orthographiés, et le modèle répond parfois de travers sur des cas qui ressemblaient pourtant aux exemples testés. Quelqu'un modifie alors le prompt pour corriger ce cas, sans vérifier que les cas qui marchaient la veille marchent encore.

Un développeur ne livrerait pas une fonction vérifiée sur trois appels à la main. Un prompt mérite le même traitement : un jeu d'essai, une mesure, une comparaison avant chaque changement. La suite montre comment le faire en une centaine de lignes de Python, sans outil payant ni framework.

Le problème : un prompt qui « a l'air de marcher »

Prenons une petite boutique en ligne qui reçoit quelques centaines de messages par semaine. L'objectif : classer chaque message dans une catégorie (facturation, technique, compte, autre) et signaler ceux qui sont urgents, pour que les bons messages arrivent devant les bonnes personnes.

Le premier prompt tient en deux lignes. Essayé dans l'interface de chat sur trois messages, il donne trois bonnes réponses. Branché dans l'application, il répond une fois sur dix par une phrase entière au lieu d'un nom de catégorie, invente une catégorie « livraison » qui n'existe pas, et classe comme non urgent un client qui écrit que le paiement plante et qu'il perd des ventes.

Trois raisons expliquent cet écart. Un modèle ne répond pas toujours la même chose à la même question, donc un essai réussi ne prouve presque rien. Trois exemples choisis par la personne qui écrit le prompt ressemblent toujours à ce qu'elle avait en tête. Et la forme de la réponse, laissée libre, finit par dériver. Aucun de ces problèmes ne se voit à l'œil nu sur trois essais.

Le principe : une sortie contrainte, des cas connus, une mesure

Le test d'un prompt repose sur trois éléments. Une sortie au format imposé, pour pouvoir la comparer automatiquement à une réponse attendue. Un jeu d'essai, c'est-à-dire une liste de messages dont la bonne réponse est connue à l'avance. Et une boucle qui lance le prompt sur tout le jeu, plusieurs fois, et compte les réponses conformes.

Jeu d'essai message + attendu Modèle prompt + schéma imposé Comparaison obtenu == attendu ? Score + échecs à lire on modifie le prompt, on relance tout le jeu
La boucle d'évaluation : chaque modification du prompt est rejugée sur l'ensemble des cas connus.

La sortie structurée est la pièce qui rend le reste possible. L'API d'OpenAI permet de fournir un schéma, ici décrit avec la bibliothèque Pydantic, et le modèle est alors contraint de produire un objet qui respecte ce schéma : les bons champs, les bons types, et une valeur choisie dans la liste autorisée quand le champ en définit une. La catégorie « livraison » inventée devient impossible, et la phrase entière à la place du nom de catégorie aussi.

Le jeu d'essai, lui, ne demande aucune technique. Il demande de la discipline : écrire les cas avant de toucher au prompt, y mettre les messages ambigus plutôt que les évidents, et l'enrichir à chaque erreur constatée en production. Un jeu de vingt cas bien choisis vaut mieux que deux cents cas faciles.

Le code, étape par étape

1. Imposer la forme de la réponse

Le SDK Python d'OpenAI expose la méthode responses.parse, qui accepte un modèle Pydantic et renvoie directement l'objet analysé.

# classer.py
import os
from typing import Literal
 
from openai import OpenAI
from pydantic import BaseModel
 
client = OpenAI()
MODELE = os.environ["OPENAI_MODEL"]
 
 
class Classement(BaseModel):
    categorie: Literal["facturation", "technique", "compte", "autre"]
    urgent: bool
 
 
def classer(message: str, consignes: str) -> Classement:
    reponse = client.responses.parse(
        model=MODELE,
        instructions=consignes,
        input=message,
        text_format=Classement,
    )
    return reponse.output_parsed

Le nom du modèle vient d'une variable d'environnement, au même titre que la clé d'API. C'est un choix délibéré : OpenAI publie de nouveaux modèles plusieurs fois par an, et le jeu d'essai sert justement à vérifier qu'un changement de modèle ne casse rien. Le nom en dur dans le code empêche de faire cette comparaison sans modifier le programme. Les noms disponibles sont listés dans la documentation officielle d'OpenAI, et l'article sur GPT-5.5 et ce qu'il change pour les développeurs donne un exemple de ce que ces changements de version impliquent.

2. Écrire le jeu d'essai avant de retoucher le prompt

# evaluer.py
from classer import classer
 
CAS = [
    ("Ma carte a été débitée deux fois pour la commande 4471.", "facturation", True),
    ("Je n'arrive plus à me connecter depuis ce matin.", "compte", True),
    ("Le bouton Exporter ne fait rien sur Firefox.", "technique", False),
    ("Est-ce que vous livrez en Belgique ?", "autre", False),
    ("Je veux changer l'adresse de facturation de mon compte.", "compte", False),
    ("Votre site affiche une erreur 500 au paiement, je perds des ventes.", "technique", True),
]

Deux cas de cette liste sont piégés exprès. « L'adresse de facturation de mon compte » contient le mot facturation mais relève de la gestion du compte. « Une erreur 500 au paiement » parle de paiement mais décrit une panne technique. Ce sont ces cas-frontières qui départagent deux prompts, beaucoup plus que les messages évidents. La règle qui décide de la bonne réponse doit être écrite quelque part, idéalement dans le prompt lui-même, sinon le jeu d'essai mesure l'accord entre le modèle et une intuition non formulée.

3. Mesurer, en répétant chaque cas

def evaluer(consignes: str, repetitions: int = 3) -> tuple[float, list]:
    echecs = []
    total = 0
    for message, categorie, urgent in CAS:
        for _ in range(repetitions):
            resultat = classer(message, consignes)
            total += 1
            if (resultat.categorie, resultat.urgent) != (categorie, urgent):
                echecs.append((message, resultat.categorie, resultat.urgent))
    return 1 - len(echecs) / total, echecs
 
 
if __name__ == "__main__":
    from consignes import V1, V2
 
    for nom, consignes in [("v1", V1), ("v2", V2)]:
        score, echecs = evaluer(consignes)
        print(f"{nom} : {score:.0%} de réponses conformes")
        for message, categorie, urgent in echecs:
            print(f"   {categorie:<12} urgent={urgent!s:<5} {message}")

La répétition sert à repérer l'instabilité. Un cas qui réussit deux fois sur trois est un cas fragile, et c'est souvent le signe que le prompt laisse une ambiguïté. Le score global intéresse moins que la liste des échecs : c'est elle qu'on lit pour comprendre ce que le modèle a mal compris.

4. Améliorer le prompt en partant des échecs

Le fichier consignes.py contient les versions successives du prompt, ce qui permet de les comparer dans la même exécution et de garder leur historique dans Git.

# consignes.py
V1 = "Classe le message client dans une catégorie et indique s'il est urgent."
 
V2 = """Tu tries les messages du support d'une boutique en ligne.
 
Catégories :
- facturation : paiement, remboursement, facture, double débit.
- technique : un élément du site ou de l'application ne fonctionne pas,
  y compris pendant le paiement.
- compte : connexion, mot de passe, informations personnelles du compte,
  y compris l'adresse de facturation.
- autre : questions générales, livraison, produits.
 
Un message est urgent si le client ne peut plus utiliser le service,
perd de l'argent, ou signale une panne qui touche les ventes."""

La version 2 ne contient aucune formule magique. Elle définit chaque catégorie, tranche explicitement les cas-frontières repérés dans le jeu d'essai et donne une règle mesurable pour l'urgence. Écrire un prompt revient en grande partie à écrire une spécification, et le jeu d'essai sert à vérifier que la spécification a été comprise.

5. Les sorties libres : jugées par règles ou par un second modèle

Tous les usages ne produisent pas une catégorie comparable à une valeur attendue. Pour un résumé ou une réponse rédigée, deux approches existent. Les vérifications par règles d'abord : longueur maximale, présence d'un numéro de commande, absence d'une promesse de remboursement. Elles sont simples, gratuites et fiables. Le jugement par un second appel au modèle ensuite, à qui l'on fournit la réponse et une grille de critères précise. Cette seconde méthode rend service, à condition de vérifier à la main un échantillon de ses verdicts, parce qu'un juge automatique a lui aussi ses biais.

Les pièges qui donnent de faux bons scores

Copier les exemples du prompt dans le jeu d'essai

Quand le prompt contient des exemples de messages déjà classés, les reprendre tels quels dans le jeu d'essai revient à donner les réponses avant l'examen. Le score monte, et ne dit rien sur les messages réels. Le jeu d'essai doit contenir des cas que le prompt n'a jamais vus.

Ajuster le prompt jusqu'à 100 % sur six cas

Avec un petit jeu d'essai, on finit par écrire un prompt qui règle chaque cas un par un, avec une phrase dédiée à chaque échec. Le score devient parfait et le prompt devient un catalogue d'exceptions. Le remède consiste à garder une partie des cas de côté, jamais consultée pendant l'écriture, et à ne la lancer qu'au moment de valider une version.

Changer de modèle sans relancer le jeu

Un nouveau modèle, ou une nouvelle version du même modèle, peut améliorer la plupart des cas et en dégrader quelques-uns, souvent les plus délicats. Comme le nom du modèle est une variable, la comparaison se fait en une commande. Sauter cette étape au nom du « nouveau modèle forcément meilleur » est l'erreur la plus courante.

Oublier le coût des répétitions

Vingt cas, trois répétitions, deux versions de prompt : cent vingt appels à chaque exécution. Avec un modèle économique, le coût reste négligeable. Avec un modèle haut de gamme et des messages longs, il devient visible sur la facture du mois. Les limites de débit de l'API peuvent aussi interrompre la boucle, un sujet traité dans l'article sur la consommation d'une API tierce, les relances et les limites de débit.

Mettre des données réelles de clients dans le jeu d'essai

Les meilleurs cas de test viennent souvent de vrais messages. Les copier tels quels dans un dépôt de code y fait entrer des noms, des adresses et des numéros de commande. Les anonymiser avant de les versionner fait partie du travail, au même titre que la protection des clés d'API, sujet abordé dans l'article sur les risques d'une application non sécurisée.

Aller plus loin

Ce jeu d'essai devient vite un réflexe, puis un fichier qu'on enrichit à chaque incident. L'étape suivante consiste à le lancer automatiquement à chaque modification du prompt dans le dépôt, comme on lance les tests unitaires d'un programme. Le même principe s'applique ensuite à des usages plus ambitieux, comme ceux décrits dans 15 projets LLM à coder.

Pour les personnes en reconversion, les développeurs juniors et les curieux qui veulent apprendre à écrire, structurer et évaluer des prompts appelés depuis du code, la formation Prompt Engineering et API LLM couvre ce terrain. Pour construire ensuite une application complète autour d'un modèle, la formation Création d'une application IA avec Python et l'API OpenAI prend le relais. Le parcours d'ensemble est décrit dans la roadmap pour devenir développeur IA, et la question de la méthode d'apprentissage dans comment réussir sa formation à l'IA.

Le premier jeu d'essai peut tenir en dix cas. Le plus difficile reste de les écrire avant de toucher au prompt.

Questions fréquentes

Combien de cas faut-il dans un jeu d'essai ?

Pour commencer, une vingtaine de cas suffit, à condition qu'ils couvrent chaque catégorie et surtout les cas ambigus. Le jeu grandit ensuite au fil des erreurs constatées en production. Au-delà de quelques centaines de cas, le coût et la durée de chaque exécution deviennent les vraies contraintes.

Pourquoi le même prompt donne-t-il des réponses différentes ?

Un modèle de langage choisit chaque morceau de texte parmi plusieurs possibilités pondérées par des probabilités, avec une part de hasard. Deux appels identiques peuvent donc diverger, surtout sur les cas ambigus. C'est pour cette raison qu'un jeu d'essai répète chaque cas plusieurs fois au lieu de se fier à un seul appel.

La sortie structurée garantit-elle une réponse juste ?

Non. Elle garantit la forme : des champs présents, des types corrects, une valeur choisie dans la liste autorisée. Le modèle peut toujours choisir la mauvaise catégorie, et c'est précisément ce que mesure le jeu d'essai. Forme garantie et contenu vérifié se complètent.

Faut-il un outil spécialisé pour évaluer ses prompts ?

Pas pour débuter. Une liste de cas et une boucle Python suffisent à prendre l'habitude. Les outils spécialisés deviennent intéressants quand le jeu d'essai grossit, que plusieurs personnes modifient les prompts ou qu'il faut suivre l'évolution des scores dans le temps.

Cette méthode fonctionne-t-elle avec d'autres modèles qu'OpenAI ?

Oui. Seule la fonction qui appelle le modèle change d'un fournisseur à l'autre, le jeu d'essai et la boucle de mesure restent identiques. C'est même le meilleur moyen de comparer deux fournisseurs sur sa propre tâche plutôt que sur des classements publics.

Faut-il savoir coder pour faire du prompt engineering ?

Pour un usage personnel dans une interface de chat, non. Pour intégrer un modèle dans un outil, l'évaluer et le maintenir, quelques bases de Python changent tout : elles permettent de lancer cent essais là où l'on en ferait trois à la main.

Vous êtes expert ?

Partagez votre expertise sur notre blog

Tutoriel, retour d'expérience, analyse - publiez un article invité et gagnez en visibilité.

Écrire pour nous