Pierre KasparianAI & Data freelancer
← Retour à la catégorie
agent IARAG multitenants productionvector databaseElasticsearchpipeline données LLM

Mémoire persistante pour agents IA avec Elasticsearch

19 juin 2026 · 7 min de lecture · Guides

Pierre Kasparian

Freelance intégration IA · Spécialiste LLM, RAG · 11+ réalisations clients

Les agents IA ont un problème de mémoire. Pas au sens de la RAM, mais au sens de la continuité : dès que la session se ferme, tout ce qu'un utilisateur a dit, tenté ou résolu disparait. La fenêtre de contexte est un tampon de travail, pas un système de mémoire.

Réponse directe : une mémoire persistante pour agent IA, c'est un store externe structuré en plusieurs types (épisodique, sémantique, procédural), requêtable par contenu et par temps, avec isolation stricte des données par utilisateur. L'équipe Elasticsearch Labs a publié une implémentation complète sur ce sujet, atteignant un R@10 de 0,89 sur 168 questions avec zéro fuite entre tenants.

Pourquoi la fenêtre de contexte ne suffit pas

Injecter l'historique complet des échanges passés dans le contexte semble une solution simple. Elle se casse rapidement en production pour trois raisons.

Coût et latence. Chaque appel grossit à mesure que les sessions s'accumulent. Pour un assistant en production avec des centaines d'utilisateurs actifs, le coût d'inférence devient un problème réel.

L'effet "lost in the middle". Les modèles ont tendance à ignorer les informations placées loin des bords de la fenêtre de contexte. Un fait critique mentionné il y a trois sessions peut tout simplement disparaitre de l'attention du modèle.

La non-persistance. Un crash, une déconnexion, une session expirée : tout est perdu. Pour un assistant qui accompagne un client sur plusieurs semaines, c'est rédhibitoire.

Les trois indices : épisodique, sémantique, procédural

L'architecture repose sur trois indices Elasticsearch distincts, inspirée du modèle COALA de la psychologie cognitive.

TypeContenuDurée de vie
EpisodiqueChaque message utilisateur, horodatéCourt terme, décroissance par decay
SémantiqueFaits stables sur l'utilisateur ("Sarah a un Hub v2")Long terme, mis à jour par supersession
ProcéduralPlaybooks multi-étapes avec compteurs succès/échecLong terme, affiné par feedback

Cette séparation permet de donner à chaque type de mémoire son propre cycle de vie : la mémoire épisodique s'accumule vite et décroit, la mémoire sémantique est curatée et mise à jour, la mémoire procédurale s'améliore avec les retours utilisateurs.

À côté de ces trois indices, un quatrième est consulté en lecture seule : le catalogue produit ou la base de connaissances de l'entreprise. L'agent le requête via le même pipeline que ses mémoires, sans friction supplémentaire.

Le pipeline de rappel : hybrid retrieval + cross-encoder

Chaque requête de rappel passe par deux étapes.

Étape 1 : retrieval hybride avec RRF.

Le document est indexé deux fois depuis une seule écriture : le texte brut alimente l'index inversé BM25, et le même texte est routé via copy_to vers un champ semantic_text qui génère automatiquement des vecteurs denses Jina v5. Les deux legs sont fusionnés par Reciprocal Rank Fusion (RRF) avec un rank_constant=30, ce qui donne plus de poids aux positions hautes que la valeur par défaut d'Elasticsearch (60).

BM25 ancre les correspondances littérales (codes erreur, numéros de version, noms propres). Les vecteurs denses capturent la forme sémantique d'une question dont la réponse utilise des mots différents. Ni l'un ni l'autre seul ne couvre tous les cas : les deux ensemble oui.

Étape 2 : reranker cross-encoder Jina v2.

Le retriever hybride sur-fetche 80 candidats par leg. Ces candidats sont ensuite reordonnés par un cross-encoder Jina v2, qui score chaque paire (requête, document) en tandem plutôt que de comparer des embeddings indépendants. C'est le même principe que dans mon guide sur les rerankers cross-encoders : on sobre-fetche rapidement, on reclasse précisément.

