Salut, agent en formation ! Emma ici, de retour d’une autre exploration nocturne du fascinant monde des agents IA. Vous savez, ce genre de nuit où vous commencez avec une simple question et soudain, il est 3 heures du matin, et vous avez un script Python à moitié préparé et une nouvelle obsession ?
C’est à peu près ma vie ces derniers temps, et tout cela grâce à quelque chose qui, en surface, semble un peu sec : la mémoire dans les agents IA.
Maintenant, avant que vos yeux ne se brouillent, laissez-moi vous dire pourquoi c’est absolument crucial, surtout pour nous, les débutants qui essayons de créer quelque chose d’utile. Nous avons tous joué avec des chatbots, n’est-ce pas ? Vous lui demandez quelque chose, il répond. Puis vous posez une question de suivi, et parfois il se souvient du contexte précédent, et parfois… c’est comme parler à un poisson rouge. Cette partie « se souvenir » ? C’est la mémoire, et c’est la différence entre une interaction frustrante et un agent qui semble réellement intelligent et utile.
Aujourd’hui, je veux parler de la façon dont nous, en tant que débutants, pouvons commencer à construire des agents qui se rappellent réellement des choses, en nous concentrant spécifiquement sur une approche super pratique : utiliser un simple fichier texte pour la mémoire « à court terme » et un stockage vectoriel de base pour la connaissance « à long terme ». Il ne s’agit pas de construire un super-agent multimodal et auto-améliorant (pas encore !), mais de mettre les pieds dans le plat avec les fondamentaux qui rendent ces systèmes complexes possibles. Pensez-y comme enseigner à votre agent à tenir un journal et une bibliothèque de référence.
Pourquoi la mémoire est importante (au-delà de « ne pas oublier »)
Soyons réalistes. Un agent IA qui oublie tout après chaque interaction n’est pas vraiment un agent. C’est plutôt comme une calculatrice très rapide. Mais quand un agent peut se souvenir des conversations passées, des faits qu’il a appris ou des actions qu’il a effectuées, il se transforme soudainement. Il peut :
- Maintenir le contexte : C’est énorme pour des conversations naturelles. « Que dire de ça ? » a du sens si l’agent se souvient de « ça ».
- Apprendre et s’adapter : Si un agent se souvient des préférences ou des échecs passés, il peut ajuster son comportement.
- Effectuer des tâches en plusieurs étapes : Pensez à réserver un voyage. L’agent doit se souvenir de votre destination, de vos dates et de vos préférences au fil de plusieurs échanges.
- Personnaliser les interactions : Se souvenir du nom d’un utilisateur ou de ses questions passées rend l’expérience beaucoup plus fluide.
Mon propre moment « ahah ! » à ce sujet est venu lorsque j’essayais de construire un simple agent pour m’aider à planifier mes repas hebdomadaires. Au départ, je lui faisais juste suggérer des recettes en fonction des ingrédients que je lui disais. Mais chaque fois que je voulais affiner une suggestion ou mentionner une restriction alimentaire, je devais me répéter. C’était frustrant ! On aurait dit avoir une conversation avec quelqu’un qui avait une amnésie immédiate après chaque phrase. C’est à ce moment-là que j’ai réalisé : cette chose a besoin d’un cerveau, même si c’est un tout petit.
La mémoire à court terme : l’approche du bloc-notes
Pour nous, débutants, le moyen le plus simple de donner à un agent une mémoire « à court terme » – celle qui se souvient du contexte immédiat de la conversation – est étonnamment simple : un fichier texte. Ou, si vous vous sentez audacieux, une liste en mémoire qui est écrite dans un fichier occasionnellement. C’est comme si votre agent tenait un bloc-notes courant de la conversation actuelle.
Comment je le fais : un fichier journal simple
Mon agent planificateur de repas devait se souvenir de ce dont nous venions de parler. Ai-je demandé des recettes de poulet ? Ai-je dit que je n’aimais pas le brocoli ? Pour cela, j’ai mis en place un système de journalisation très basique. Chaque entrée utilisateur et chaque sortie agent sont ajoutées à un fichier texte. Lorsque l’agent doit répondre, il peut lire les dernières lignes de ce fichier pour obtenir le contexte.
Voici un exemple Python super simplifié sur la façon dont vous pourriez gérer cela. Imaginez que la logique de base de votre agent appelle une fonction pour « stocker » et « récupérer » l’historique de la conversation.
# conversation_manager.py
CONVERSATION_LOG_FILE = "agent_conversation_log.txt"
MAX_SHORT_TERM_MEMORY_LINES = 10 # Se souvenir seulement des 10 derniers échanges
def add_to_short_term_memory(speaker, message):
"""Ajoute un message au journal de conversation."""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(CONVERSATION_LOG_FILE, "a") as f:
f.write(f"[{timestamp}] {speaker}: {message}\n")
def get_short_term_memory():
"""Lit les dernières lignes du journal de conversation."""
try:
with open(CONVERSATION_LOG_FILE, "r") as f:
lines = f.readlines()
# Ne retourner que les lignes les plus récentes
return "".join(lines[-MAX_SHORT_TERM_MEMORY_LINES:])
except FileNotFoundError:
return ""
# Exemple d'utilisation dans la boucle de votre agent :
# user_input = input("Vous : ")
# add_to_short_term_memory("Utilisateur", user_input)
# current_context = get_short_term_memory()
# agent_response = your_llm_call(prompt=f"{current_context}\nUtilisateur : {user_input}\nAgent :")
# add_to_short_term_memory("Agent", agent_response)
# print(f"Agent : {agent_response}")
Cette approche est d’une simplicité déconcertante, et c’est ça qui est beau pour les débutants. Vous êtes littéralement en train de renvoyer les derniers morceaux de votre conversation à votre modèle de langage (LLM) dans le cadre de l’invite. C’est comme rappeler à votre ami : « Hé, souvenez-vous que nous parlions de ce film hier ? Eh bien, je l’ai vu, et… » Le LLM utilise ensuite ce contexte pour générer une réponse plus pertinente.
Astuce d’Emma : N’essayez pas de renvoyer l’historique de toute la conversation au LLM s’il devient trop long ! Les LLM ont des « fenêtres de contexte », c’est la quantité maximale de texte qu’ils peuvent traiter à la fois. Pour les débutants, se limiter aux 5-10 derniers échanges est un bon point de départ pour garder les choses gérables et rentables.
La mémoire à long terme : les bases du stockage vectoriel
D’accord, donc notre agent peut se souvenir des dernières choses que nous avons dites. Génial ! Mais que se passe-t-il si j’ai dit à mon agent planificateur de repas la semaine dernière que je suis allergique aux cacahuètes ? Ou que je préfère des repas végétariens le lundi ? Ce genre d’informations doit persister au-delà d’une seule conversation et être accessible lorsqu’il est pertinent, pas seulement lorsqu’il a été mentionné récemment. C’est là que la mémoire « à long terme » entre en jeu, et pour nous, cela signifie un stockage vectoriel de base.
Qu’est-ce qu’un stockage vectoriel ? (Simplifié pour les débutants)
Imaginez que vous avez une immense bibliothèque de livres. Si vous voulez trouver des livres sur « les voyages dans l’espace », vous pourriez manuellement examiner chaque titre de livre, mais cela prendrait une éternité. Au lieu de cela, vous iriez probablement dans la section science-fiction, puis chercheriez des mots-clés. Un stockage vectoriel est comme un bibliothécaire super puissant et hyper rapide pour les informations qui ont été converties en nombres.
Voici l’idée simplifiée :
- Emballages : Vous prenez un morceau de texte (comme « Je suis allergique aux cacahuètes ») et le convertissez en une liste de nombres. Cette liste de nombres est appelée un « emballage ». De manière cruciale, les textes ayant des significations similaires auront des emballages qui sont « proches » les uns des autres dans cet espace numérique.
- Stockage : Vous stockez ces emballages (et le texte original) dans une base de données spéciale appelée un stockage vectoriel.
- Récupération : Lorsque votre agent reçoit une nouvelle requête (par exemple, « Suggérez une recette de dîner »), vous créez un emballage pour cette requête. Ensuite, vous demandez au stockage vectoriel de trouver les emballages stockés qui sont les « plus proches » (les plus similaires) de votre emballage de requête. Ces emballages les plus proches pointent vers les morceaux de texte originaux qui sont les plus pertinents pour votre requête.
Donc, si votre agent est interrogé sur une « recette de dîner », et qu’il a une entrée de mémoire à long terme à propos de « l’allergie aux cacahuètes », l’emballage pour « recette de dîner » pourrait être « suffisamment proche » de « l’allergie aux cacahuètes » pour récupérer cet élément d’information important, même si « l’allergie aux cacahuètes » n’a pas été explicitement mentionnée dans la conversation actuelle.
Mon premier expérience de stockage vectoriel : les préférences des utilisateurs
Pour mon planificateur de repas, je voulais qu’il se souvienne des restrictions alimentaires et des cuisines préférées. Donc, quand je lui ai dit, « Je ne mange pas de viande rouge », je voulais que ce fait soit stocké et récupéré chaque fois qu’il proposait une recette. Voici comment j’ai mis en place une version basique en utilisant une bibliothèque telle que `FAISS` (Facebook AI Similarity Search) ou `ChromaDB` (qui est souvent plus facile pour le développement local), combinée avec `sentence-transformers` pour les emballages.
Utilisons `ChromaDB` pour cet exemple, car il est assez accessible pour commencer à fonctionner localement. Vous l’installeriez généralement avec `pip install chromadb sentence-transformers`.
# long_term_memory.py
from sentence_transformers import SentenceTransformer
import chromadb
# Initialiser le modèle d'embedding
# Ce modèle convertit le texte en vecteurs numériques
embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
# Initialiser le client ChromaDB et la collection
# Cela crée une base de données sur votre machine locale
client = chromadb.PersistentClient(path="./chroma_db")
try:
long_term_collection = client.get_or_create_collection(name="agent_long_term_memory",
metadata={"hnsw:space": "cosine"})
except Exception as e:
print(f"Erreur lors de la création ou de la récupération de la collection : {e}")
# Gérer les erreurs potentielles, par exemple, si la base de données est corrompue ou verrouillée
# Pour un débutant, redémarrer le chemin de la base de données ou recréer peut être le plus simple
def add_to_long_term_memory(fact_id, fact_text):
"""Ajoute un fait à la mémoire à long terme."""
try:
embedding = embedding_model.encode(fact_text).tolist() # Convertir un tableau numpy en liste
long_term_collection.add(
documents=[fact_text],
embeddings=[embedding],
ids=[fact_id]
)
print(f"Ajouté '{fact_text}' à la mémoire à long terme avec l'ID : {fact_id}")
except Exception as e:
print(f"Erreur lors de l'ajout à la mémoire à long terme : {e}")
def retrieve_from_long_term_memory(query_text, n_results=3):
"""Récupère les faits pertinents de la mémoire à long terme en fonction d'une requête."""
try:
query_embedding = embedding_model.encode(query_text).tolist()
results = long_term_collection.query(
query_embeddings=[query_embedding],
n_results=n_results,
include=['documents', 'distances']
)
# Formater les résultats de manière agréable
retrieved_facts = []
if results and results['documents']:
for i, doc_list in enumerate(results['documents']):
for j, doc in enumerate(doc_list):
retrieved_facts.append({
"text": doc,
"distance": results['distances'][i][j]
})
return retrieved_facts
except Exception as e:
print(f"Erreur lors de la récupération de la mémoire à long terme : {e}")
return []
# Exemple d'utilisation :
# add_to_long_term_memory("user_allergy_001", "L'utilisateur est allergique aux arachides.")
# add_to_long_term_memory("user_pref_002", "L'utilisateur préfère les plats végétariens le lundi.")
# add_to_long_term_memory("user_diet_003", "L'utilisateur ne mange pas de viande rouge.")
# query = "Suggérez une recette de dîner saine pour ce soir."
# relevant_info = retrieve_from_long_term_memory(query, n_results=2)
# print(f"\nInformations pertinentes à long terme pour '{query}':")
# for item in relevant_info:
# print(f"- {item['text']} (Distance : {item['distance']:.2f})")
# query_2 = "Que devrais-je cuisiner lundi ?"
# relevant_info_2 = retrieve_from_long_term_memory(query_2, n_results=2)
# print(f"\nInformations pertinentes à long terme pour '{query_2}':")
# for item in relevant_info_2:
# print(f"- {item['text']} (Distance : {item['distance']:.2f})")
Lorsque l’agent reçoit une nouvelle requête (comme « Suggérez une recette de dîner »), il interroge d’abord sa mémoire à long terme (la collection ChromaDB) avec cette requête. Il récupère les faits les plus pertinents (comme « L’utilisateur est allergique aux arachides » ou « L’utilisateur préfère les plats végétariens le lundi ») et combine ensuite ces faits avec l’historique de conversation à court terme avant d’envoyer le tout au LLM. De cette façon, le LLM dispose d’un contexte beaucoup plus riche avec lequel travailler.
Conseil d’Emma : Les `ids` dans la fonction `add` sont importants. Ils vous permettent de mettre à jour ou de supprimer des faits spécifiques par la suite si nécessaire. Par exemple, si la préférence d’un utilisateur change, vous pouvez écraser l’ancien fait par un nouveau en utilisant le même ID.
Mettre le tout ensemble : une boucle d’agent simple
Alors, comment notre agent décide-t-il quand utiliser la mémoire à court terme ou à long terme ? C’est généralement une combinaison. Voici un flux conceptuel pour un agent simple :
- Entrée utilisateur : L’utilisateur tape un message.
- Stocker à court terme : Ajouter le message de l’utilisateur au journal de conversation à court terme.
- Récupérer à long terme : Utiliser le message de l’utilisateur (ou une version résumée de la conversation) comme requête pour le magasin de vecteurs. Récupérer les N faits les plus pertinents.
- Construire le prompt : Combiner l’historique récent de conversation à court terme ET les faits récupérés à long terme en un seul prompt complet pour le LLM.
- Le LLM génère une réponse : Le LLM traite ce prompt enrichi et génère une réponse.
- Stocker à court terme : Ajouter la réponse de l’agent au journal de conversation à court terme.
- (Optionnel) Mettre à jour à long terme : Si l’agent génère une nouvelle information qui doit être mémorisée à long terme (par exemple, « D’accord, j’ai noté que vous souhaitez des options sans gluten. »), elle peut être ajoutée au magasin de vecteurs.
- Sortie de la réponse : L’agent présente la réponse à l’utilisateur.
Ce cycle permet à votre agent d’être conscient des échanges immédiats tout en s’appuyant sur une base de connaissances plus large qu’il a accumulée.
Défis du monde réel et ce que j’ai appris
Ce n’est pas que du bonheur et des faits parfaitement récupérés, bien sûr. Voici quelques problèmes que j’ai rencontrés :
- L’ingénierie des prompts est essentielle : Il ne suffit pas de balancer tous les faits récupérés dans le prompt du LLM. Vous devez indiquer au LLM comment utiliser cette information. Quelque chose comme : « Voici un contexte pertinent sur les préférences de l’utilisateur : [faits récupérés]. En fonction de cela et de notre historique de conversation : [mémoire à court terme], veuillez répondre à la dernière requête de l’utilisateur… »
- Gérer les limites de la fenêtre de contexte : Si vous récupérez trop de faits à long terme ET avez un long historique à court terme, vous pouvez atteindre la limite de jetons du LLM. Vous devrez peut-être limiter la mémoire à court terme ou être sélectif quant au nombre de faits à long terme que vous incluez.
- Quand mettre à jour la mémoire à long terme : Décider quand une information provenant de la conversation doit être stockée de manière permanente est un choix de conception. Pour mon planificateur de repas, des déclarations explicites comme « J’aime la cuisine italienne » ou « Je suis allergique aux noix » sont des candidats clairs. Des indices plus subtils sont plus difficiles et peuvent nécessiter un autre appel au LLM pour les identifier.
- « Des informations erronées produisent des résultats erronés » : Si vos faits initiaux stockés dans le magasin de vecteurs ne sont pas bien formulés ou sont contradictoires, votre récupération souffrira. La clarté est importante.
Mais honnêtement, le plus grand obstacle pour moi a été de simplement commencer. L’idée des « magasins de vecteurs » semblait intimidante. Mais une fois que je l’ai décomposée en embeddings et en recherche de similarité simple, et que j’ai utilisé des bibliothèques conviviales pour les débutants, cela a cliqué. C’est comme apprendre à faire du vélo – un peu bancal au début, mais incroyablement libérateur une fois que vous avez compris.
Conclusions exploitables pour votre premier agent avec mémoire
- Commencez simplement avec la mémoire à court terme : Implémentez un fichier texte de base ou une liste en mémoire pour suivre les derniers tours de conversation. C’est le bloc-notes immédiat de votre agent.
- Expérimentez avec un magasin de vecteurs local pour le long terme : Installez `chromadb` et `sentence-transformers`. Essayez d’ajouter quelques « faits » sur vous-même ou un sujet spécifique, puis interrogez-les. Familiarisez-vous avec le fonctionnement de la récupération.
- Combinez-les dans la boucle de votre agent : Structurez votre agent pour d’abord obtenir des informations pertinentes à long terme, puis les combiner avec un contexte récent à court terme, et enfin tout envoyer à votre LLM choisi.
- Concentrez-vous sur des prompts clairs : Indiquez explicitement à votre LLM comment utiliser les informations récupérées. Ne vous contentez pas de déverser du texte.
- Testez, testez, testez : Essayez des cas limites. Que se passe-t-il si l’utilisateur contredit un vieux fait ? Que se passe-t-il s’il pose une question complètement hors sujet ? Observez comment votre système de mémoire gère cela.
Construire des agents qui se souviennent est une étape fondamentale vers la création d’outils IA véritablement utiles et intelligents. Cela les dépasse au-delà des simples bots de questions-réponses pour devenir des compagnons qui comprennent le contexte et accumulent des connaissances. Vous pouvez le faire ! Allez donner à votre agent une mémoire, et faites-moi savoir quelles choses brillantes il commence à retenir.
Bonne construction,
Emma
🕒 Published: