Vous avez passe des heures a peaufiner un prompt. Il genere exactement ce que vous attendez. Vous le deployez en production, et trois semaines plus tard, les utilisateurs signalent des resultats incoherents. Le modele a ete mis a jour, ou le contexte a change, et votre prompt ne fonctionne plus comme prevu. Ce scenario, tout developpeur qui integre des LLM dans ses applications l'a vecu au moins une fois. La solution existe pourtant : tester ses prompts avec la meme rigueur que son code.
Pourquoi tester ses prompts est aussi important que tester son code
Dans le developpement logiciel classique, personne ne deploie du code sans tests unitaires. Les tests garantissent que le comportement attendu est respecte, detectent les regressions et documentent les specifications. Pour les prompts, la logique est identique.
Un prompt est du code. Il definit un comportement, accepte des entrees et produit des sorties. La difference avec une fonction classique, c'est que la sortie est non deterministe. Un meme prompt peut produire des resultats legerement differents a chaque execution. Cette variabilite ne dispense pas de tester, elle rend le testing encore plus indispensable.
Sans tests de prompts, vous naviguez a l'aveugle. Vous ne savez pas si une modification ameliore ou degrade vos resultats. Vous ne detectez pas les regressions introduites par une mise a jour du modele. Vous ne pouvez pas comparer objectivement deux versions d'un prompt. Le [prompt engineering](/prompt-engineering-developpeur-guide/) ne s'arrete pas a l'ecriture du prompt : il inclut sa validation systematique.
Le probleme du drift : un prompt qui marche aujourd'hui peut echouer demain
Les fournisseurs de LLM mettent regulierement a jour leurs modeles. OpenAI, Anthropic, Google, tous font evoluer leurs modeles de maniere continue. Ces mises a jour ameliorent souvent les performances globales, mais elles peuvent aussi modifier le comportement sur des cas specifiques.
Ce phenomene s'appelle le model drift. Un prompt qui generait du JSON valide avec GPT-4-0613 peut soudainement ajouter du texte avant le JSON avec une version ulterieure. Un prompt qui respectait une contrainte de longueur peut devenir plus verbeux. Un prompt qui suivait un format precis peut introduire des variations.
Le drift ne se limite pas aux modeles. Vos propres modifications sont aussi une source de regressions. Ajouter une instruction pour gerer un cas limite peut degrader les performances sur les cas nominaux. Modifier le ton peut affecter la structure. Chaque changement est un risque sans tests pour le valider.
Methodologie : definir des cas de test pour vos prompts
La premiere etape consiste a formaliser ce que vous attendez de votre prompt. Comme pour les tests logiciels, vous definissez des paires input/expected output.
Un cas de test pour un prompt comprend trois elements. D'abord, l'entree : les variables que vous injectez dans le prompt (question utilisateur, contexte, document a analyser). Ensuite, les assertions : les criteres que la sortie doit respecter (contient un mot-cle, est du JSON valide, ne depasse pas 200 tokens, ne contient pas d'hallucinations). Enfin, les metriques : les scores quantitatifs qui evaluent la qualite (similarite semantique, coherence, pertinence).
Concretement, pour un prompt de generation de code, vos cas de test pourraient ressembler a ceci :
Cas 1 : "Ecris une fonction Python qui trie une liste"
- La sortie contient "def "
- La sortie est du Python syntaxiquement valide
- La fonction gere une liste vide sans erreur
Cas 2 : "Ecris une requete SQL pour les utilisateurs actifs"
- La sortie contient "SELECT"
- La sortie ne contient pas "DROP" ou "DELETE"
- La requete est syntaxiquement valide
Cette approche systematique transforme l'evaluation subjective ("ca a l'air correct") en validation objective et reproductible. C'est d'ailleurs la meme logique que celle appliquee pour [tester du code genere par IA](/tester-code-genere-ia-strategies/).
Les outils du prompt testing
Plusieurs outils matures permettent aujourd'hui de tester vos prompts de maniere structuree.
Promptfoo : l'outil open source de reference
Promptfoo est un framework open source de test et d'evaluation de prompts. Il fonctionne avec une configuration YAML declarative et supporte tous les principaux fournisseurs de LLM.
Son approche est directe : vous definissez vos prompts, vos cas de test et vos assertions dans un fichier YAML, puis vous lancez l'evaluation. Promptfoo execute chaque combinaison prompt/test, applique les assertions et genere un rapport detaille.
prompts:
- "Genere une fonction {{langage}} qui {{description}}. Retourne uniquement le code, sans explication."
providers:
- openai:gpt-4o
- anthropic:messages:claude-sonnet-4-20250514
tests:
- vars:
langage: Python
description: "calcule la suite de Fibonacci"
assert:
- type: contains
value: "def "
- type: python
value: |
import ast
try:
ast.parse(output)
return {"pass": True}
except SyntaxError as e:
return {"pass": False, "reason": str(e)}
- type: llm-rubric
value: "Le code genere est-il correct, lisible et gere-t-il les cas limites ?"
- vars:
langage: JavaScript
description: "valide une adresse email"
assert:
- type: contains
value: "function"
- type: javascript
value: "output.includes('return') && !output.includes('eval')"
- type: cost
threshold: 0.05
L'execution se fait en une commande :
npx promptfoo eval
npx promptfoo view # interface web pour analyser les resultats
LangSmith : tracing et evaluation integres
LangSmith, developpe par l'equipe LangChain, propose une approche centree sur le tracing. Chaque appel LLM est trace, enregistre et analysable. Vous pouvez creer des datasets de test, definir des evaluateurs et suivre les performances dans le temps.
Son avantage principal est l'integration native avec LangChain et la capacite a tracer des chaines complexes (RAG, agents). Son inconvenient est le couplage fort avec l'ecosysteme LangChain.
Braintrust : evaluation a grande echelle
Braintrust se positionne sur l'evaluation a grande echelle avec un focus sur la collaboration en equipe. Il propose des evaluateurs preconfigures (factualite, coherence, pertinence) et une interface visuelle pour comparer les resultats. Son modele de scoring est particulierement adapte aux cas ou plusieurs evaluateurs humains interviennent.
Evals custom avec pytest
Pour les equipes qui preferent rester dans leur stack de test existante, pytest offre une base solide :
import pytest
import openai
client = openai.OpenAI()
PROMPT_TEMPLATE = """Genere une fonction {langage} qui {description}.
Retourne uniquement le code, sans explication."""
@pytest.fixture
def llm_response():
def _call(langage, description):
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": PROMPT_TEMPLATE.format(
langage=langage, description=description
)}],
temperature=0
)
return response.choices[0].message.content
return _call
def test_python_fibonacci(llm_response):
output = llm_response("Python", "calcule la suite de Fibonacci")
assert "def " in output
compile(output, "<string>", "exec") # verifie la syntaxe
def test_no_dangerous_code(llm_response):
output = llm_response("Python", "lit un fichier CSV")
assert "os.system" not in output
assert "subprocess" not in output
assert "eval(" not in output
Les metriques essentielles du prompt testing
Tester un prompt ne se resume pas a verifier qu'il "marche". Plusieurs dimensions meritent d'etre mesurees.
Exactitude : la sortie correspond-elle a ce qui est attendu ? Pour du code, est-il syntaxiquement valide ? Passe-t-il les tests unitaires ? Pour du texte, contient-il les informations cles ?
Coherence : sur 10 executions avec le meme input, les resultats sont-ils homogenes ? Un prompt dont les resultats varient fortement est un prompt instable, meme si la moyenne est correcte.
Latence : combien de temps prend la generation ? Un prompt qui necessite 15 secondes pour repondre peut etre problematique en production.
Cout : combien coute chaque execution ? Un prompt verbeux qui consomme 4000 tokens en sortie quand 500 suffiraient impacte directement votre budget.
Toxicite et securite : la sortie contient-elle des contenus inappropries ? Le prompt est-il vulnerable aux injections ? Ces verifications sont critiques pour les applications grand public.
Regression testing : detecter les degradations
Le regression testing de prompts suit le meme principe que le regression testing logiciel. Vous constituez une suite de tests de reference, vous l'executez apres chaque modification de prompt et vous comparez les resultats.
La cle est de constituer un dataset de reference solide. Commencez avec 20 a 30 cas de test qui couvrent vos principaux scenarios : cas nominaux, cas limites, cas d'erreur. Executez votre suite de reference et stockez les scores comme baseline.
A chaque modification de prompt, relancez la suite complete. Si le score global baisse de plus de 5%, la modification doit etre revue. Si un cas de test specifique passe de "reussi" a "echoue", c'est un signal d'alerte immediat.
Promptfoo facilite ce workflow avec la comparaison integree :
# Sauvegarder la baseline
npx promptfoo eval --output baseline.json
# Modifier le prompt, puis comparer
npx promptfoo eval --output new.json
npx promptfoo diff baseline.json new.json
A/B testing de prompts : comparer deux versions
Quand vous hesitez entre deux formulations, l'A/B testing de prompts tranche objectivement. Le principe est simple : vous definissez deux versions du prompt, vous les executez sur les memes inputs et vous comparez les scores.
# promptfooconfig.yaml - A/B test
prompts:
- id: version-a
raw: "Analyse ce code et liste les bugs potentiels : {{code}}"
- id: version-b
raw: |
Tu es un expert en revue de code. Analyse le code suivant
et identifie les bugs potentiels. Pour chaque bug, indique
la ligne concernee, la severite (critique/majeur/mineur)
et la correction suggeree.
Code : {{code}}
tests:
- vars:
code: |
def divide(a, b):
return a / b
assert:
- type: llm-rubric
value: "La reponse identifie-t-elle le risque de division par zero ?"
- type: llm-rubric
value: "La reponse est-elle structuree et actionnable ?"
L'analyse des resultats revele souvent que le prompt le plus long n'est pas toujours le meilleur. Parfois, une formulation concise obtient de meilleurs scores de pertinence tout en reduisant les couts et la latence.
Integration CI/CD : tester les prompts dans GitHub Actions
L'etape finale pour industrialiser le prompt testing est l'integration dans votre pipeline CI/CD. Chaque pull request qui modifie un prompt declenche automatiquement la suite de tests.
# .github/workflows/prompt-tests.yml
name: Prompt Tests
on:
pull_request:
paths:
- 'prompts/**'
- 'promptfooconfig.yaml'
jobs:
eval:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install promptfoo
run: npm install -g promptfoo
- name: Run prompt evaluations
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
promptfoo eval --output results.json
promptfoo export results.json --format csv > results.csv
- name: Check pass rate
run: |
PASS_RATE=$(cat results.json | jq '.results.stats.successes / .results.stats.count * 100')
echo "Pass rate: ${PASS_RATE}%"
if (( $(echo "$PASS_RATE < 90" | bc -l) )); then
echo "Pass rate below 90%, failing build"
exit 1
fi
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: prompt-eval-results
path: results.*
Cette configuration echoue la build si le taux de reussite des tests de prompts descend sous 90%. Les resultats sont archives comme artefacts pour analyse ulterieure.
Template de test suite pour prompts de dev
Pour demarrer rapidement, voici une structure de projet de test de prompts adaptee au developpement :
prompt-tests/
promptfooconfig.yaml # Configuration principale
prompts/
code-generation.txt # Prompt de generation de code
code-review.txt # Prompt de revue de code
doc-generation.txt # Prompt de documentation
datasets/
code-gen-tests.yaml # Cas de test generation
code-review-tests.yaml # Cas de test revue
evaluators/
syntax-check.py # Evaluateur syntaxe custom
security-check.py # Evaluateur securite custom
baselines/
latest.json # Derniere baseline validee
Le fichier de configuration principal centralise les references :
# promptfooconfig.yaml
prompts:
- file://prompts/code-generation.txt
providers:
- id: openai:gpt-4o
config:
temperature: 0
tests: file://datasets/code-gen-tests.yaml
defaultTest:
assert:
- type: cost
threshold: 0.10
- type: latency
threshold: 10000
Cette structure vous donne une base solide pour tester systematiquement vos prompts.
Passer du bricolage a l'ingenierie
Le prompt testing n'est pas un luxe : c'est une necessite pour toute equipe qui deploie des LLM en production. Sans tests, vous accumulez une dette technique invisible. Chaque prompt non teste est un bug potentiel qui attend de se manifester.
Commencez simple. Prenez votre prompt le plus critique, celui qui genere le plus de valeur ou le plus de plaintes. Ecrivez 10 cas de test. Lancez-les avec promptfoo. En moins d'une heure, vous aurez une vision objective de la fiabilite de votre prompt et une baseline pour mesurer vos ameliorations futures.
La maturite d'une equipe dans son usage des LLM ne se mesure pas au nombre de prompts en production, mais a la rigueur avec laquelle ces prompts sont testes. Le passage du "ca marche sur mon poste" au "ca passe en CI" est le meme saut qualitatif que celui que le developpement logiciel a fait il y a vingt ans avec les tests automatises.