Gauntlet : que se passe-t-il lorsque les outils de votre agent se rebellent ?

Hackathon de l’agent Elasticsearch Builder

gauntlet-blog_(1).png

À deux jours de la date limite du hackathon, j’ai décidé de prendre du recul et de repenser mon approche en profondeur.

L’idée originale s’appelait Rehearse : un agent qui répète des actions dans un bac à sable simulé par un autre agent avant de les exécuter dans le monde réel. Le concept était bon, mais avec le recul, le défaut était évident. L’environnement peut changer entre la simulation et l’exécution. Votre agent simule l’envoi d’un e-mail, mais au moment de l’exécution, la boîte de réception semble différente. La simulation s’écarte de la réalité, et tout s’écroule

Mais il existe une catégorie de problèmes qui échappe à cette difficulté : les tests de fuzz-testing contradictoire. Si votre agent échoue en simulation, il peut également échouer dans la vraie vie. C’est ainsi que Gauntlet est né. 48 heures avant la date limite, la réutilisation des mêmes informations du noyau (un agent qui utilise la recherche pour développer la mémoire et rester créative) a mis en évidence un problème où la stochasticité n’entre pas en ligne de compte.

Le problème avec les agents de test sur le scénario idéal

Nous avons presque tous entendu parler d’OpenClaw, l’assistant personnel d’IA devenu viral. Si vous avez suivi le discours autour des assistants IA agentiques avec un large accès aux outils, vous avez constaté les préoccupations de sécurité. Les agents oublient ce qu’ils ne sont pas censés faire ou ce qu’ils n’ont jamais su au départ. La raison est simple : nous testons le chemin optimal. Nous vérifions que l’agent fonctionne comme prévu. Nous vérifions rarement ce qui se passe lorsque quelqu’un essaie de lui faire faire ce qu’il ne devrait pas faire.

Les bacs à sable de test adversaire existent, mais leur mise en place est fastidieuse. Vous concevez manuellement les vecteurs d’attaque. Vous semez les données adverses à la main. Vous configurez l’infrastructure de test pour chaque scénario. C’est lent, ça ne monte pas en charge, et ça ne trouve que les bugs auxquels vous avez déjà pensé.

Je cherchais quelque chose de différent : un système où l’environnement lui-même est automatiquement un adversaire et devient plus créatif au fil du temps.

L’idée : simuler l’environnement de test avec un autre agent

Au lieu de créer un environnement de test, Gauntlet utilise un agent de simulation qui intercepte les appels d’outils de votre agent principal et trouve des moyens créatifs de le faire échouer. Lorsque votre agent appelle search_emails, l’agent de simulation voit le résultat et décide de le modifier, en injectant une invite dans le corps d’un e-mail, en renvoyant des données subtilement erronées ou en fournissant de fausses informations pour voir si l’agent principal s’en aperçoit. L’agent principal ne sait jamais qu’il se trouve dans une simulation.

L’interface est composée de deux décorateurs :

@function_tool
@gauntlet.query
def search_emails(folder: str = "inbox") -> str:
    """Search emails in the given folder."""
    return json.dumps(fetch_emails(folder))

Il y a @gauntlet.query pour les opérations de lecture et @gauntlet.mutation pour les écritures. C’est toute la surface d’intégration. Lorsque l’exécution se termine, evaluate() vérifie ce qui s’est passé et stocke les bugs confirmés.

C’est simple à utiliser, mais cela cache deux problèmes complexes.

Les deux problèmes qui en font un problème de recherche

Premièrement, l’agent de simulation doit maintenir un modèle cohérent du monde tout au long de la conversation. S’il a indiqué à l’agent principal qu’un e-mail provenait d’Alice, il ne peut pas le contredire par la suite. Un e-mail modifié qui est manifestement faux ne vous apprend rien. Tout repose sur la crédibilité.

Deuxièmement, l'agent de simulation doit trouver de nouveaux bugs. Redécouvrir le même modèle d'injection de prompt 50 fois n'est pas utile. Il doit se souvenir de ce qu'il a déjà trouvé et explorer de nouvelles directions tout en restant ancré dans ce que les outils font réellement.

Les deux constituent des problèmes de recherche. Et c’est là qu’Elasticsearch devient le pilier du système.

Deux circuits de mémoire

L’agent de simulation fonctionne sur deux circuits mémoire, tous deux hébergés dans Elasticsearch.

La mémoire à court terme suit tout au sein de la session en cours : chaque appel d’outil intercepté, le résultat original, sa mutation, et la réaction de l’agent principal. C’est la couche de cohérence. L’agent de simulation peut interroger ses propres décisions récentes et rester cohérent en interne tout en restant antagoniste. Équilibrer créativité et cohérence a été le plus grand défi de conception de tout le projet.

C’est dans la mémoire à long terme que la créativité se concentre. Elle stocke les bugavec des vecteurs d'encodage permettant la recherche par similarité, les implémentations complètes des outils permettant à l’agent d’analyser les modes de défaillance, ainsi que les résultats des exécutions précédentes. Lorsqu’un agent de simulation a besoin d’une nouvelle idée d’attaque, il consulte la mémoire à long terme pour identifier les tentatives antérieures, repérer les failles et formuler de nouvelles hypothèses.

Ces éléments alimentent un cycle fermé : émettre des hypothèses sur les bugs susceptibles d’exister, créer des circonstances pour les prouver et stocker les bugs confirmés dans l’index. L’inventaire grandit. Les attaques deviennent plus créatives. L’écart entre Gauntlet et la configuration manuelle de l’environnement de test ne cesse de se creuser avec le temps.

