Sommaire

  1. C'est quoi, la mémoire des agents ?
  2. La base commune : où et quoi stocker
  3. Le vrai défi : les conversations longues
  4. Tableau récapitulatif des techniques
  5. Le cas Podlet : mes choix et mes réflexions
  6. Et vous, quelle approche utilisez-vous ?
  7. Pour aller plus loin

C'est quoi, la mémoire des agents ?

Si vous utilisez ChatGPT ou la plupart des applications de chat populaires, vous n'y prêtez sans doute pas attention : la gestion de la mémoire est déjà intégrée à l'application web. Quand vous démarrez une conversation, l'IA se rappelle vos interactions précédentes. Derrière cette apparente simplicité, chaque application doit faire des choix — totalement transparents pour vous — qui déterminent comment les conversations et les informations qu'elles contiennent sont sauvegardées.

Vous pouvez facilement identifier les limites de ces choix : lancez une conversation relativement longue. À un moment donné, vous constaterez que les réponses deviennent moins pertinentes, que l'agent commence à inventer des choses, à oublier des détails importants ou à ne plus vraiment suivre ses directives.

Il n'existe pas de solution miracle qui résolve tous ces problèmes simultanément. Mais les applications populaires ont mis en place des techniques éprouvées. Si vous envisagez de créer des agents de zéro, vous allez, vous aussi, être confronté à ces décisions.

Dans cet article, je vous présente ces techniques, ce qu'elles impliquent concrètement, et comment choisir celle qui correspond à votre projet. Pas de code ici : uniquement le raisonnement et les critères de choix.

À qui s'adresse cet article ? Aux développeurs et architectes qui construisent des applications à base de LLM et qui doivent implémenter leur propre gestion de mémoire conversationnelle, ainsi qu'aux utilisateurs curieux de comprendre ce qu'il y a derrière les chats IA qu'ils utilisent quotidiennement.


La base commune : où et quoi stocker

Choisir son support de stockage

Première brique indispensable : il faut persister les informations quelque part. Deux grandes familles s'offrent à vous.

SolutionAvantagesInconvénients
Base de données (SQLite, PostgreSQL, etc.)Évolutive, facile à sauvegarder, utilisable avec un service cloud managéL'utilisateur ne peut pas simplement ouvrir un fichier pour consulter ou modifier les données
Fichier (Markdown, JSON, JSONL)Modifiable facilement par un humain, simple à inspecterNécessite des fonctions de lecture/écriture supplémentaires ; moins robuste à grande échelle

Pour Podlet, j'ai choisi une base de données. La fiabilité et la flexibilité sont supérieures, ce qui facilite les évolutions futures de l'application. C'est un choix cohérent avec l'architecture globale : Podlet tourne en local avec Docker et une base SQLite légère, ce qui permet de garder l'application simple à déployer tout en restant robuste.

comparatif base de donnée vs fichier

Les types de messages à sauvegarder

Un agent comprend généralement quatre types de messages :

  • Utilisateur : un message envoyé par l'humain
  • Assistant : une réponse générée par l'agent
  • Outil (tool) : le résultat de l'utilisation d'un outil (recherche web, exécution de commande, etc.)
  • Système : une directive générale qui cadre le comportement de l'agent

Ce que vous choisissez de sauvegarder — ou pas — dépend directement du design de votre application. Voyons deux cas de figure.


Cas n°1 : application multi-agents

