Guide

Promptfoo, des tests pour ce que les tests ordinaires ne couvrent pas

Promptfoo teste prompts, modèles et agents, et génère des attaques pour évaluer leur résistance. Configuration, assertions, rachat par OpenAI, prix et CI.

L'équipe CodeWorlds15 min de lecture ·

Pratique Python dans des leçons interactives avec un éditeur de code.

Crée un compte gratuit→
Dans cet article11

Le code se teste avec des assertions, car son résultat est déterministe. La réponse d'un modèle ne l'est pas, donc la question « est-ce que ce changement de prompt a amélioré quelque chose » se termine généralement par la vérification de trois exemples et l'impression que c'est mieux.

Promptfoo transforme cette impression en un chiffre. Tu définis des cas de test, tu précises ce qui doit être vérifié, et tu lances une comparaison sur plusieurs variantes à la fois : prompts différents, modèles différents, réglages différents. La seconde moitié de l'outil génère des attaques qui vérifient si l'application peut être cassée.

En mars 2026, OpenAI a annoncé le rachat du projet, avec l'assurance qu'il reste open source sous la licence actuelle et que la technologie rejoint la plateforme de ce fournisseur. Pour les utilisateurs de la version open source, rien n'a changé.

Ta première suite de tests

La configuration vit dans un fichier, donc elle passe sous contrôle de version comme le reste du code.

Bash
npx promptfoo@latest init
YAML
prompts:
  - "Classe ce ticket dans une catégorie : {{content}}"
  - file://prompts/classification-v2.txt

providers:
  - openai:gpt-5-mini
  - anthropic:claude-sonnet-5

tests:
  - vars:
      content: "Je ne peux plus me connecter depuis hier"
    assert:
      - type: contains
        value: "connexion"
      - type: latency
        threshold: 3000

  - vars:
      content: "Merci de renvoyer ma facture de mars"
    assert:
      - type: contains
        value: "paiements"

Une exécution compare chaque prompt à chaque modèle sur chaque cas, donc deux prompts et deux modèles sur deux cas produisent huit appels. Les résultats apparaissent dans un tableau qui montre d'un coup d'œil quelle variante passe le plus de tests.

Cette construction est le cœur de l'outil. Plutôt que de corriger un seul prompt sans arrêt, tu compares plusieurs variantes à la fois sur le même jeu de cas et tu choisis celle qui obtient les meilleurs résultats selon une mesure plutôt que selon une impression.

Les types d'assertion

Les assertions se répartissent en trois groupes qui diffèrent par leur coût et leur fiabilité, et les mélanger sans discernement est l'erreur la plus courante.

Les assertions déterministes vérifient des faits sur la réponse : si elle contient une chaîne de caractères, si elle correspond à un motif, si c'est du JSON valide, si elle reste dans une limite de temps ou de coût. Elles sont gratuites, instantanées, et devraient constituer la majorité d'une suite.

YAML
assert:
  - type: is-json
    value:
      required: [category, priority]
  - type: javascript
    value: "output.priority >= 1 && output.priority <= 5"
  - type: cost
    threshold: 0.01

Les assertions basées sur un modèle vérifient des choses qu'aucune comparaison directe ne couvre : si une réponse reste fidèle aux faits fournis, si elle a le bon ton, si elle ne promet rien d'interdit. Elles coûtent des tokens et ajoutent leur propre bruit, donc réserve-les à ce qu'aucune vérification plus simple ne peut couvrir.

YAML
assert:
  - type: llm-rubric
    value: "La réponse s'appuie uniquement sur le contexte fourni et n'ajoute aucun fait"
  - type: factuality
    value: "Les copies de factures se téléchargent depuis le panneau de facturation"

Le troisième groupe compare à une réponse de référence, utile quand tu as des références prêtes. Elles sont plus fiables qu'une évaluation libre et demandent du travail pour construire le jeu de données.

Red teaming

La seconde moitié de l'outil vérifie si une application peut être poussée vers un comportement que tu ne veux pas. C'est difficile à faire à la main, car ça demande à la fois de l'inventivité et de la méthode.

Bash
npx promptfoo@latest redteam init
npx promptfoo@latest redteam run

L'outil génère des tentatives d'attaque dans plusieurs catégories. L'injection de prompt vérifie si le contenu fourni par l'utilisateur peut écraser l'instruction système. Le jailbreaking cherche des formulations qui poussent le modèle à faire ce qu'on lui avait dit de refuser. La fuite de données vérifie si l'instruction système ou les données d'un autre utilisateur peuvent être extraites. L'abus d'outils vérifie si un agent peut être amené à appeler une opération hors de son périmètre.

