Créer des Agents IA qui ÉVOLUENT avec le Temps

L’un des plus grands avantages de la création d’agents IA par rapport aux flux de travail ou automatisations traditionnels est leur capacité à agir davantage comme un humain. Cette intelligence qui permet de prendre des décisions à la volée et d’agir en votre nom est la raison pour laquelle les agents IA sont souvent considérés comme le cas d’utilisation le plus important pour les LLM (grands modèles de langage). Mais pour des entités censées être si humaines, elles ont généralement une mémoire terriblement limitée.

J’ai une solution simple et efficace pour résoudre ce problème que je souhaite vous présenter aujourd’hui. Actuellement, tout le monde se concentre sur l’utilisation de documents pour enseigner aux agents IA via la RAG (Retrieval Augmented Generation). C’est certainement important, mais ce n’est pas vraiment de la mémoire. Et si nous donnions à nos agents IA la capacité d’apprendre non seulement grâce aux documents que nous leur fournissons, mais aussi à travers nos conversations ?

Nous voulons des agents IA qui apprennent au fur et à mesure de nos interactions, capables de se souvenir de nos objectifs, préférences, instructions ou corrections. C’est ce type de mémoire à long terme qui permet véritablement d’élever vos agents IA au niveau supérieur de personnalisation et de comportement humain.

Dans cet article, je vais vous montrer étape par étape comment construire un de ces agents auto-apprenants en utilisant une bibliothèque Python open-source appelée Mem Zero. Cette bibliothèque est simple à utiliser et conçue exactement pour ce que nous essayons de faire : développer des connaissances (ou mémoires) sur des utilisateurs individuels au fur et à mesure de leurs interactions avec l’agent.

Le problème des agents IA sans mémoire à long terme

Commençons par comprendre le problème. Voici à quoi ressemble une conversation avec un LLM qui n’a pas de mémoire à long terme implémentée.

Pour ce test, j’utilise Gemini 2.0 Flash. C’est un agent (ou plutôt un chatbot) qui n’a pas de mémoire à long terme. Dans ma première requête, je lui décris une pile technologique que j’utilise pour construire ma société SaaS. Théoriquement, le chatbot comprend les différents services que j’utilise comme Redis et Supabase.

Mais regardez ce qui se passe : je vais commencer une nouvelle conversation et poser une question concernant ces services que je viens de décrire. Je demande : « Quelles considérations devrais-je avoir pour ma base de données ? »

Si c’était vraiment un agent intelligent, il se souviendrait de ma pile technologique entre les conversations. Mais comme vous pouvez le constater, rien dans sa réponse ne montre qu’il comprend réellement ce que j’utilise. Il mentionne certaines choses comme Redis que j’utilise, mais il liste également de nombreux services différents comme MongoDB, Oracle – des technologies que je n’ai pas du tout mentionnées dans ma pile technologique.

On voit clairement que Gemini n’a pas cette mémoire à long terme. Lorsque je commence une nouvelle conversation, je dois lui rappeler tous les détails importants des conversations précédentes pour le mettre à jour. C’est extrêmement pénible.

La solution : un agent avec mémoire à long terme

Contrastons maintenant avec un agent doté d’une mémoire à long terme construit avec Mem Zero. Le résultat final, que nous allons construire dans cet article, est disponible gratuitement sur studio.automator.ai – c’est l’agent IA Pyantic AI mem.

Je vais soumettre la même requête, indiquant que je travaille sur une entreprise SaaS et détaillant ma pile technologique. Comme avant, l’agent reconnaît mes technologies. Mais maintenant, lorsque je commence une nouvelle conversation et pose la même question à l’agent (« Quelles considérations devrais-je avoir pour ma base de données ? »), la réponse est beaucoup plus pertinente.

En effet, l’agent se souvient que je construis une entreprise SaaS. Il parle de Supabase, PostgreSQL, et si je cherche Redis, il en parle également en mentionnant mon Fast API. Contrairement à Gemini, il ne fait pas référence à des technologies que je n’utilise pas – il ne mentionne que celles que j’utilise réellement.

C’est un exemple très basique, mais j’espère que vous pouvez imaginer tout ce que vos agents IA pourront faire lorsqu’ils seront capables de se souvenir des interactions passées avec les utilisateurs et commenceront à construire une base de connaissances spécifique à chaque utilisateur.

Commencer avec Mem Zero

Commencer avec Mem Zero ne pourrait pas être plus facile. Ils ont un dépôt GitHub (que je vais lier dans les ressources) et vous n’avez qu’à exécuter pip install memzero-ai une fois que vous avez Python sur votre machine. C’est aussi simple que cela.