Dans une application où l'utilisateur peut changer d'agent (et donc d'outils disponibles) au sein d'une même conversation, les réponses d'outils ne doivent pas persister telles quelles — ou du moins pas sans transformation préalable.

Pourquoi ?

Imaginez : vous utilisez un agent équipé d'un outil de recherche web. Vous changez ensuite d'agent, et ce dernier n'a pas cette capacité. Il voit pourtant dans l'historique des appels à l'outil de recherche et tente de les reproduire. Comme l'outil n'est pas disponible, aucun résultat n'est retourné : erreur garantie.

Cela implique également qu'au sein d'une même conversation, un agent devra probablement appeler plusieurs fois le même outil avec la même requête (relire un fichier, refaire une recherche), puisque les résultats précédents ne sont pas conservés.

Ce qu'il faut faire : chaque message doit être analysé avant stockage, et les tool calls doivent être retirés. Il faut accepter qu'au cours de la conversation, des appels redondants soient effectués.

L'alternative (non recommandée) : vous pouvez tenter de conserver les appels d'outils, mais certains modèles deviendront incompatibles et les risques de confusion augmentent. Une piste plus sophistiquée consiste à extraire, reformuler puis intégrer les résultats d'outils directement dans un message assistant. Par exemple, un tool call execute command xyz qui retourne ABC pourrait être transformé en : « La commande xyz donne le résultat ABC. » Cela demande néanmoins de connaître à l'avance toute la palette d'outils disponibles.


Cas n°2 : agent unique

Dans ce cas, vous pouvez stocker et réutiliser l'historique complet, y compris les appels d'outils et leurs résultats, sans problème.

Avantage : pour des conversations assez courtes avec le prompt caching activé (disponible chez OpenAI, Anthropic et Google), c'est souvent un excellent moyen d'économiser des tokens — jusqu'à 90 % de réduction sur les coûts pour les messages mis en cache. Les messages d'outils, souvent répétitifs, sont d'excellents candidats au cache.

Inconvénient : le contexte se remplit rapidement. Au-delà de la limite maximale de tokens, la requête est tout simplement rejetée par le fournisseur.


Le vrai défi : les conversations longues

Quand je parle de « chat long », je désigne une conversation comptant de nombreux échanges entre l'utilisateur et l'agent.

Ce qui se passe quand le contexte grossit

Plusieurs phénomènes se manifestent à mesure que le contexte s'allonge.

Dilution du prompt système. Chaque nouveau message ajoute des tokens. Plus la conversation avance, plus les tokens du prompt système sont dilués dans la masse. Résultat : l'identité de l'agent s'efface progressivement au profit des messages les plus récents. Ce phénomène est bien documenté par la recherche : le papier fondateur « Lost in the Middle: How Language Models Use Long Contexts » (Liu et al., TACL 2024) montre que les LLM peinent à exploiter les informations situées au milieu d'un long contexte — exactement là où finissent vos instructions système après quelques dizaines d'échanges. Conséquence : la lecture des skills devient moins fiable, l'utilisation des outils peut être affectée, le taux d'hallucination augmente, et les réponses perdent globalement en fiabilité.

graphique ou diagramme illustrant la dilution du
prompt système au fil des messages, avec une courbe descendante montrant la
« part de tokens système » dans le contexte total

Dépassement de la limite de contexte. Chaque modèle a une fenêtre de contexte maximale (exprimée en tokens). Une fois cette limite atteinte, le fournisseur rejette purement et simplement la requête.


Les techniques pour réduire le contexte

Aucune n'est parfaite. Chacune a ses avantages et ses angles morts. Voici le panorama.


1. Le résumé

C'est l'approche la plus intuitive : plutôt que de transmettre l'intégralité de l'historique, on en fait un résumé — partiel ou complet.

Mais même cette technique, qui paraît simple, cache une multitude de décisions. Quel system prompt donner à l'agent chargé du résumé ? À quel moment déclencher la synthèse : après chaque nouveau message ? Remplacer les X messages les plus anciens ? Résumer à partir d'un certain seuil de tokens ?

Bilan : cela entraîne inévitablement une perte d'information au fil de la conversation, mais peut s'avérer extrêmement efficace pour réduire la consommation de tokens sur des échanges très longs.


2. La suppression (sliding window)

C'est l'une des techniques les plus simples : on ne transmet tout simplement pas certains messages à l'agent.

Principe : le system prompt est toujours inclus, puis on ajoute les X derniers messages jusqu'à une limite de tokens définie. Si l'ensemble des messages cumule moins de tokens que la limite, tout est transmis. Sinon, les messages les plus anciens sont tout bonnement ignorés.

Avantage majeur : l'accent est mis sur les derniers échanges. Cette approche est particulièrement adaptée aux applications à chat unique. Elle permet de changer de sujet rapidement tout en conservant une forme de continuité.

⚠️ Limite : toute information antérieure à la fenêtre est définitivement perdue pour l'agent. Si l'utilisateur fait référence à un élément évoqué 15 messages plus tôt, l'agent n'en aura tout simplement pas connaissance.


3. Le RAG (Retrieval-Augmented Generation)

C'est la technique la plus avancée, qui se décline en de nombreuses variantes et peut être combinée avec les précédentes.

Le principe : on stocke les messages (ou les informations qu'ils contiennent) de manière indépendante. Au moment de construire l'historique à transmettre à l'agent, on ne récupère que les informations pertinentes par rapport au dernier message utilisateur.

La mise en œuvre classique :

  1. Découpage (chunking) des messages en morceaux
  2. Vectorisation de chaque morceau avec un modèle d'embedding dédié
  3. Stockage des vecteurs, avec potentiellement des tags supplémentaires (user, tool, assistant, ou même des tags générés automatiquement par un agent spécialisé)
  4. Recherche (retrieval) des chunks les plus pertinents au moment de l'inférence
  5. Reconstruction d'un historique ciblé (ou d'un message unique) à partir des fragments récupérés

Je ne développe pas davantage ici, car je prépare un article entièrement dédié aux variations de cette technique (stay tuned sur le blog !). Mais globalement, le RAG est redoutablement efficace sur les très longues conversations, surtout couplé à un résumé. Pour approfondir, je vous recommande la survey complète sur le RAG (Gao et al., 2024) qui couvre l'ensemble des architectures.

schéma en plusieurs étapes illustrant le pipeline
RAG appliqué à l'historique conversationnel : chunking → vectorisation →
stockage → retrieval → reconstruction


4. Le fichier mémoire (NOTES.md)

Cette technique consiste à injecter dans le system prompt une instruction qui oblige l'agent à maintenir et charger un fichier séparé — typiquement un NOTES.md. L'agent édite ce fichier à chaque tour de conversation.

Points forts :

  • Très efficace en termes de tokens
  • Cumulable avec d'autres techniques
  • Permet de débuter chaque tour avec uniquement le system prompt et le dernier message utilisateur
  • Réduit drastiquement l'utilisation de tokens
  • Peut même éviter complètement le stockage de l'historique, qui devient « auto-géré » par l'agent

Points faibles :

  • Complexité ajoutée dans les tâches de l'agent (tenir un fichier à jour)
  • Sur des tâches complexes, risque que l'agent ne mette pas à jour le fichier correctement, voire pas du tout

Pour qui ? C'est une méthode redoutable pour les petits projets (elle évite de mettre en place une base de données) comme pour les gros projets mono-agent. Cette approche s'inspire directement de MemGPT (Packer et al., 2023), un système qui gère intelligemment différents « étages » de mémoire pour étendre le contexte effectif des LLM — un papier que je vous conseille vivement si le sujet vous passionne.


5. Accepter (et passer à autre chose)

Ce n'est pas vraiment une « technique », mais c'est une décision de design tout à fait viable. Elle consiste à reconnaître que toutes les techniques ont leurs limites et à accepter les inconvénients des conversations longues. Une fois la limite de contexte atteinte, il faut simplement recommencer un nouveau chat.

Les meilleurs modèles — particulièrement à partir de Gemini 1.5 Pro avec sa fenêtre de 2 millions de tokens — sont aujourd'hui capables de gérer des contextes gigantesques, ce qui rend cette approche de plus en plus crédible pour de nombreux cas d'usage. Cela dit, même avec 2M de tokens, le phénomène de « Lost in the Middle » persiste : la taille ne fait pas tout.

Pour une comparaison concrète des modèles et de leurs performances respectives sur des tâches de génération, jetez un œil à mon comparatif ChatGPT vs Claude vs Kimi.


Tableau récapitulatif des techniques

TechniqueComplexitéÉconomie de tokensRisque de perte d'infoMulti-agent friendly
Résumé⭐⭐⭐⭐⭐Élevé
Suppression⭐⭐Très élevé
RAG⭐⭐⭐⭐⭐⭐⭐Faible
Fichier mémoire⭐⭐⭐⭐⭐⭐Faible⚠️
AccepterAucun

Le cas Podlet : mes choix et mes réflexions

Pour Podlet, j'ai initialement fait le choix de ne pas ajouter de couche supplémentaire au-delà de la simple sauvegarde des messages. Je ne stocke ni les appels d'outils ni leurs résultats, afin de pouvoir changer d'agent librement au sein d'une même conversation.

Cependant, je considère sérieusement l'ajout d'une option de gestion avancée de l'historique. Voici mes critères :

  • ✅ Fonctionner avec différents agents dans la même conversation
  • ✅ Présenter un avantage tangible en termes d'utilisation des tokens
  • ✅ Être compatible avec le système de sous-agents déjà en place
  • ✅ Ne pas ralentir massivement le fonctionnement
  • ✅ Pouvoir être activé/désactivé facilement

Honnêtement, avec ces contraintes, le cahier des charges est très serré.

Passons en revue les options :

Le fichier mémoire est conceptuellement séduisant, mais il entre en conflit avec mon architecture multi-agents. Injecter des instructions de gestion de fichier dans le system prompt est idéal… sauf qu'il devient difficile de découpler cette injection entre l'agent principal et les sous-agents. La seule voie réaliste serait de laisser l'utilisateur gérer cela lui-même au niveau de la création de ses agents — ce que je pourrais documenter.

Le résumé est techniquement possible, mais la réactivité en prendrait un coup : après la réponse de l'agent, avant de rendre la main à l'utilisateur, il faudrait invoquer un agent spécialisé pour mettre à jour le résumé. Cela ralentirait significativement les interactions.

Le RAG souffre du même problème de latence, avec en plus la nécessité d'utiliser un modèle d'embedding dédié. Cela dit, il existe aujourd'hui des outils relativement simples qui facilitent grandement l'intégration de cette solution avancée : LangChain pour l'orchestration complète des agents et de leur mémoire, LlamaIndex pour l'ingestion et l'indexation des données, ou encore Chroma pour le stockage vectoriel léger. C'est une piste que je garde sous le coude pour un futur article — et peut-être une future release de Podlet.


Et vous, quelle approche utilisez-vous ?

La gestion de la mémoire des agents est un problème loin d'être résolu, et chaque projet a ses contraintes propres. J'espère que ce tour d'horizon vous aidera à faire vos propres choix.


Pour aller plus loin


Je vous invite à tester Podlet par vous-même : github.com/HellKaiser45/Podlet.git