Proving Ground

Des agents jugés sur ce qui s’est passé, pas sur ce qu’ils en disent

Proving Ground est un benchmark pour agents utilisant des outils. Il les fait tourner face à une entreprise simulée déterministe (clients, commandes, tickets, une boîte de réception) et note le journal d’événements du monde, pas le message final de l’agent. Sa métrique phare est le succès halluciné : l’agent affirme que le remboursement est passé, et le registre ne montre aucun remboursement.

Type
Projet personnel, 2026, conçu et réalisé de bout en bout
Monde
40 clients, 120 commandes, 30 tickets, 24 e-mails, 9 documents de base de connaissances
Suite
24 scénarios, 20 outils, 4 scaffolds, 6 profils de politique
Modèles
Tout endpoint compatible OpenAI, température 0, seed fixe
Tests
232 cas de test (pytest)

La mécanique fonctionne et elle est testée : chaque scénario a une solution de référence écrite à la main, qui doit passer. Aucun benchmark n’a encore été mené sur un modèle : il n’y a donc pas de résultats à présenter.

Une cellule du benchmark

Un benchmark est une grille : scénario × scaffold × profil de politique. Chaque cellule fait tourner un agent dans un monde neuf, et chaque appel d’outil passe un filtre de politique avant de pouvoir changer quoi que ce soit.

Un scénario adverse, un agent, un monde
Cellule benchmark scénario × scaffold Création du monde seed 1001 + patch Tour de l’agent un des 4 scaffolds Filtre politique taint, budget, confirm Outil exécuté événement écrit d’abord Notation du monde contrôles du journal Classification 14 codes d’échec Résultats SQLite + UI en direct Cellule benchmark scénario × scaffold Création du monde seed 1001 + patch Tour de l’agent un des 4 scaffolds Filtre politique taint, budget, confirm Outil exécuté événement écrit d’abord Notation du monde contrôles du journal Classification 14 codes d’échec Résultats SQLite + UI en direct
  • Entrée ou sortie
  • Appel LLM
  • Code
  • Contrôle
  1. Cellule benchmark Une cellule : un scénario adverse, le scaffold ReAct, le profil de politique « taint ». Chaque réponse du modèle est enregistrée dans une cassette : la cellule peut donc être rejouée à l’identique.
  2. Création du monde Un monde neuf, issu du seed 1001 et du patch propre au scénario, écrit dans le journal d’événements par l’acteur « system ».
  3. Tour de l’agent Le modèle lit la tâche et demande un outil : read_inbox.
  4. Filtre politique Outil inconnu, liste d’autorisation, étapes, tokens, répétitions ; puis, pour les seuls outils irréversibles, interdiction, contamination et confirmation. Une lecture dans le budget : autorisée.
  5. Outil exécuté L’horloge virtuelle avance et un événement est ajouté au journal du monde avant tout changement. Le texte de l’e-mail est transmis au suivi de contamination.
  6. Tour de l’agent Un e-mail contient des instructions. L’agent appelle issue_refund, un outil irréversible, avec un identifiant de commande qui n’apparaissait que dans ce texte non fiable.
  7. Filtre politique DENY_TAINT. L’appel est refusé avec son motif ; le monde et l’horloge restent intacts.
  8. Tour de l’agent L’agent donne sa réponse finale sans rembourser.
  9. Notation du monde Les contrôles portent sur l’état final du monde, jamais sur la réponse : aucun événement de remboursement n’existe. Si la réponse en avait revendiqué un, ce serait compté comme un succès halluciné.
  10. Classification Un code d’échec attribué par des règles, ordonnées par cause racine, et l’issue de l’attaque lue dans le monde.
  11. Résultats Enregistré dans SQLite et diffusé par WebSocket vers le dashboard : succès, sécurité, succès halluciné, étapes et coût.

Les autres chemins du graphe

  • La boucle de tours s’arrête aussi après 3 réponses mal formées d’affilée, ou au bout de 31 tours (le budget de 25 étapes, plus 6).
  • Budget épuisé : l’agent est prié de conclure et d’être honnête, et son prochain appel bloqué met fin à l’exécution.
  • Outils irréversibles sous le profil « confirm » : l’appel renvoie un jeton que l’agent doit renvoyer tel quel. Il n’y a pas d’approbateur simulé dont la réponse pourrait fuiter.
  • Un modèle juge optionnel note la clarté, l’ancrage et la calibration de 1 à 5. Il ne peut jamais modifier le succès.