Ils proposent également une plateforme pour héberger Mem Zero pour vous, mais si vous préférez, vous pouvez l’auto-héberger gratuitement. C’est un projet 100% open-source, et c’est ce que nous allons utiliser dans cet article.

Je vais commencer par une implémentation très basique de Mem Zero, basée sur leur modèle, puis je vais progressivement la complexifier pour ajouter des éléments importants comme l’authentification Supabase pour l’identification des utilisateurs et pour notre stockage vectoriel des mémoires.

Implémentation de base avec Mem Zero (Version 1)

Commençons par coder une implémentation simple de Mem Zero. Nous allons importer nos bibliothèques et variables d’environnement, notamment notre clé API OpenAI pour cette première version.

import os
import openai
from memzero import MemClient, MemConfig

# Configuration de base avec la clé API OpenAI
openai.api_key = os.environ.get("OPENAI_API_KEY")

Ensuite, configurons Mem Zero. Il y a beaucoup de paramètres possibles, mais nous gardons cela simple pour l’instant :

# Configuration pour Mem Zero
config = MemConfig(
    llm={
        "provider": "openai",
        "model": "gpt-4o-mini",
    }
)

# Création des clients OpenAI et Mem Zero
client = openai.OpenAI()
mem_client = MemClient(config)

Maintenant, créons notre fonction principale pour discuter avec l’agent en utilisant les mémoires :

def chat_with_memories(user_message, user_id="default_user"):
    # Récupération des mémoires pertinentes
    memories = mem_client.search(
        query=user_message,
        user_id=user_id,
        limit=3
    )
    memories_str = str(memories)

    # Création du prompt système avec les mémoires
    system_prompt = f"""Vous êtes une IA utile. Répondez aux questions en fonction du dernier message de l'utilisateur et des mémoires suivantes : {memories_str}"""

    # Préparation des messages pour l'API OpenAI
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_message}
    ]

    # Obtention de la réponse de l'agent
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages
    )
    ai_response = response.choices[0].message.content

    # Ajout de la mémoire basée sur cette interaction
    mem_client.add(
        messages=[
            {"role": "user", "content": user_message},
            {"role": "assistant", "content": ai_response}
        ],
        user_id=user_id
    )

    return ai_response

def main():
    while True:
        user_input = input("\nVous: ")
        if user_input.lower() == "exit":
            break
        response = chat_with_memories(user_input)
        print(f"\nIA: {response}")

if __name__ == "__main__":
    main()

Cette fonction est très simple. Elle prend le message actuel de l’utilisateur et un ID utilisateur (pour séparer les mémoires entre utilisateurs). Elle récupère d’abord les mémoires pertinentes avec la fonction search de Mem Zero, puis crée un prompt système incluant ces mémoires. Ensuite, elle envoie une requête à OpenAI, obtient la réponse, et utilise la fonction add de Mem Zero pour extraire et stocker les mémoires clés de cette interaction.

Un point important à noter : nous ne construisons pas d’historique de conversation au fil du temps. Nous n’envoyons que le prompt système et le message utilisateur le plus récent à GPT-4o Mini. C’est crucial car nous allons prouver que même sans historique de conversation, l’agent est capable de se souvenir des choses.

Test de l’implémentation de base

Testons notre implémentation en exécutant le script :

python iterations/version1_basic_mem.py

Dans cette interface de chat avec GPT-4o Mini, je peux dire quelque chose de simple comme « Bonjour ». À ce stade, rien ne sera stocké dans nos mémoires car il n’y a rien qui vaille la peine d’être sauvegardé.

Pour prouver que nous n’avons pas d’historique de conversation, je vais demander « Qu’est-ce que je viens de dire ? ». Si nous stockions plus que le dernier message utilisateur, l’agent pourrait nous dire que nous avons dit « Bonjour ». Mais comme vous pouvez le voir, il n’est pas capable de se rappeler des conversations ou déclarations précédentes.

Maintenant, je vais lui donner quelque chose à mémoriser : « J’aime tous les types de fromages sauf le fromage de chèvre ». L’agent me répond, et en arrière-plan, il appelle la fonction add de Mem Zero pour ajouter cette mémoire.

Même sans historique de conversation, je peux maintenant lui demander « Quelles sont mes préférences alimentaires ? » et obtenir une réponse pertinente. Il sait, grâce à la mémoire à long terme (et non à l’historique de conversation), quelles sont mes préférences en matière de fromage.

Intégration avec Supabase (Version 2)

L’ajout de Supabase est étonnamment simple. Voici les modifications nécessaires :

# Configuration pour Mem Zero avec Supabase
config = MemConfig(
    llm={
        "provider": "openai",
        "model": os.environ.get("OPENAI_MODEL", "gpt-4o-mini"),
    },
    vector_store={
        "provider": "supabase",
        "connection_string": os.environ.get("SUPABASE_CONNECTION_STRING"),
    }
)

