Context Engineering — Section 6 : Mémoire
Transformer un LLM amnésique en un assistant personnalisé et cohérent.
6. Mémoire : Donner un passé au LLM
- A. Panorama
- B. Scopes de Mémoire
- C. Mémoire Court Terme
- D. Mémoire Long Terme
- E. Architecture
- F. Extraction & MàJ
- G. Évaluation
- H. Pitfalls
- I. Snippets
- J. Playbook
Panorama : Le Problème de l'Amnésie
Par nature, un appel API à un LLM est **stateless**. Chaque requête est indépendante, sans connaissance des précédentes. Sans un système de mémoire externe, un LLM ne peut pas se souvenir de vous, de vos préférences, ou même du début de la conversation en cours. La gestion de la mémoire est le processus qui consiste à **capturer, stocker, et réinjecter le contexte pertinent** des interactions passées dans les nouvelles requêtes.
- Long Terme: Concerne l'historique global avec un utilisateur ou sur un sujet. Permet la personnalisation ("Tu sais que je suis développeur Python") et la capitalisation de connaissance.
Les Scopes de Mémoire
La mémoire n'est pas monolithique. Elle doit être segmentée selon sa portée et sa durée de vie.
| Scope | Durée de vie | Contenu typique | Cas d'usage |
|---|---|---|---|
| Session / Conversation | Quelques minutes/heures (la durée de l'interaction) | Historique des messages, entités mentionnées récemment. | Chatbot de support client, assistant de brainstorming. |
| Utilisateur | Permanente (jusqu'à suppression) | Préférences, rôle ("je suis un manager"), résumé des conversations passées, faits clés ("mon projet s'appelle 'Phoenix'"). | Tuteur personnalisé, coach de fitness, assistant personnel. |
| Projet / Partagé | Permanente | Glossaire du projet, décisions d'équipe, documentation partagée, état actuel d'un workflow. | Assistant de gestion de projet, base de connaissance d'équipe. |
Techniques de Mémoire à Court Terme (Session)
Ces techniques visent à gérer l'historique de la conversation en cours sans dépasser la fenêtre de contexte du LLM.
- Conversation Buffer: La plus simple. On garde tous les messages et on les renvoie à chaque fois. Simple mais explose rapidement la fenêtre de contexte.
- Sliding Window Buffer: On ne garde que les `k` derniers messages. Rapide et simple, mais perd le contexte du début de conversation (ex: l'objectif initial).
- Token Buffer: Similaire à la fenêtre glissante, mais on garde les `n` derniers tokens. Plus précis pour la gestion de la taille du contexte.
- Summary Buffer: Utilise un LLM pour résumer la conversation au fur et à mesure. Le résumé est injecté dans le prompt système. Préserve le contexte long, mais ajoute latence et coût à chaque tour.
- Combined Buffer (Summary + Window): Le meilleur des deux mondes. On garde un résumé de la conversation et les `k` derniers messages. Équilibre parfait entre préservation du contexte et gestion de la taille.
Techniques de Mémoire à Long Terme (Utilisateur & Projet)
Stocker et retrouver des informations pertinentes parmi un grand volume de données historiques. C'est là que les index vectoriels brillent.
- Récupération: La question de l'utilisateur est encodée en vecteur, et on effectue une recherche de similarité cosinus pour trouver les `k` souvenirs les plus proches.
- Exemple: `(Utilisateur: Alice) -[travaille_sur]-> (Projet: Phoenix) -[a_un_budget_de]-> (5000€)`
- Très puissant mais complexe à mettre en place.
- Ce résumé est stocké et injecté dans le `system` prompt de chaque nouvelle session pour donner immédiatement le contexte clé au LLM.
Architecture & Pipeline de Mémoire
La mémoire s'intègre comme une couche de récupération d'information en amont de l'appel au LLM.
Extraction & Mise à Jour des Souvenirs
La mémoire doit être un système vivant. L'information doit être ajoutée, mais aussi mise à jour ou supprimée.
Ex: `Conversation: "Ok super, je vais travailler sur le projet Alpha."`
→ `LLM Extractor` → `Fact: (user, works_on, project_alpha)`
Ex: `"/remember mon API key est XYZ"`
Ex: `"/forget ma dernière instruction"`
Ex: `"/show-memory"`
- Droit à l'oubli: Vous devez être capable de supprimer toutes les données associées à un utilisateur sur demande. Une bonne segmentation de la mémoire par `user_id` est cruciale.
Évaluation de la Mémoire
Une mauvaise mémoire est pire que pas de mémoire du tout. Il faut la mesurer.
| Métrique | Description | Comment mesurer ? |
|---|---|---|
| Retrieval Precision (Précision) | Parmi les souvenirs récupérés, combien sont réellement pertinents pour la question actuelle ? | Évaluation humaine ou LLM-as-a-Judge sur un jeu de test. Score de 1 à 5 pour chaque souvenir récupéré. |
| Retrieval Recall (Rappel) | Avons-nous récupéré tous les souvenirs pertinents ? | Difficile à automatiser. Se fait généralement via une analyse qualitative des échecs. |
| Task Success Rate (Taux de succès) | L'ajout de la mémoire a-t-il permis de mieux réussir des tâches complexes ? | Définir des scénarios multi-étapes (ex: "planifie un voyage en 3 étapes"). Le score est le % de scénarios réussis avec vs sans mémoire. |
Pièges & Erreurs à Éviter
C'est le risque le plus important. Si le système mémorise un fait incorrect ou une interprétation erronée, il le réutilisera, renforçant l'erreur. Un mécanisme de validation ou de confiance sur les souvenirs est nécessaire pour les systèmes critiques.
- Ignorer la vie privée : Stocker des informations personnelles identifiables (PII) sans cryptage, sans politique de rétention claire et sans le consentement de l'utilisateur est une recette pour le désastre.
- Mémoire trop bavarde : Récupérer trop de souvenirs (ex: top-k=20) peut noyer le LLM et consommer la fenêtre de contexte avec des informations peu pertinentes.
- Absence de mécanisme d'oubli : Ne pas permettre aux utilisateurs (ou aux administrateurs) de corriger ou de supprimer des souvenirs.
Snippet 1 : Mémoire de Session Simple (LangChain)
from langchain.memory import ConversationBufferWindowMemory
from langchain.llms import OpenAI
from langchain.chains import ConversationChain
# On configure une mémoire qui garde les 2 derniers échanges (k=2)
memory = ConversationBufferWindowMemory(k=2)
llm = OpenAI(temperature=0)
conversation = ConversationChain(
llm=llm,
verbose=True,
memory=memory
)
# Premier échange
conversation.predict(input="Bonjour, je m'appelle Jean.")
# Deuxième échange
conversation.predict(input="Je travaille sur le projet 'Apollo'.")
# Troisième échange
# La mémoire aura "oublié" le nom "Jean" mais se souviendra du projet.
conversation.predict(input="Quel est mon nom ?") # -> Il ne saura probablement pas.
conversation.predict(input="Sur quoi je travaille ?") # -> Il saura répondre "Apollo".
Snippet 2 : Mémoire à Long Terme Vectorielle (Concept)
import chromadb
from sentence_transformers import SentenceTransformer
class VectorMemory:
def __init__(self):
self.client = chromadb.Client()
self.collection = self.client.create_collection("user_memory")
self.encoder = SentenceTransformer('all-MiniLM-L6-v2')
def add_memory(self, user_id, text_memory, doc_id):
embedding = self.encoder.encode(text_memory).tolist()
self.collection.add(
ids=[doc_id],
embeddings=[embedding],
metadatas=[{"user_id": user_id}]
)
def retrieve_memories(self, user_id, query_text, n_results=3):
query_embedding = self.encoder.encode(query_text).tolist()
results = self.collection.query(
query_embeddings=[query_embedding],
n_results=n_results,
where={"user_id": user_id}
)
return results['documents']
# Utilisation:
# memory_store = VectorMemory()
# memory_store.add_memory("alice123", "Alice prefers concise answers.", "mem1")
# relevant_memories = memory_store.retrieve_memories("alice123", "Can you explain this topic?")
# -> ['Alice prefers concise answers.']
Playbook de Déploiement
- Étape 1 : Commencer avec une Mémoire de Session. Ne vous lancez pas tout de suite dans la mémoire long terme. Implémentez une mémoire de session robuste, de type "Résumé + Fenêtre glissante". C'est 80% du gain de performance pour 20% de l'effort.
- Étape 2 : Mettre en place la Mémoire Vectorielle Utilisateur. Choisissez une base de données vectorielle. Mettez en place un pipeline qui, à la fin de chaque session, génère un résumé de l'échange et le stocke sous forme de vecteur associé à l'`user_id`.
- Étape 3 : Intégrer la Récupération de Mémoire. Modifiez votre pipeline d'inférence pour qu'il récupère les `k` souvenirs les plus pertinents avant de construire le prompt final. Injectez-les dans une section dédiée, par exemple `
`. - Étape 4 : Développer un Extracteur de Faits. Créez un prompt et une fonction dédiés qui prennent une conversation et en extraient des faits atomiques. Exécutez cette fonction de manière asynchrone pour ne pas ralentir l'interaction.
- Étape 5 : Construire l'Interface de Gestion. La mémoire n'est pas "fire and forget". Vous avez besoin d'une interface (même simple en admin) pour voir, corriger et supprimer les souvenirs stockés pour un utilisateur. C'est crucial pour la maintenance et la conformité.
