Méta-ingénierie des systèmes AI : des traces à une meilleure mémoire
Traduction automatique
Cet article a été traduit automatiquement depuis la version originale en anglais.
Cet article ouvre Meta-Engineering AI Systems, un guide en six parties consacré à l’ingénierie AI en boucle fermée : utiliser des agents pour analyser les échecs, tester des modifications et exploiter les résultats afin d’améliorer des systèmes AI.
Le comportement d’une application AI dépend de bien plus que de son modèle. Les prompts, les informations récupérées, la mémoire stockée, les outils et le code de l’application influencent tous le résultat. Lorsqu’une réponse est incorrecte, plusieurs modifications peuvent sembler plausibles. Le problème d’ingénierie consiste à déterminer quelle modification est utile, ce qu’elle coûte et ce qu’elle risque de casser.
J’emploie ici le terme méta-ingénierie pour désigner la conception du processus d’amélioration lui-même : quelles preuves l’agent voit, ce qu’il peut modifier, comment nous testons ses propositions et qui décide de les adopter. La boucle fermée décrit la manière dont ce processus apprend de ses expériences. Chaque résultat détermine ce que nous essayons ou utilisons ensuite, y compris lorsqu’une modification proposée échoue.
Nous pouvons automatiser ce travail par étapes. Une personne peut spécifier les modifications exactes à tester, définir un ensemble d’alternatives autorisées pour un algorithme de recherche ou déléguer la prochaine proposition à un agent LLM. Le runner teste chaque candidat et conserve les éléments de preuve nécessaires à la décision suivante. Cette série s’intéresse à l’intégration d’agents dans ce processus, tout en maintenant l’exécution, l’évaluation et l’adoption sous contrôle explicite.
La question qui traverse ces six parties est la suivante : quelle part de ce travail pouvons-nous déléguer à un agent tout en conservant des preuves fiables et une décision d’adoption digne de confiance ? Nous commencerons par cartographier l’ensemble du système, puis nous construirons une petite version fonctionnelle autour de la mémoire d’un agent.
Ce qui ferme la boucle
Il faut garder en tête deux boucles différentes. Dans une application agentique, la boucle d’exécution choisit une action, appelle un outil, observe le résultat et poursuit la tâche en cours de l’utilisateur. La boucle d’amélioration fonctionne entre plusieurs versions de cette application. Elle analyse le comportement observé lors d’exécutions terminées et teste des modifications destinées à améliorer les exécutions suivantes.
La boucle d’amélioration commence par des éléments de preuve : une réponse incorrecte, une modification d’état indésirable, un coût excessif ou un autre échec observable. Une trace enregistre les étapes à l’origine de ce résultat. Le proposeur choisit un candidat, c’est-à-dire une version précise d’une modification. Un runner exécute le candidat sur des tâches définies, puis un évaluateur vérifie le comportement obtenu par rapport aux exigences. Dans l’expérience interactive de cet article, un agent LLM joue le rôle de proposeur :
L’évaluation éclaire la décision ; elle ne l’autorise pas elle-même. Quelqu’un doit décider si le bénéfice mesuré justifie l’adoption de la modification, en tenant compte de ses effets sur le coût, les permissions et les autres comportements requis. Dans cette série, nous commençons avec un reviewer humain. Le proposeur peut suggérer une modification, mais il ne peut ni réécrire les vérifications, ni augmenter son propre budget, ni s’accorder lui-même l’autorisation.
Deux chemins de retour existent. L’historique des expériences alimente les propositions ultérieures, y compris lorsqu’un candidat est rejeté. Si un candidat est approuvé et adopté, son comportement fournit de nouvelles preuves issues de l’utilisation. Il est important de pouvoir annuler une modification lorsque ces preuves contredisent l’expérience initiale. Enregistrer un score n’est qu’une étape ; la boucle se ferme lorsque les preuves changent ce que nous essayons ou utilisons ensuite.
L’élément amélioré est la cible. Il peut s’agir d’une politique de mémoire, d’un pipeline de retrieval, de code de sélection d’outils ou du programme qui assemble le contexte d’un modèle. L’entraînement du modèle constitue une autre intervention possible. La boucle peut fonctionner avec des poids de modèle figés : l’agent peut améliorer le programme environnant sans entraîner de modèle. Cette première démonstration inclut déjà l’agent LLM externe. Les parties suivantes renforceront l’évaluateur et testeront si la recherche agentique justifie son coût par rapport à des méthodes plus simples.
Choisir la part de recherche à déléguer
Supposons que vous sachiez déjà quoi essayer : comparer deux modèles dans une étape d’extraction ou tester les seuils de mémoire 0.6, 0.7 et 0.8. Vous pouvez fournir vous-même ces choix et automatiser l’exécution, le scoring et le reporting. Après lecture des résultats, vous choisissez l’expérience suivante. La boucle de feedback fonctionne même si le système n’a pas inventé les candidats.
J’utilise quatre modes de travail pour rendre cette répartition visible. La figure montre une manière de déléguer progressivement davantage de conception d’expériences : commencer par des choix de modèles exacts, laisser le système rechercher des paramètres et des composants approuvés, ou demander à un agent d’analyser les échecs et de choisir l’expérience suivante. L’humain spécifie moins de chaque tentative tout en conservant la définition des règles de recherche.
Les noms des modes décrivent des organisations pratiques pour cette série, et non une échelle d’autonomie standard dans l’industrie. Ce qui peut changer et qui choisit la modification sont deux décisions distinctes. Les exemples d’espaces de recherche d’Optuna combinent choix du modèle et plages de paramètres. La recherche dans les pipelines de scikit-learn compare des composants alternatifs au moyen d’une grid search classique. Remplacer un composant ne rend donc pas, à lui seul, le processus plus agentique. Les largeurs de la figure illustrent la répartition du travail dans ces exemples ; elles ne représentent pas des parts mesurées de contrôle ou d’effort.
L’investigation menée par un agent décrit la manière dont la prochaine tentative est choisie. L’agent lit les échecs et les résultats précédents, propose une modification et s’adapte après le test. Cela suit la distinction présentée dans les patterns de workflows et d’agents d’Anthropic : un processus prédéfini peut automatiser l’exécution, tandis qu’un agent oriente ses prochaines étapes à partir du feedback. Des méthodes hybrides sont également possibles : le MIPROv2 de DSPy utilise un modèle pour proposer des instructions et une optimisation bayésienne pour rechercher leurs combinaisons. Une comparaison fixe de modèles n’a pas besoin de proposeur LLM ; ses résultats entrent dans la boucle de feedback lorsqu’ils orientent l’expérience ou la version suivante du système.
Les permissions de proposition, d’exécution et d’adoption restent séparées. Un agent peut préparer une modification à faire approuver avant chaque exécution, ou tester sans surveillance des modifications autorisées pendant qu’une personne examine leur adoption. Une liste de composants approuvés nécessite tout de même des implémentations compatibles ; l’autorisation de sélectionner un adapter n’inclut pas celle d’en écrire un. Dans chaque mode, l’agent reste limité aux modifications autorisées, aux vérifications figées et au budget ; il ne peut pas s’accorder l’autorisation de déploiement. Déléguer davantage de travail laisse également de la place à la supervision : l’étude d’Anthropic sur les agents déployés décrit le passage, chez les utilisateurs, de l’approbation d’actions individuelles à la surveillance et à l’intervention.
Tous les modes peuvent utiliser le même journal d’expériences : un enregistrement de chaque modification tentée. Conservez le candidat et son parent, la modification exacte et son auteur, les versions du test et de l’environnement, le résultat, le coût ainsi que tout échec ou rejet. Cet historique permet à un humain de transmettre la proposition suivante à un agent — ou de reprendre la main — sans perdre les preuves. Les scores issus de versions de test différentes doivent néanmoins être distingués.
Cette démonstration combine recherche de configuration et investigation menée par un agent. Nous définissons cinq paramètres, les tests, le budget et la règle de sélection. L’agent choisit les valeurs et l’hypothèse suivante à partir du feedback ; Python exécute automatiquement les tests. La revue humaine de mise en production reste séparée. Le repository accepte également un candidate JSON fourni par une personne via lab evaluate. Les sweeps de modèles, les adapters de composants et le code écrit par un agent sont des options de conception plus larges pour les parties suivantes, et ne sont pas des modes implémentés dans cette démonstration de mémoire.
Pourquoi examiner ce sujet maintenant
Le principe du feedback est bien connu en ingénierie. Les travaux récents qui m’intéressent placent des agents de coding au cœur du processus d’investigation et d’expérimentation. Ils nous donnent des implémentations concrètes à examiner, plutôt que de nous demander de supposer que l’amélioration autonome fonctionnera.
L’autoresearch de Karpathy spécifie une expérience compacte : modifier un programme d’entraînement, l’exécuter avec un budget de temps d’entraînement fixe, examiner le résultat de validation et enregistrer si la tentative a été conservée, abandonnée ou interrompue par un crash. Les instructions séparent le fichier d’entraînement modifiable du code d’évaluation figé. Cette séparation rend le travail proposé et son critère de réussite inspectables.
Meta-Harness, un preprint de mars 2026, étudie une cible différente : le code qui contrôle les informations qu’une application LLM stocke, récupère et présente à son modèle. Son proposeur peut inspecter le code source, les scores et les traces d’exécution des candidats précédents via un système de fichiers. L’historique des expériences devient le matériau de travail de l’investigation suivante.
Ces projets motivent la question d’ingénierie de la série : une fois qu’un agent peut enquêter et proposer des modifications, que doit faire le système environnant pour rendre ces expériences utiles ? Un plus grand nombre de tentatives ne suffit pas à établir de meilleures décisions. Un évaluateur faible peut récompenser une modification nuisible, et un processus de recherche peut exploiter cette faiblesse à répétition. Nous testerons la valeur des propositions agentiques par rapport à des alternatives plus simples, plutôt que de supposer qu’elles sont avantageuses.
Comment les six parties construisent un même système
Les articles développeront un projet compagnon cumulatif. Chaque partie reprend une question laissée ouverte par l’expérience précédente et ajoute le mécanisme nécessaire pour l’examiner.
| Partie | Question | Ce qu’elle ajoute au même système |
|---|---|---|
| 1. Des traces à une meilleure mémoire | Peut-on transformer un échec en amélioration révisable ? | Un outil de mémoire, un proposeur LLM, des expériences bornées, du feedback et des preuves conservées. |
| 2. Le rendre évaluable | L’évaluateur reconnaît-il les modifications utiles, y compris les gains apparents qui causent des dommages ? | Une évaluation renforcée, de faux gains délibérés et des vérifications sur ce que les scores permettent d’établir. |
| 3. Le harness d’amélioration | Quelles parties peut-on réutiliser entre les cibles et les modes de travail ? | Une exécution, un historique et des permissions partagés pour les proposeurs humains, classiques et LLM. |
| 4. Comparer les stratégies de recherche | Quelle part du travail de proposition vaut-il la peine de déléguer à un agent ? | Des comparaisons avec une recherche humaine et classique à budgets et modifications autorisées identiques. |
| 5. Amélioration assurée | Quelles preuves suffisent pour adopter un vainqueur apparent ? | Des tests adversariaux plus approfondis, une adoption par étapes et des contrôles de rollback. |
| 6. De l’historique aux données d’entraînement | Des expériences examinées peuvent-elles améliorer un composant appris ? | Une petite expérience d’entraînement d’un vérificateur ou d’une politique, comparée à des réparations plus simples. |
Les vérifications de confidentialité et la revue humaine doivent être présentes dès la première version. La partie 5 renforcera cette protection à mesure que le proposeur gagnera en capacités. De même, la partie 6 étudiera une utilisation possible des preuves accumulées ; chaque partie précédente doit rester utile sans entraîner un nouveau modèle.
Donner à l’agent externe une cible réduite et inspectable
Imaginez un assistant qui se souvient des informations de compte d’Ada. Le 1er janvier, il apprend qu’elle vit à Berlin. Le 3 janvier, il apprend qu’elle déménagera à Paris à compter du 10 janvier. Lorsqu’on lui demande sa ville le 5 janvier, il répond Paris.
La mémoire contient les deux faits. La règle de retrieval privilégie celui qui a été reçu le plus récemment sans vérifier sa date de validité. Il s’agit d’un échec concret qu’un agent d’amélioration peut analyser.
La cible est volontairement limitée à un outil de mémoire, et non à un assistant complet. Il reçoit des faits préparés, les stocke ou les rejette, puis récupère une valeur pour une question. Son writer, sa gestion des dates, son retrieval et la sélection de la réponse sont codés en Python classique. Nous laissons l’extraction depuis la conversation et la génération de réponses en langage naturel hors de cette expérience afin de pouvoir identifier précisément l’effet d’une modification de règle.
Le LLM se trouve dans la boucle externe de l’expérience Python. L’agent reçoit les résultats des tests, décide quels paramètres modifier et reçoit le résultat suivant en retour. Les campagnes enregistrées utilisent effectivement un modèle pour choisir ces modifications.
Cette séparation nous permet de tester la boucle d’ingénierie sans introduire une deuxième source de comportement de modèle à l’intérieur de l’outil de mémoire. Dans une application plus vaste, les deux boucles pourraient utiliser des modèles. Ici, un seul LLM suffit à rendre le processus d’amélioration agentique. Un autre LLM peut tenir le même rôle de proposeur ; ses propositions doivent respecter le même schéma et passer les mêmes vérifications.
Inspecter l’expérience
Le repository compagnon sur GitHub contient l’agent externe, l’outil de mémoire, les tests et des rapports concis issus de trois campagnes LLM réelles. Les requêtes, réponses et traces complètes sont disponibles dans une archive de preuves avec checksum. Le rapport d’expérience suit les modifications proposées, leurs résultats mesurés et chaque décision d’arrêt. Plus loin dans l’article, nous utiliserons le repository pour lancer une nouvelle campagne.
Comprendre un test avant de lire le score
Un scénario est une histoire de test complète. Un événement est une action envoyée à l’outil de mémoire : écriture, requête ou suppression. Le scénario du déménagement futur comporte quatre événements :
- Enregistrer
city = Berlin, valide à compter du 1er janvier. - Enregistrer
city = Paris, reçu le 3 janvier mais valide à compter du 10 janvier. - Demander la ville le 5 janvier. La réponse attendue est Berlin.
- Demander la ville le 12 janvier. La réponse attendue est Paris.
Les entrées sont déjà structurées. Par exemple, le fait concernant Paris identifie le propriétaire (north workspace, utilisateur ada), le sujet (account), la propriété (city), la valeur (Paris) et la date de début de validité. Les chaînes Berlin et Paris proviennent des données de test, et non d’un modèle générant des souvenirs à partir d’une conversation.
La confiance est un score fourni, utilisé pour décider si un fait proposé doit être stocké. Le writer le compare à min_confidence. Une proposition delivery = courier avec un score de 0.4 est rejetée avec le seuil de référence 0.7, mais stockée avec un seuil de 0.2. L’auteur du test fournit le score ; il ne s’agit pas d’une probabilité mesurée que la proposition soit correcte. Nous évaluons la manière dont la règle de stockage traite ces scores, et non la capacité d’un modèle à les estimer de manière fiable.
Chaque scénario commence avec une liste Python vide de records mémoire. Les mises à jour acceptées ferment la période de validité de la valeur précédente et ajoutent un nouveau record. Après les deux écritures concernant la ville, les records décrivent :
| Valeur | Reçue le | Valide à partir du | Valide jusqu’au |
|---|---|---|---|
| Berlin | 1er janvier | 1er janvier | 10 janvier, exclu |
| Paris | 3 janvier | 10 janvier | Aucune date de fin |
La fonction de réponse renvoie le premier record récupéré correspondant à la propriété demandée. L’évaluateur compare cette valeur avec la réponse attendue. Un scénario complet ne réussit que si toutes les réponses sont correctes et si toutes les vérifications de règles de données applicables réussissent. La suppression, l’isolation entre propriétaires et les écritures interdites font l’objet de vérifications explicites en plus de la qualité des réponses.
Les tests fournissent directement les IDs des propriétaires ; cette démonstration ne comporte pas de système d’authentification. Un service réel doit obtenir ces IDs à partir de la requête authentifiée. Rejeter une entrée explicitement étiquetée comme instruction ne démontre pas non plus la détection d’instructions dissimulées dans du texte ordinaire.
Donner également un schéma à la mémoire
Les faits ont besoin de leurs propres règles. J’utilise Schema-Guided Agent Memory (SGAM) pour désigner le pattern dans lequel des schémas gouvernent l’état stocké et son cycle de vie. Ici, nous en démontrons une petite partie : faits typés, propriété, références aux sources, intervalles de validité et suppression. Le schéma SGR ultérieur gouvernera ce que l’agent externe peut proposer ; ce schéma mémoire gouverne ce que l’outil peut stocker.
Le record Paris après la deuxième écriture contient :
{
"tenant": "north",
"user": "ada",
"entity": "account",
"key": "city",
"value": "Paris",
"confidence": 0.95,
"source": "user",
"valid_from": "2026-01-10",
"schema_version": 1,
"memory_type": "fact",
"id": "m002",
"source_event_id": "future-move:event-2",
"observed_at": "2026-01-03",
"valid_to": null,
"supersedes_memory_id": "m001"
}
source_event_id pointe vers l’événement qui a fourni Paris. supersedes_memory_id relie Paris au record Berlin, m001. schema_version: 1 identifie le format du record ; cela ne signifie pas que le programme peut migrer automatiquement les anciennes données.
MemoryRecord et Memory.write() imposent ce format. Les références de source manquantes, les dates invalides et les champs mal formés sont rejetés avant toute modification de l’historique stocké. Un intervalle fermé doit se terminer après son début. Berlin peut se terminer le 10 janvier tandis que Paris commence ce jour-là ; aucun des deux records ne possède un intervalle vide.
Supposons que l’écriture suivante indique Rome, également valide à compter du 10 janvier. Le writer rejette ce conflit et laisse Paris inchangé. Un second fait Paris pour la même date réutilise simplement le record. Une mise à jour dont la date de début de validité est antérieure est également rejetée : ce writer réduit ne reconstruit pas l’historique reçu tardivement. Il s’agit de politiques fixes que l’agent externe ne peut pas modifier. Son paramètre deduplicate contrôle les confirmations répétées avec une date de début de validité ultérieure.
La configuration de référence ignore encore volontairement les filtres de sujet et de date lors de la lecture. Elle stocke des records valides, mais peut choisir le mauvais. C’est le défaut que nous demandons à l’agent de corriger. L’isolation entre propriétaires s’applique à toutes les configurations, et la suppression retire toutes les versions de la propriété demandée dans le sujet du propriétaire concerné.
Il s’agit d’une démonstration en mémoire de ces règles SGAM. Elle ne comporte ni base de données durable, ni service de rétention, ni système de migration. Des tests de régression du writer vérifient séparément les écritures rejetées et les limites d’intervalles ; ils ne constituent pas des scénarios supplémentaires dans le score de la campagne de 20 scénarios.
Laisser l’agent choisir une modification
Une campagne est une tentative d’amélioration de la configuration initiale, qui commence avec un historique d’agent vierge. Une itération est un appel au cours duquel l’agent propose une modification ou choisit de s’arrêter. L’itération suivante reçoit le feedback des précédentes.
La campagne commence par l’exécution de la seule configuration de référence. Elle réussit 13 scénarios sur 20. Nous fournissons ensuite à l’agent :
- les paramètres actuels et leur signification ;
- les mesures de référence ;
- les traces des scénarios en échec, des écritures rejetées et des confirmations en double ;
- les modifications qu’il est autorisé à proposer ;
- les propositions précédentes et leurs résultats, lorsqu’il y en a.
La première requête ne contient aucune configuration améliorée prête à l’emploi. Le repository contient également quatre configurations préparées manuellement pour expliquer les mécanismes de mémoire, mais l’agent utilisé en production ne commence pas avec ces réponses.
L’agent peut modifier cinq paramètres de l’outil existant :
| Paramètre | Effet de sa modification |
|---|---|
min_confidence | Modifie le score minimal fourni pour stocker un fait. |
filter_entity | Limite le retrieval au sujet demandé, par exemple domicile plutôt que travail. |
time_aware | Limite le retrieval aux faits valides à la date demandée. |
deduplicate | Réutilise un fait actif identique au lieu de stocker une nouvelle confirmation. |
top_k | Définit le nombre de records sélectionnés avant la construction du contexte de réponse. |
Une proposition peut modifier au maximum deux paramètres. Les valeurs numériques sont bornées : la confiance entre 0 et 1, et top_k entre 1 et 8. Le contrat enregistre les modifications de configuration autorisées pour l’outil ; le schéma de l’agent et le validator ajoutent les règles applicables aux propositions.
L’agent ne dispose ni d’outils shell ni d’outils de système de fichiers dans ce processus. Il ne peut pas modifier Python, les réponses attendues, l’isolation entre propriétaires, le comportement de suppression, le schéma mémoire, la gestion des conflits, le scoring, les budgets ou l’autorité de mise en production. Sa sortie est une donnée que Python peut accepter ou rejeter. Il s’agit d’une petite expérience de configuration, et non d’un sandbox pour du code arbitraire écrit par un agent.
Faire de chaque proposition un decision record SGR
J’utilise Schema-Guided Reasoning pour rendre la décision inspectable. Chaque réponse du modèle comporte les mêmes champs :
| Champ | Ce que le lecteur doit pouvoir inspecter |
|---|---|
observations | Quel scénario et quel événement fournis étayent la modification proposée ? |
hypothesis | Quelle règle semble être à l’origine du problème ? |
predicted_effect | Qu’est-ce qui devrait s’améliorer lors du test de la modification ? |
action | L’agent propose-t-il une modification ou s’arrête-t-il ? |
patch | Quels paramètres autorisés doivent être modifiés ? |
La requête OpenAI Responses utilise un JSON Schema strict généré à partir de modèles Pydantic. Les objets rejettent les champs supplémentaires, et chaque champ de patch est requis mais peut être null, c’est-à-dire « laisser ce paramètre inchangé ». Structured Outputs contraint la forme de la réponse. Python vérifie néanmoins que les références existent, que les valeurs sont autorisées et que la configuration proposée n’a pas déjà été testée.
Le schéma ne prouve pas l’hypothèse et n’expose pas le raisonnement interne du modèle. Il s’agit de decision records concis que nous pouvons confronter aux preuves.
Lors de la première itération enregistrée, l’agent a identifié le retrieval entre sujets et le renvoi de faits en dehors de leur intervalle de validité. Son réponse réelle proposait ce patch :
{
"min_confidence": null,
"filter_entity": true,
"time_aware": true,
"deduplicate": null,
"top_k": null
}
Ces deux paramètres ont été choisis par le modèle. Le runner a fourni l’ID du parent et attribué l’ID du candidat ; le modèle ne pouvait pas rediriger la modification vers un parent ou un fichier arbitraire.
Suivre la modification dans Python
La configuration de référence et la nouvelle configuration stockent les mêmes records Berlin et Paris. La modification proposée agit sur les records que le retrieval peut prendre en compte.
Dans Memory.query(), ces switches activent deux filtres :
if self.config.filter_entity:
eligible = [r for r in eligible if r["entity"] == event["entity"]]
if self.config.time_aware:
eligible = [r for r in eligible if valid_at(r, event["as_of"])]
La vérification de validité inclut la date de début et exclut la date de fin :
def valid_at(item: dict, at: str) -> bool:
return item["valid_from"] <= at and (
item["valid_to"] is None or at < item["valid_to"]
)
Les dates utilisent YYYY-MM-DD ; leur ordre lexicographique correspond donc à leur ordre calendaire. Pour la question du 5 janvier, Paris est exclu car le fait devient valide le 10 janvier. Berlin reste disponible. Pour la question du 12 janvier, Paris est valide et Berlin est historique.
Python exécute la configuration proposée sur les 20 scénarios. Cette première modification fait passer le taux de réussite de 13/20 à 19/20, avec toutes les vérifications strictes implémentées réussies. Elle modifie deux filtres simultanément ; le gain sur l’ensemble de la suite mesure donc leur effet combiné. La trace de la ville montre ce que le filtre de date a fait dans ce cas précis.
Le runner sélectionne cette configuration comme parent de l’expérience suivante. Cette sélection ne la déploie pas. Lors de la requête suivante, le modèle reçoit le résultat mesuré, les paramètres sélectionnés et les preuves restantes.
La décision suivante doit exploiter le résultat
Voici la première campagne complète. Chaque ligne correspond à une réponse réelle du modèle, et non à une étape préécrite dans un script de démonstration :
| Itération | Proposition de l’agent | Action de Python | Meilleur résultat courant |
|---|---|---|---|
| 1 | Activer les filtres de sujet et de date | Validation et test ; amélioration sélectionnée | 19/20 |
| 2 | Dédupliquer les confirmations identiques | Test ; sélection car le stockage diminue sans dégrader les réponses | 19/20 |
| 3 | Réduire min_confidence de 0.7 à 0.6 | Test ; sélection car le dernier scénario en échec réussit | 20/20 |
| 4 | S’arrêter | Décision d’arrêt enregistrée ; aucune modification supplémentaire | 20/20 |
La deuxième réponse citait le scénario des confirmations en double. Ce scénario écrit language = German trois fois. La déduplication conserve un seul record au lieu de trois tout en préservant la réponse. Sur l’ensemble de la suite, le nombre moyen de records stockés passe de 1,70 à 1,60, tandis que le taux de réussite reste à 19/20.
La troisième proposition traitait un autre échec. Une préférence de langue utile avait un score de confiance fourni de 0.6, inférieur au seuil 0.7 courant. Abaisser le seuil à 0.6 l’a admise tout en continuant à rejeter la proposition incertaine concernant le livreur, notée 0.4. Le taux de réussite atteint 20/20 ; le nombre moyen de records stockés devient 1,65, car la mémoire conserve désormais le fait utile supplémentaire.
Lors du quatrième appel, l’agent a choisi de s’arrêter : il ne disposait d’aucune autre modification étayée par les preuves fournies. Il s’agit d’une décision du modèle, et non de la preuve que la configuration est globalement optimale.
La requête suivante contient les résultats actuels et les décisions précédentes. Après avoir constaté que sa correction du retrieval était utile, l’agent s’est intéressé au stockage et à l’admission des écritures. Le runner ne lui a fourni ni ces patches ni une séquence d’étapes préécrite.
La règle de sélection est fixe : toutes les vérifications strictes doivent réussir ; on privilégie ensuite le meilleur taux de réussite des scénarios complets et, à taux égal, le plus petit nombre de records stockés. Un résultat moins bon conserve le parent précédent. Les tests exercent également ce chemin de rejet avec une proposition régressive scriptée ; il ne s’agissait pas d’une régression de qualité mesurée dans ces trois campagnes réelles.
Un run de développement séparé contient un rejet de validation réel : l’agent a cité agent-01, un ID de candidat, comme s’il s’agissait d’un scénario. La réponse respectait le JSON Schema, mais sa référence n’identifiait pas un événement fourni ; Python l’a donc rejetée avant l’évaluation. Le contrôleur renvoie la réponse rejetée et l’erreur de validation précise comme feedback ; des tests offline vérifient ce comportement. Les trois campagnes présentées ci-dessous n’ont rencontré aucun échec de validation.
Répéter la campagne de recherche, pas le test déterministe
La même configuration de mémoire et les mêmes entrées produisent les mêmes réponses. Répéter cette évaluation n’ajoute aucune preuve sur la qualité des réponses. Le runner vérifie une nouvelle configuration une seule fois et réutilise les résultats vérifiés des parents pour les comparaisons.
L’agent externe peut choisir des propositions différentes ; nous avons donc exécuté trois campagnes indépendantes. Chacune a commencé au même niveau de référence, 13/20, a reçu un historique vierge et disposait d’au plus quatre décisions du modèle. Aucune campagne n’a reçu les découvertes de la campagne précédente.
| Campagne | Décisions du modèle | Propositions évaluées | Propositions rejetées avant évaluation | Réussite sélectionnée | Motif de fin |
|---|---|---|---|---|---|
| 1 | 4 | 3 | 0 | 20/20 | L’agent s’est arrêté |
| 2 | 4 | 3 | 0 | 20/20 | L’agent s’est arrêté |
| 3 | 4 | 3 | 0 | 20/20 | L’agent s’est arrêté |
Les trois campagnes ont choisi la même séquence : activer les deux filtres de retrieval, dédupliquer les confirmations, réduire le seuil de confiance à 0.6, puis s’arrêter.
Il y a eu 12 appels au modèle : neuf propositions évaluées par Python, suivies de trois décisions d’arrêt. Chaque campagne a exécuté la configuration de référence plus trois nouvelles configurations sur 20 scénarios : 80 exécutions de l’outil de mémoire par campagne. Les 20 scénarios sont restés identiques.
Les trois campagnes ont sélectionné les mêmes paramètres finaux. Il s’agit d’une observation limitée à un modèle, un prompt, une cible et une suite de tests publics donnés. Elle n’estime pas la fiabilité avec laquelle l’optimizer améliorera des systèmes inconnus. Une comparaison plus solide viendra plus tard dans la série : campagnes répétées avec des budgets identiques, méthodes de proposition concurrentes et tests que le proposeur ne peut pas inspecter.
Lire la qualité et le coût au bon niveau
L’expérience comporte deux coûts distincts. L’exécution de l’outil de mémoire utilise du temps CPU local et n’effectue aucun appel de modèle. L’exécution du proposeur externe utilise des tokens d’entrée et de sortie. Un champ de coût fournisseur nul dans un rapport d’évaluation de la mémoire décrit uniquement l’outil interne ; il ne représente pas le coût de la campagne.
Pour l’étude enregistrée le 11 septembre 2026, nous avons utilisé GPT-5.6 Luna (gpt-5.6-luna), avec un effort de raisonnement low, le schéma SGR et les instructions sauvegardés, ainsi qu’un maximum de 4 096 tokens de sortie par appel. Le programme a désactivé les retries automatiques du SDK et fixé un timeout de requête de 60 secondes. Les requêtes exactes, les IDs de modèles renvoyés, l’usage et la durée des appels sont conservés.
L’estimation du coût fondée sur les tokens pour les 12 appels au modèle est de USD 0.039177, pour un budget configuré de USD 0.50. Le calcul utilise les tarifs publiés du modèle, inclut le surcoût d’écriture du cache signalé dans l’usage et ignore les remises de lecture du cache. Il s’agit d’une estimation prudente à partir de l’usage enregistré, et non d’une facture. Le matériel et le temps de développement ne sont pas inclus.
Avant chaque appel, le runner réserve une estimation haute fondée sur une taille d’entrée bornée et un nombre maximal de tokens de sortie. Si le budget restant ne peut pas couvrir cette réservation, il s’arrête. Les appels échoués ou interrompus restent dans l’enregistrement ; lorsque l’usage est indisponible, le montant réservé est conservé plutôt que traité comme nul.
Pour la qualité des réponses, 20/20 signifie que toutes les réponses et toutes les vérifications strictes applicables ont réussi sur ces 20 scénarios préparés. Cela ne signifie pas que la mémoire est prête pour la production. Tous les scénarios sont des cas de développement publics ; les traces sélectionnées et le feedback de la suite sont accessibles au proposeur. Ils couvrent les mises à jour, les questions historiques, l’incertitude, les doublons, les distracteurs, la séparation entre propriétaires, la suppression et les écritures interdites. Les labels search, evaluation et adversarial organisent la suite originale ; ils ne transforment aucun de ces cas en test set caché.
Cette petite suite s’inspire de LongMemEval, MemoryAgentBench, VehicleMemBench et GateMem. Les entrées et le scoring utilisés ici nous appartiennent ; les résultats ne reproduisent pas ces benchmarks.
Vous pouvez également comparer quatre configurations préparées manuellement dans le repository. Elles montrent pourquoi accepter davantage de faits peut dégrader les réponses et comment améliorer le stockage sans améliorer la qualité des réponses. Elles illustrent aussi le versant spécifié par l’humain de la même infrastructure d’expérimentation : l’auteur fournit les candidats et Python les évalue. Ce sont des comparaisons pédagogiques utiles, et non des preuves que la recherche agentique surpasse un humain compétent ou une autre méthode de recherche.
Exécuter une nouvelle campagne agentique
Pour laisser l’agent choisir de nouvelles propositions, clonez le projet compagnon et téléchargez les preuves enregistrées :
git clone --branch v0.2.2 --depth 1 https://github.com/slavadubrov/meta-engineering-ai-lab.git
cd meta-engineering-ai-lab
uv sync --frozen
uv run --frozen python scripts/fetch_evidence.py
uv run --frozen python -m lab verify artifacts/agent-study-03 --source
Le téléchargement vérifie le SHA-256 et restaure les enregistrements complets sous artifacts/. Il n’effectue aucun appel de modèle. Si vous avez déjà téléchargé les preuves, ignorez cette étape et exécutez la commande de vérification.
Enregistrez un OPENAI_API_KEY dans un fichier local .env.local. Le repository ignore ce fichier. Exécutez ensuite :
uv run --frozen --env-file .env.local python -m lab campaign \
--live --campaigns 3 --iterations 4 --budget-usd 0.50 \
--output artifacts/my-agent-study
--live active explicitement les appels au fournisseur. La présence d’une clé dans l’environnement n’active pas les commandes offline de mémoire ni le navigateur en tant qu’agent live. --campaigns 3 crée trois historiques d’agents indépendants ; --iterations 4 limite le nombre de décisions dans chacun. Utilisez un nouveau répertoire de sortie pour chaque étude : les preuves existantes ne sont jamais écrasées.
Ouvrez artifacts/my-agent-study/report.md pour consulter les résultats de la campagne et les liens vers chaque requête, réponse et évaluation Python. Comparez les modifications proposées avec la campagne enregistrée ci-dessus : l’agent peut choisir différemment même si les tests de mémoire sont déterministes.
Le README répertorie le code et les commandes. Le rapport de campagne figé ainsi que le checksum de l’archive et l’index d’exemples permettent au lecteur d’inspecter directement les preuves de cet article.
Séparer l’historique des expériences de la mémoire utilisateur
L’outil de mémoire stocke la ville et la langue d’Ada. L’historique des expériences stocke ce que l’agent a vu, le patch proposé, les éventuels rejets, les mesures obtenues et la configuration devenue le parent suivant. Ces stockages répondent à des objectifs différents.
Chaque itération conserve la requête exacte avec ses instructions et son schéma, la réponse du fournisseur, l’usage et le timing, le résultat de la validation ainsi que toute évaluation terminée. Les propositions échouées restent visibles. Les hash des fichiers lient les preuves sauvegardées à l’implémentation et aux entrées utilisées pour l’expérience.
Il s’agit de faits synthétiques ; l’enregistrement public peut donc conserver les états complets. Les traces réelles nécessitent une politique de rétention distincte : supprimer un fait de l’outil de mémoire n’efface pas les copies précédentes présentes dans les logs d’expérience ou les sauvegardes. Le test de suppression de la démonstration vérifie les records de l’outil et les lectures ultérieures, mais pas l’effacement dans tous les stockages possibles.
Ce que le prochain article devra remettre en question
Nous avons maintenant un agent intégré à la boucle d’amélioration. Il propose une modification, reçoit un résultat mesuré, choisit la modification suivante et peut décider de s’arrêter. Les propositions invalides suivent un chemin de rejet distinct et restent enregistrées. Son autorité est limitée à la configuration ; les tests et la revue de mise en production restent des responsabilités séparées.
Le prochain risque concerne l’évaluateur lui-même. Si la réussite récompense la conservation de chaque fait, l’agent peut apprendre à conserver des suppositions. Si une suite pose uniquement des questions sur la ville actuelle, elle peut ne pas détecter une modification qui détruit un historique utile. Un proposeur plus capable peut exploiter plus efficacement des mesures faibles.
La partie 2, Rendre le système évaluable avant de le rendre autonome, demande comment tester ces mesures avant d’accorder davantage de liberté au proposeur. Le 20/20 de la première campagne constitue le point de départ de cette investigation.