Nous changeons simplement la configuration de notre client Mem Zero pour spécifier que nous voulons utiliser Supabase comme stockage vectoriel au lieu de la méthode en mémoire par défaut. Pour la chaîne de connexion, nous utilisons une variable d’environnement.

Pour configurer cette chaîne de connexion, allez dans votre instance Supabase, cliquez sur « Connect » en haut au milieu, descendez jusqu’à « Transaction Pooler » et consultez les paramètres. Vous pouvez copier cette chaîne de connexion directement. La seule chose à remplir est votre mot de passe de base de données.

J’ai également rendu le modèle dynamique en fonction d’une variable d’environnement. Le reste du code est exactement le même que la version 1.

Test de l’intégration Supabase

Exécutons la version 2 et observons nos mémoires être stockées dans Supabase :

python iterations/version2_supabase_mem.py

Dans mon instance Supabase, la table des mémoires (dans le schéma « vecs », différent du schéma « public » auquel vous êtes probablement habitué) est complètement vide. Mem Zero créera cette table pour vous, vous n’avez donc pas besoin d’exécuter SQL vous-même.

Revenons au terminal pour discuter avec l’agent et observer l’apparition de nos mémoires dans Supabase. Je vais dire quelque chose d’aléatoire : « Je me tirerai dans le pied avant de coder à nouveau avec PHP ».

L’agent crée le vecteur pour notre mémoire (c’est pourquoi nous avons cette énorme liste de nombres), puis me donne une réponse. Si je rafraîchis la table dans Supabase, nous voyons maintenant notre première mémoire. Dans les métadonnées, nous pouvons voir quel texte a été vectorisé : « L’utilisateur est frustré par PHP et ne veut plus coder avec ». Nous avons également l’ID utilisateur (actuellement « default_user ») et l’horodatage de création.

Pour prouver que cela fonctionne vraiment comme mémoire à long terme, je vais quitter mon script et le redémarrer complètement. Même s’il y avait un historique de conversation, nous avons maintenant une nouvelle instance du script. Si je demande « Quelles sont mes préférences de codage ? », l’agent recherche dans les mémoires, trouve celle que nous avons, et me répond correctement : « Selon vos mémoires, vous semblez préférer éviter PHP pour le codage ».

Authentification Supabase et interface utilisateur (Version 3)

Pour la version 3, j’ai créé une interface utilisateur Streamlit très simple pour démontrer l’authentification Supabase. La plupart du code est du boilerplate que Claude 3.7 m’a aidé à créer.

Nous avons besoin de l’URL et de la clé Supabase pour l’authentification, que nous définissons dans notre fichier .env. Nous obtenons notre configuration pour Mem et créons notre client Mem de la même manière.

Pour toutes les inscriptions et connexions via Supabase, nous stockons l’utilisateur dans l’état de session de l’interface utilisateur. Ainsi, nous pouvons extraire l’ID utilisateur lorsque nous appelons notre client Mem Zero, au lieu d’utiliser cette valeur par défaut que nous utilisions auparavant.

Notre fonction chat_with_memories est essentiellement la même, à quelques différences près pour bien fonctionner avec l’interface. L’important est que l’ID utilisateur est maintenant dynamique au lieu d’être codé en dur.

Voici comment cela fonctionne : une fois que l’utilisateur est connecté, cette valeur existe, et nous avons l’ID utilisateur à l’intérieur. Nous extrayons l’ID utilisateur et le passons à chat_with_memories au lieu d’utiliser cette valeur par défaut.

Test de l’authentification Supabase

Exécutons la version 3 avec la commande streamlit run iterations/version3_supabase_auth.py. Cela ouvre automatiquement une page dans notre navigateur où nous pouvons nous connecter sur le côté gauche.

Je vais me connecter avec un de mes comptes de test. Une fois connecté, l’interface affiche mon ID utilisateur actuel. Nous pouvons également effacer nos mémoires si nécessaire.

Donnons à l’agent une opinion : « Je pense que nous avons déjà atteint l’AGI (Intelligence Artificielle Générale) et que les gens sont simplement discrets à ce sujet ». C’est une opinion que l’agent devrait stocker comme mémoire pour moi.

Si je retourne à Supabase et que je rafraîchis, nous avons ce nouvel enregistrement : « L’utilisateur croit que nous avons déjà atteint l’AGI et que les gens sont discrets à ce sujet ». Et l’ID utilisateur, au lieu d’être cette valeur par défaut, est maintenant un véritable ID utilisateur de Supabase.