Tout fonctionne dans Elastic Agent Builder

L’ensemble de l’agent de simulation est développé au sein d’Elastic Agent Builder : instructions, liaisons d’outils et état de conversation multi-tours via l’API Amazon Bedrock Converse. Aucune orchestration externe n’est nécessaire.

L’outil dont je suis le plus fier est generate-hypothesis. Il s’agit d’une unique instruction ES|QL qui échantillonne les bugs existants, les agrège avec MV_CONCAT, et appelle COMPLETION en ligne pour proposer une nouvelle hypothèse d’attaque. Il gère l’échantillonnage, l’agrégation, le raisonnement LLM et la génération de résultats en une seule requête, sans jamais quitter le pipeline ES|QL. Je m’attendais à devoir faire la navette entre Elasticsearch et un script externe. Cela n’a pas été nécessaire.

La fonction COMPLETION d’ES|QL a été la plus grande surprise. Entre COMPLETION, STATS, MV_CONCAT et SAMPLE, j’ai pu créer des pipelines de raisonnement entiers sous forme de requêtes uniques. Le stockage des bugs utilise Kibana Workflows, et un tableau de bord Kibana créé par programmation offre une visibilité en temps réel sur le nombre de bugs, la répartition de la gravité et les cartes thermiques des schémas d’attaque.

L'API Converse a résolu un autre problème que je redoutais. L'agent simulé doit se souvenir de ce qu'il a déjà dit à l'agent principal au sein d'une seule exécution. J'ai supposé que je devrais récupérer les historiques de conversation à partir d'index et les recharger dans l'agent à chaque appel. Mais il s'avère que l'API Converse gère nativement l'état multi-tour. Je n'ai écrit aucune logique de gestion de conversation. Il suffit de continuer à appeler converse, et cela reste cohérent.

Les avantages concrets

La configuration manuelle de l'environnement de test adverse prend environ une heure par scénario. Avec Gauntlet, le même processus prend entre 2 et 10 minutes, et sa mémoire à long terme permet à chaque exécution de prendre en compte toutes les exécutions précédentes. Plus vous l'utilisez, plus il apprend à connaître les points faibles de votre agent et plus il s'efforce d'en trouver de nouveaux.

Et ensuite ?

Actuelement, Gauntlet fonctionne en 1 contre 1 : un agent de simulation contre un agent principal. Mais le problème est d’un parallélisme flagrant. 20 sessions d’attaque pourraient être exécutées simultanément sur des sessions séparées sans aucun changement architectural. Le scaling est la prochaine étape évidente.

La question ouverte la plus intéressante est celle de l’exploration ou de l’exploitation dans la mémoire à long terme. L’agent de simulation doit équilibrer la tentative de variations d’attaques connues réussies (exploitation) par rapport à des hypothèses complètement nouvelles (exploration). C’est un problème bien étudié dans d’autres domaines, mais son application aux tests d’agents adverses semble inexplorée. Il y a peut-être quelque chose d’intéressant à explorer au-delà de ce projet.

Je pense aussi beaucoup à Rehearse. Gauntlet est un cas particulier : le fuzz-testing fonctionne parce qu’un échec en simulation implique un échec possible dans la réalité. Mais il existe d’autres domaines où l’environnement est suffisamment stable entre la simulation et l’exécution pour que le concept initiale de répétition puisse fonctionner. Je ne les ai pas encore trouvés, mais je cherche.

Conclusion

Si vous créez des agents ayant accès à des outils réels, testez ce qui se passe lorsque ces outils ripostent. Pas seulement une fois manuellement, mais en permanence, avec un système qui se souvient de ce qu’il a essayé et devient plus créatif au fil du temps. C’est ce que fait Gauntlet.

Kavish Sathia

Étudiant, National University of Singapore

Kavish Sathia étudie l’informatique à la NUS et travaille sur les systèmes agentiques.

GitHub · Démo · Site web · LinkedIn

La publication et la date de publication de toute fonctionnalité ou fonction décrite dans le présent article restent à la seule discrétion d'Elastic. Toute fonctionnalité ou fonction qui n'est actuellement pas disponible peut ne pas être livrée à temps ou ne pas être livrée du tout.

Dans cet article, nous sommes susceptibles d'avoir utilisé ou mentionné des outils d'IA générative tiers appartenant à leurs propriétaires respectifs qui en assurent le fonctionnement. Elastic n'a aucun contrôle sur les outils tiers et n'est en aucun cas responsable de leur contenu, de leur fonctionnement, de leur utilisation, ni de toute perte ou de tout dommage susceptible de survenir à cause de l'utilisation de tels outils. Veuillez faire preuve de prudence lorsque vous utilisez des outils d'IA avec des informations personnelles, sensibles ou confidentielles. Toute donnée que vous soumettez peut être utilisée pour entrainer l'IA ou à d'autres fins. Vous n'avez aucune garantie que la sécurisation ou la confidentialité des informations renseignées sera assurée. Vous devriez vous familiariser avec les pratiques en matière de protection des données personnelles et les conditions d'utilisation de tout outil d'intelligence artificielle générative avant de l'utiliser. 

Elastic, Elasticsearch et les marques associées sont des marques commerciales, des logos ou des marques déposées d'Elasticsearch B.V. aux États-Unis et dans d'autres pays. Tous les autres noms de produits et d'entreprises sont des marques commerciales, des logos ou des marques déposées appartenant à leurs propriétaires respectifs.