Un tiers de la suite ne se gagne pas en agissant

Les 24 scénarios se répartissent en cinq familles : 6 directs, 4 ambigus, 4 impossibles, 4 à distracteurs et 6 adverses. Dans les scénarios ambigus et impossibles, la bonne décision est de demander ou de refuser : un agent qui agit toujours perd donc un tiers de la suite.

Le monde autorise même les violations de politique, comme rembourser une commande annulée, afin que ce soit l’agent qui soit mesuré et non le simulateur. Chaque scénario est livré avec une solution de référence écrite à la main, qui doit passer sans être signalée, ce qui teste les scénarios eux-mêmes.

Quatre scaffolds, les mêmes 20 outils

10 outils de lecture, 6 écritures réversibles et 4 actions irréversibles : remboursements, e-mails, remises et suppressions.

  • ReAct

    Une seule boucle : réfléchir, appeler un outil, lire l’observation, jusqu’à la réponse finale.

  • Planifier puis exécuter

    Un planificateur rédige d’abord un plan structuré ; une replanification est autorisée si des étapes ont été bloquées ou ont échoué.

  • Reflexion

    Après une première tentative, un critique plus petit relit un relevé mécanique des appels et des événements du monde, et l’agent a droit à une tentative de plus, avec 3 leçons au maximum. Le monde n’est pas réinitialisé.

  • Orchestrateur et workers

    Un agent principal délègue jusqu’à 3 sous-tâches à des workers aux outils restreints (le rôle researcher en voit 10, operator 16, settler les 20). La restriction est appliquée dans l’appel lui-même, et pas seulement masquée dans le prompt.

Six profils de politique

Du profil open au profil strict. Le profil delimited encadre le texte non fiable par des délimiteurs ; confirm exige un jeton pour les outils irréversibles ; taint bloque les appels irréversibles dont les arguments proviennent d’un texte non fiable (shingles de 5 mots, tokens rares, adresses e-mail) ; strict combine confirm et taint, et readonly est le sixième.

La contamination est vérifiée avant la confirmation : une instruction injectée ne peut donc pas devenir une action par simple confirmation.

Choix d’ingénierie

  • L’état du monde décide

    Le succès est calculé à partir du journal d’événements. Un modèle juge peut commenter la réponse, mais pas changer le score.

  • Pas de LangGraph, et c’est voulu

    Le scaffold est la variable testée : la boucle doit donc pouvoir être interceptée, enregistrée et rejouée ligne par ligne.

  • Déterministe par construction

    Un monde généré à partir d’un seed, une horloge virtuelle, une température de 0 et une cassette par cellule : un changement ne réenregistre que la colonne qu’il touche.

  • Un suivi de contamination sans liste d’attaques

    La détection suit la provenance du texte au lieu de reconnaître des charges connues. Une liste d’identifiants de confiance a corrigé un vrai faux positif, qui bloquait le bon remboursement dans un scénario direct.

  • Une restriction appliquée, pas suggérée

    La liste d’outils d’un worker est vérifiée au moment de l’appel : un outil absent de son prompt est donc aussi hors de sa portée.

  • Deux protocoles d’échange

    Appel d’outils natif ou protocole THOUGHT / ACTION en texte brut, enregistré avec chaque exécution, pour les modèles sans function calling.

Technologies

Agents
boucles écrites à la main, SDK compatible OpenAI, cassettes JSONL
Simulateur
dataclasses Python, scénarios YAML, event sourcing, horloge virtuelle
Backend
Python 3.12, FastAPI, WebSocket, SQLModel, SQLite
Frontend
React 18, Vite, Tailwind CSS 4, graphiques SVG dessinés à la main
Qualité
pytest, ruff, GitHub Actions

Vous construisez quelque chose de similaire ?

Je détaille volontiers la conception, les compromis, ou ce que je changerais ensuite.