Maintenant, je vais me déconnecter et me connecter à un autre compte pour voir que nos mémoires seront stockées séparément. Je vais donner une opinion complètement opposée : « Je ne pense pas du tout que nous ayons atteint l’AGI ».

En retournant à Supabase et en rafraîchissant, nous avons un troisième enregistrement : « L’utilisateur ne pense pas que nous ayons atteint l’AGI du tout ». Et cet ID utilisateur est différent, correspondant à celui avec lequel nous sommes actuellement connectés.

Si je demande maintenant « Pensez-vous que nous avons atteint l’AGI ? », l’agent me répond : « Selon votre mémoire, vous croyez que nous n’avons pas atteint l’AGI ».

Mais si je me déconnecte et me reconnecte à mon premier compte, puis pose exactement la même question, l’agent me répond : « Selon ce que vous avez partagé, vous croyez que nous avons déjà atteint l’AGI et que les discussions sont cachées au public ».

C’est pourquoi je fais exprès de créer des mémoires complètement opposées : pour montrer que, comme nous séparons par ID utilisateur, il n’y a absolument aucune chance que l’agent fasse accidentellement référence à une mémoire d’un utilisateur différent. Nous sommes garantis d’obtenir la bonne réponse, même avec des informations complètement différentes.

Comment fonctionne Mem Zero en coulisses

Mem Zero fait beaucoup de choses pour vous en coulisses. Même avec une implémentation de base, c’est une version assez puissante de la mémoire à long terme.

Les deux fonctionnalités principales de Mem Zero, que vous pouvez intégrer à n’importe quel framework d’agent, sont l’ajout de mémoires et leur recherche.

Pour l’ajout de mémoires, vous avez vos messages qui arrivent via une conversation, puis un grand modèle de langage spécifiquement invité à extraire les mémoires clés de la conversation. C’est différent de votre agent principal – c’est la partie mémoire de votre système. Ces nouvelles mémoires sont ajoutées à une base de données vectorielle. Vous avez essentiellement cette configuration RAG, cette base de connaissances pour chaque utilisateur individuel conversant avec votre agent.

Vous pouvez aller encore plus loin avec Mem en implémentant une connaissance graphique – c’est un cas d’utilisation plus avancé que je n’aborderai pas dans cet article. Mais vous pouvez également stocker des entités et des relations pour le rendre encore plus puissant. Avec RAG et la base de données vectorielle, c’est généralement suffisant.

L’important ici est que c’est beaucoup plus que juste RAG, car vous séparez les données par utilisateurs, et Mem fait également des choses importantes sous le capot, comme la résolution de conflits. Lorsque de nouvelles mémoires arrivent, il s’assure que vous ne dupliquez pas ces mémoires lorsqu’il pourrait déjà y avoir quelque chose de similaire.

Pour la recherche de mémoires, tout ce que nous regardons ici est exécuté avant notre agent IA principal, car il est responsable de récupérer les mémoires les plus pertinentes pour fournir à notre agent cette capacité de mémoire à long terme. Nous avons un LLM qui réécrit intelligemment la requête pour extraire les informations les plus pertinentes de notre base de données vectorielle. Quelles que soient ces mémoires pertinentes, lorsqu’il les extrait de la base de données vectorielle, elles sont transmises à notre agent IA.

Comme pour l’ajout de mémoires, Mem Zero fait beaucoup plus en coulisses que vous ne pourriez le penser, car ils implémentent des techniques RAG avancées comme le reclassement des scores pertinents, incluant toutes les métadonnées et horodatages, s’assurant vraiment que cette mémoire à long terme est super robuste.

Conclusion

Il existe des plateformes comme ChatGPT qui intègrent quelque chose de similaire à Mem. Il y a des plateformes qui font les choses mieux que Gemini, mais le niveau de personnalisation et de contrôle que vous avez avec Mem Zero est incomparable. Vous pouvez parcourir leurs SDK Python ou Node – vous avez tellement de marge de manœuvre pour vraiment faire correspondre la mémoire à long terme au mieux à votre cas d’utilisation, avec la façon dont vous ajoutez et recherchez des mémoires. C’est tout simplement très puissant.

J’espère que ce guide était clair et concis sur la façon d’implémenter la mémoire à long terme pour vos agents IA. Le meilleur aspect de tout cela est que Mem Zero est vraiment facile à intégrer, quel que soit votre cas d’utilisation ou le framework que vous utilisez.

Je prévois certainement de créer plus de contenu sur Mem à l’avenir – des cas d’utilisation avancés, l’intégration avec différentes plateformes et la configuration de la mémoire graphique également. Si vous avez apprécié ce contenu et que vous attendez avec impatience plus de choses sur les agents IA, n’hésitez pas à explorer davantage ce sujet passionnant.