Le résultat est un rapport avec les requêtes précises qui ont fonctionné. Ça compte, car une liste de vulnérabilités sans exemple ne sert à rien, alors qu'une requête qui est vraiment passée peut aller directement dans la suite de tests comme cas de régression.

Fais tourner ça avant une mise en production plutôt qu'après un incident. Une application avec un agent qui a un accès en écriture est un cas particulier ici, car les conséquences d'une attaque réussie vont au-delà d'une réponse inappropriée.

Tester tout le chemin, pas seulement le prompt

L'erreur méthodologique la plus courante consiste à tester une instruction isolée du reste de l'application. Un prompt avec un contexte codé en dur passe ses tests alors que l'application répond mal, car le problème se situe dans les fragments qui arrivent jusqu'au contexte.

L'outil peut appeler ton propre endpoint, donc tu testes ce qui s'exécute réellement pour l'utilisateur.

YAML
providers:
  - id: https://localhost:3000/api/assistant
    config:
      method: POST
      headers:
        Content-Type: application/json
      body:
        question: "{{content}}"
        userId: "test-118"
      transformResponse: json.answer

Avec cet agencement, un test couvre la recherche vectorielle, les appels d'outils et toute la logique intermédiaire. Si l'application récupère des fragments depuis Chroma ou depuis l'extension pgvector, c'est généralement cette étape qui est responsable de la plupart des mauvaises réponses, plutôt que la formulation de l'instruction.

Teste aussi l'étape de récupération séparément. Un ensemble de questions où le fragment qui doit atteindre le contexte est marqué te permet de mesurer la précision de la récupération indépendamment de la qualité de la réponse. Ça sépare deux problèmes qui, sinon, se mélangent.

Travail d'équipe et revue des résultats

Les résultats de tests dans un terminal conviennent à une seule personne et ne servent à rien pour une équipe. L'outil propose une vue dans le navigateur avec un tableau comparatif qui montre les réponses côte à côte.

Bash
npx promptfoo@latest view

Cette vue aide surtout pour l'évaluation manuelle. Certaines choses sont difficiles à exprimer comme une assertion et faciles à juger à l'œil, donc passer en revue vingt réponses dans un tableau prend un quart d'heure et en dit plus qu'un simple décompte de réussites.

Dans le travail d'équipe, des rôles clairement établis comptent aussi. Celui qui change le prompt lance la suite, mais juger si le changement est acceptable devrait revenir à quelqu'un qui connaît les besoins métier. C'est le même principe que pour la revue de code.

Mets aussi au clair qui ajoute les nouveaux cas. La meilleure source, ce sont les réclamations des utilisateurs et les situations où l'application a échoué, donc la personne qui gère les réclamations est la candidate naturelle, à condition que le format de la suite soit assez simple pour être utilisé sans connaître le code.

Utilisation dans un pipeline de build

Une suite lancée à la main fonctionne pendant deux semaines, puis s'arrête. La brancher sur le build fait apparaître une régression au moment du changement plutôt que chez l'utilisateur.

YAML
- name: Tests de prompts
  env:
    PROMPTFOO_PASS_RATE_THRESHOLD: '90'
  run: npx promptfoo@latest eval --config promptfoo.yaml

Deux choses doivent être réglées dans un tel déploiement. La première, c'est le coût : une suite complète à chaque commit représente des centaines d'appels par jour, donc une répartition raisonnable fait tourner un petit jeu rapide à chaque changement et la suite complète avant une mise en production ou une fois par jour.

La seconde, c'est le non-déterminisme. Un test sur un modèle peut réussir quatre fois et échouer à la cinquième, donc fixe le seuil de réussite au niveau de la suite plutôt que d'exiger un sans-faute. La variable d'environnement montrée ci-dessus fait exactement ça, en prenant un pourcentage de cas réussis ; elle vaut cent par défaut, et la commande se termine avec le code cent dès que le résultat tombe sous le seuil.

Conserve les résultats entre les exécutions, car seule la comparaison avec la précédente montre une tendance. Un résultat unique dit combien de tests ont réussi ; la différence dit si le dernier changement a aidé.

Prix

VarianteCoûtCe qui est inclus
Community0 USDTests complets, licence MIT, red teaming jusqu'à dix mille tentatives par mois, exécution en local ou auto-hébergée
Enterprisedevis individuelLimites de tentatives personnalisées, résultats partagés, gestion des accès, surveillance continue, cloud géré par le fournisseur
Enterprise On-Premisedevis individuelTout ce qui précède, plus un déploiement sur ta propre infrastructure et une isolation complète des données

La grille tarifaire ne publie aucun chiffre à part zéro : les deux plans payants se chiffrent individuellement selon la taille de l'équipe. La seule limite de la version gratuite vaut cependant la peine d'être connue. Une tentative, c'est une requête envoyée au système testé pendant le red teaming, et le plan Community couvre dix mille tentatives par mois sans frais. Les tentatives supplémentaires ne s'achètent que dans le cadre d'un contrat Enterprise, donc à plus grand volume de tests, c'est ce plafond, plutôt que le prix de l'outil, qui décide du moment où la conversation avec un commercial commence.

La bibliothèque elle-même est gratuite, mais tester coûte des tokens. Cent cas sur deux modèles et deux prompts donnent quatre cents appels, donc chiffre une grosse suite avant de la lancer.

Trois approches limitent ce coût. La première, c'est de privilégier les assertions déterministes, qui ne coûtent rien. La seconde, c'est de tester sur un modèle moins cher là où tu vérifies la logique du prompt plutôt que la qualité de la réponse. La troisième, c'est de mettre les résultats en cache, pour qu'une réexécution sans changement ne génère aucun appel.

Que faire du résultat du red teaming

Un rapport qui liste les attaques réussies, c'est le début du travail, pas la fin. Trois choses doivent être réglées pour chaque vulnérabilité trouvée.

La première, c'est la conséquence. Une réponse où le modèle s'est écarté du sujet est un désagrément d'image. Une réponse où un agent a appelé une opération qui modifie le compte de quelqu'un d'autre est un incident de sécurité. La même technique d'attaque peut produire l'un ou l'autre, selon ce que l'agent a sous la main.

La seconde, c'est l'endroit où placer la correction. Renforcer l'instruction système aide partiellement et peut être contourné, car un modèle peut toujours être convaincu de faire autrement. La réponse durable se trouve dans le code : vérification des permissions à l'intérieur de l'outil, périmètre d'opération restreint, approbation requise pour les actions irréversibles.

Il existe parfois un troisième endroit : un filtre qui inspecte l'entrée et la sortie du modèle séparément de son instruction, exécuté à chaque requête. La bibliothèque open source la plus connue de ce genre est LLM Guard, de Protect AI, et elle demande une réserve, car le projet a été archivé en juillet 2026 et ses mainteneurs ont écrit clairement qu'aucun nouveau détecteur ne viendrait. Le code s'installe et fonctionne encore, mais mettre dans ta pile une bibliothèque qui ne recevra plus de correctifs est une décision à prendre les yeux ouverts. Traite le filtre lui-même comme une couche qui réduit le nombre de tentatives réussies, pas comme un substitut à la vérification des permissions à l'intérieur de l'outil.

La troisième, c'est de l'enregistrer dans la suite. Une requête qui est passée devient un cas de régression, pour que le même trou ne revienne pas au prochain changement de prompt. Sans cette étape, une correction dure jusqu'à la prochaine modification importante.

Rappelle-toi aussi que le red teaming automatisé vérifie des schémas connus de l'outil. Ça ne remplace pas la revue de ce que l'agent peut faire en général, et cette question mérite d'être posée avant que quiconque commence à tester. Un agent sans accès aux opérations qui modifient des données est, par définition, immunisé contre toute une catégorie de problèmes.

Promptfoo face aux alternatives

OutilPoint fortPoint faibleÀ choisir quand
PromptfooTests et red teaming réunis, configuration dans un fichierPas de traces de productionComparer des variantes, tester avant une mise en production
LangSmithTraces de production plus évaluationsSource fermée, pas de red teamingDiagnostiquer une application en cours d'exécution
LangfuseOpen source, auto-hébergementMoins d'assertions prêtes à l'emploiObservabilité sur ta propre infrastructure
DSPyOptimisation de prompt selon une métriqueDemande un jeu de données et une métriqueChoisir les instructions automatiquement

Ces outils couvrent des étapes différentes, et on en utilise généralement deux ensemble. Celui-ci compare des variantes avant la mise en production ; un outil d'observabilité diagnostique ce qui se passe en production. Les traces de production sont d'ailleurs la meilleure source de cas de test, donc les deux forment une boucle.

La dernière ligne est une catégorie différente : plutôt que de comparer des variantes écrites par un humain, elle choisit l'instruction automatiquement. Les deux se combinent, cet outil servant de vérification indépendante du résultat de l'optimisation.