Ce pipeline atteint un R@10 de 0,89 sur un jeu d'évaluation de 168 questions.

Isolation multi-tenant avec DLS

C'est le point que je trouve le plus important pour une utilisation en entreprise : l'isolation des données entre utilisateurs.

Elasticsearch Document Level Security (DLS) permet d'attacher des restrictions directement aux clés API. Chaque utilisateur dispose d'une clé qui ne peut requêter que ses propres documents. Cette isolation est appliquée au niveau de l'index, pas dans le code applicatif. Résultat : zéro fuite entre tenants sur l'ensemble des tests, sans surcharge de développement.

# Chaque requête est automatiquement filtrée par user_id via DLS
# Pas besoin de filtres applicatifs manuels
recall_results = es.search(
    index="agent_memory_semantic",
    query=hybrid_query,
    knn=dense_query
    # Le DLS ajoute automatiquement : filter: { term: { user_id: current_user } }
)

Pour un contexte RGPD, cette isolation au niveau du moteur de stockage est bien plus solide qu'une isolation applicative : même un bug dans le code ne peut pas exposer les données d'un utilisateur à un autre.

Écriture et consolidation

Écriture épisodique. Chaque message utilisateur est écrit dans l'index épisodique avant que le LLM réponde. Les réponses de l'agent ne sont pas stockées : elles sont portées par l'historique de conversation et dilueraient le rapport signal/bruit.

Consolidation. Périodiquement (ou à chaque tour en mode démo), un LLM de consolidation examine les épisodes récents et en extrait :

  • De nouveaux faits sémantiques avec leurs supporting_episode_ids
  • De nouveaux playbooks procéduraux si une résolution multi-étapes n'a pas de match existant
  • Des mises à jour de compteurs (success_count++ / failure_count++) si l'utilisateur confirme ou rejette un fix

Supersession. Quand un fait entre en contradiction avec un nouveau message ("j'ai déménagé à Édimbourg"), l'agent ne supprime pas le fait précédent. Il le marque superseded_by=nouveau_id et superseded_at=maintenant. Le recall standard filtre automatiquement les facts supersédés (filter must_not exists field=superseded_by). L'audit trail reste intact dans l'index pour les requêtes de type "où a-t-elle vécu ?".

Ce que ça donne en production

Cette architecture rend les agents beaucoup plus utiles sur des interactions longues : l'agent sait ce qui a été tenté, ce qui a fonctionné, et les préférences stables de l'utilisateur. Il ne repart pas de zéro à chaque session.

L'implémentation complète est disponible en open source sur GitHub (lien dans l'article Elasticsearch Labs). Elle expose ses tools via le protocole MCP, ce qui la rend compatible avec n'importe quel runtime d'agent.

Les points de vigilance pour la mise en production :

  • La consolidation per-turn double les appels LLM par message. En production, un job batch toutes les 24h ou au-delà d'un seuil N d'épisodes est plus économique.
  • Le decay des épisodes évite que l'index episodique ne devienne un foin. Configurer le decay_factor selon la durée de vie souhaitée.
  • Les compteurs success_count / failure_count des playbooks procéduraux ne sont pas encore utilisés pour biaiser le ranking dans l'implémentation initiale. En production, les connecter au score de retrieval permet de faire remonter automatiquement les playbooks qui ont fonctionné.

TL;DR

Une mémoire d'agent robuste repose sur trois indices séparés (épisodique, sémantique, procédural), un retrieval hybride BM25 + dense + cross-encoder reranker, et une isolation DLS par tenant. C'est constructible sur Elasticsearch avec une implémentation open source existante. Le résultat : R@10 = 0,89, zéro fuite entre utilisateurs.

Si vous intégrez des agents IA dans votre entreprise et que la mémoire multi-session ou l'isolation des données sont des contraintes, parlons-en.

À propos de l'auteur

Pierre Kasparian

Étudiant ingénieur en fin de cursus à l'UTT (Université de Technologie de Troyes) et freelance en intégration IA. Il déploie des LLM, pipelines RAG et agents IA pour des PME françaises et européennes, avec une attention sur le RGPD et hébergement européen. 11+ réalisations clients, dont Pretto et LiveSession.