Note qu'aucun de ces outils ne remplace le fait de réfléchir à ce qui doit vraiment être mesuré. Un jeu de tests reflète ce que tu as décidé d'important, donc s'il lui manque les cas où l'application échoue vraiment, un score élevé ne veut rien dire. C'est le même problème que la couverture de tests dans du code ordinaire : le chiffre monte et les bugs restent.

Quand une suite de tests dans un fichier ne suffit plus, parce que les résultats doivent être comparés entre les mises en production et montrés à l'équipe, l'étape suivante naturelle est Opik. Il a des traces, des jeux de tests et un dashboard, et le tout est sous licence Apache 2.0 sans dossier à licence séparée, donc la variante auto-hébergée n'est pas bridée. Le prix se paie en deux temps : c'est un service de plus à maintenir, et certaines métriques intégrées appellent un modèle juge, ce qui produit sa propre facture à côté de celle de l'application. À l'installation, surveille les plages de peer dependencies, car les paquets d'intégration peuvent exiger une version du cœur plus ancienne que la version actuelle.

Erreurs courantes

La première, c'est une suite composée de cas faciles. Des tests qui réussissent toujours ne montrent aucune différence entre les variantes, ce qui est exactement la raison d'être de la suite.

La deuxième, c'est d'utiliser des assertions basées sur un modèle là où une simple comparaison de valeur suffit. Vérifier si une réponse est du JSON valide avec les champs requis ne coûte rien, alors qu'évaluer la même chose avec un modèle coûte des tokens et se révèle parfois instable.

La troisième, c'est de tester le prompt seul plutôt que tout le chemin. Si l'application récupère des fragments depuis une base de données vectorielle, un test sur un contexte codé en dur passe à côté du problème de récupération responsable, en pratique, de la plupart des mauvaises réponses.

La quatrième, c'est de sauter le red teaming sur une application qui accepte du contenu utilisateur. L'injection de prompt n'est pas une menace théorique, surtout quand un agent dispose d'outils qui modifient des données.

La cinquième, c'est de ne lancer les tests qu'à la main. Une suite qui reste hors du build cesse d'être utilisée en moins d'un mois, et c'est alors l'utilisateur qui découvre la régression.

La sixième, c'est d'exiger un taux de réussite de cent pour cent. Avec des réponses non déterministes, ce seuil pousse une équipe à désactiver des tests plutôt qu'à améliorer le prompt.

FAQ

Promptfoo est-il gratuit ?

Oui, la version open source sous licence MIT couvre les tests complets et le red teaming, et tu l'exécutes toi-même. Le plan Community est gratuit pour toujours, avec une seule limite : dix mille tentatives de red teaming par mois. Les plans Enterprise et Enterprise On-Premise se chiffrent individuellement, sans tarifs publiés. Tu paies en revanche pour les tokens que les tests consomment.

Que signifie le rachat par OpenAI ?

En mars 2026, OpenAI a annoncé le rachat, en précisant que le projet reste open source sous sa licence actuelle et que les clients existants continuent d'être pris en charge. La technologie doit rejoindre la plateforme d'agents de ce fournisseur. Pour les utilisateurs de la version open source, ça ne change rien à la façon de travailler, même si un changement de propriétaire vaut la peine d'être pesé pour une planification à plusieurs années.

En quoi diffère-t-il des outils d'observabilité ?

Cet outil vérifie des variantes avant le déploiement sur un jeu de cas préparé. Des outils comme Langfuse collectent des traces depuis une application en cours d'exécution et montrent ce qui se passe réellement. Ils fonctionnent mieux ensemble : les traces fournissent des cas pour la suite, et la suite évite qu'une correction casse autre chose.

Peut-il tester des agents, pas seulement des prompts ?

Oui, l'outil peut aussi appeler ton propre endpoint, donc tu testes tout le chemin, y compris la récupération et les appels d'outils. C'est généralement plus sensé que de tester le prompt seul, car les problèmes se situent le plus souvent dans le contexte plutôt que dans l'instruction.

Par où commencer ?

Avec vingt cas pris dans du trafic réel, y compris des situations où l'application a échoué. Ajoute des assertions déterministes, lance une comparaison de deux variantes de prompt, et ce n'est qu'ensuite que tu élargis la suite avec une évaluation par modèle là où une vérification plus simple ne suffit pas.

La documentation se trouve sur le site du projet, et le rachat a été annoncé sur le blog de Promptfoo.

À lire aussi