MemGPT — des LLM avec mémoire autoéditable pour un contexte infini
(github.com/cpacker)- Letta est un projet visant à construire une IA fondée sur une mémoire avancée, capable d’apprendre et de s’améliorer au fil du temps
- Les modes d’utilisation se divisent entre Letta Code, qui exécute des agents dans un terminal local, et la Letta API, qui intègre des agents dans des applications
- La CLI nécessite Node.js 18+ ; après installation avec
npm install -g @letta-ai/letta-code, exécutezlettapour lancer sur votre ordinateur local un agent doté d’une mémoire - Les agents Letta Code aident au codage et aux tâches réalisables sur un ordinateur, prennent en charge les skills et les subagents, et incluent des skills/subagents préconstruits pour la mémoire avancée et l’apprentissage continu
- Letta est indépendant du modèle ; le README recommande Opus 4.5 et GPT-5.2 pour obtenir les meilleures performances, et renvoie au model leaderboard comme référence de classement
- La Letta API sert à intégrer des agents avec état dans des applications, et fournit une API agents complète ainsi que des SDK Python et TypeScript
- Package TypeScript/Node.js :
@letta-ai/letta-client - Package Python :
letta-client - L’exemple montre le flux consistant à créer un agent et à envoyer des messages avec
LETTA_API_KEYet une clé d’API Letta
- Package TypeScript/Node.js :
- L’utilisation de Letta et des services Letta associés est soumise à l’acceptation de la politique de confidentialité et des conditions d’utilisation
1 commentaires
Avis de Hacker News
Nous sommes les auteurs de MemGPT. Si vous avez des questions sur l’implémentation, nous y répondrons.
Si vous voulez l’essayer directement, vous pouvez voir l’édition de mémoire en action via le bot Discord sur le serveur Discord de MemGPT (https://discord.gg/9GEQrxmVyE). En discutant avec le bot, on voit MemGPT modifier sa mémoire pour mettre à jour le profil de l’utilisateur et le sien.
Tout est open source, il est donc aussi possible de l’exécuter localement avec le code de https://github.com/cpacker/MemGPT. Le dépôt contient aussi un exemple centré sur la documentation, où l’on discute avec MemGPT à propos de la documentation de l’API LlamaIndex.
Je me demande pourquoi tout traiter dans une seule fenêtre de contexte. Quand j’ai expérimenté quelque chose de similaire il y a quelques mois, j’avais parallélisé avec plusieurs agents aux étapes de prétraitement et de post-traitement.
Par exemple, la fenêtre de contexte principale ne savait pas que de la mémoire était créée ou recherchée ; un post-processeur créait automatiquement des souvenirs à partir de la conversation et les stockait, et toute la conversation était aussi enregistrée dans une base de données vectorielle. Le préprocesseur injectait automatiquement les souvenirs et le contexte pertinents pour la conversation, et réécrivait même l’historique afin que, du point de vue de la fenêtre de contexte principale, ces souvenirs semblent avoir toujours été là.
Cela permettait d’économiser beaucoup de place dans la fenêtre de contexte principale, au lieu de la consommer avec des prompts système inutiles, etc.
Dans l’approche implicite, le « LLM principal », ou dans le chat le « fil de conversation », ne sait rien de la gestion de la mémoire en arrière-plan. Celle-ci peut être assurée par un « LLM mémoire », un script à base de règles, un petit réseau neuronal, etc.
L’approche explicite correspond à MemGPT : un seul LLM s’occupe de tout. Les travaux existants sur le chat multi-session/à longue portée suivent généralement une approche implicite avec un processus séparé de génération de mémoire, et les magasins de mémoire des chatbots grand public sont très probablement eux aussi majoritairement implicites.
La gestion explicite de la mémoire nécessite de suivre des instructions complexes, ce qui me semble difficile pour la plupart des LLM publics actuels. Nous examinons des moyens de résoudre cela, par exemple en affinant des modèles ouverts.
Le compromis est bien celui que vous décrivez. L’approche implicite évite d’avoir à mettre toutes les instructions de gestion de la mémoire dans le pré-prompt du LLM. Le message système complet de MemGPT fait environ 1 000 tokens. À l’inverse, quand le LLM se comporte correctement, la gestion explicite de la mémoire rend l’ensemble du système beaucoup plus simple, sans le surcoût lié à la gestion de plusieurs modèles LLM dans des threads parallèles.
Je pense que les LLM et le traitement du langage naturel peuvent devenir une interface plus viable vers les données structurées. Quand des données sont générées dans un contexte métier précis, on les extrait, on crée des embeddings et on construit une base de données vectorielle.
En post-traitement, après la réponse du modèle principal, le post-processeur génère automatiquement des souvenirs à partir de la conversation et les stocke. Cela permet de conserver le contexte important sans imposer cette charge au modèle principal. Une partie de la logique métier pertinente est aussi exécutée dans le cadre de la requête, puis réinjectée dans le système.
En prétraitement, avant d’envoyer une nouvelle entrée au modèle principal, on consulte la mémoire stockée, on injecte le contexte pertinent et on exécute aussi de la logique. En quelque sorte, le préprocesseur fournit au modèle principal une « révision » de la conversation précédente, pour le préparer à produire une réponse plus cohérente et plus riche en informations.
À propos de ce qui est écrit dans les limitations : même si les variantes de Llama 2 70B ont été affinées pour l’appel de fonctions, si elles produisent de mauvais appels de fonctions ou hallucinent des fonctions en dehors du schéma fourni, on peut utiliser de l’échantillonnage basé sur une grammaire.
Au minimum, cela permet de garantir que les appels de fonctions sont syntaxiquement corrects.
[0] https://github.com/ggerganov/llama.cpp/tree/master/grammars
Par exemple, même un grand modèle affiné sur des données d’appel de fonctions (https://huggingface.co/jondurbin/airoboros-l2-70b-2.1#agentf...) produisait généralement du JSON analysable, mais se trompait sur les arguments ou le nom de la fonction.
Par exemple, au moment d’écrire des données, au lieu de l’appel correct
working_context.appendindiqué dans le pré-prompt, il produisait un appelpersonal_diary.addqui n’avait jamais été spécifié.En voyant seulement le titre, j’ai cru qu’il s’agissait d’une technique d’édition de mémoire modifiant la mémoire neuronale du LLM, c’est-à-dire la mémoire au niveau des poids plutôt que le contexte, par exemple une approche comme ROME [1].
J’ai été soulagé de voir qu’il s’agissait en fait d’un beau travail de RAG, et je vais bientôt construire ma propre version de MemEditGPT.
[1] https://arxiv.org/abs/2202.05262
Comme vous l’avez bien compris, MemGPT ne modifie pas les poids du LLM comme ROME. La « mémoire » dont parle MemGPT n’est pas au niveau des poids, mais au niveau du texte/des tokens.
Le concept central consiste à donner au LLM la capacité de modifier un bloc-notes de mémoire de travail conservé dans le contexte, et de lire/écrire du contexte externe via des fonctions. Un détail important est que, pour gérer la limite finie du contexte, la lecture se fait toujours par pages, c’est-à-dire par chunks.
MemGPT peut enchaîner des fonctions et effectuer plusieurs itérations de lecture/écriture à partir d’une seule entrée utilisateur. C’est ce qui lui permet, comme dans l’exemple de documentation de l’API LlamaIndex du README, de rechercher dans une grande base documentaire, de rassembler des informations issues de plusieurs sources et de retourner une réponse.
Pendant un moment, j’ai soupçonné la version web de ChatGPT (chat.openai.com, pas l’API) de fonctionner comme ça dans les conversations. Même avec un très long historique de chat, j’avais l’impression que la qualité se dégradait progressivement plutôt que de tout oublier d’un coup.
Bien sûr, il y a peut-être plus d’indices dans le contexte que je ne le pensais.
Quoi qu’il en soit, je pense que ce genre d’idée a de fortes chances de devenir une fonction de base de tous les chatbots à l’avenir.
Il y a des pertes et on finit par perdre des informations importantes, mais la dégradation des performances peut être relativement douce. Dans MemGPT, un résumé récursif implicite est aussi utilisé en plus de toute la gestion explicite de la mémoire.
Si une tâche a été un tant soit peu intéressante, la sortie est fortement biaisée par le prompt. Comme on n’a qu’un seul échantillon, la sortie/l’historique précédent, on perd une partie de l’information au lieu d’une distribution de probabilités lisse, et comme plusieurs entrées peuvent être mappées vers la même sortie, on perd encore une partie de l’information.
Mais, dans la réalité, les prompts sont souvent la formulation la plus simple et la plus courte qu’on puisse imaginer pour obtenir le résultat voulu. Donc, si le LLM estime ce prompt, son interprétation du contexte manquant a de bonnes chances d’être à peu près correcte. Autrement dit, beaucoup d’informations qui semblent avoir disparu sont conservées dans la sortie du LLM, et même lorsque l’ancien contexte est repoussé hors de la fenêtre, la quantité d’information perdue d’un coup n’est pas si grande.
Il existe beaucoup de techniques triviales pour implémenter une mémoire avec perte. Par exemple, moyenner les tokens comme le font les sentence transformers. Je ne sais pas très bien pourquoi cette méthode est rarement utilisée pour compresser beaucoup de contexte dans un prompt. En pratique, cela joue le rôle de mémoire à moyen terme.
Je ne me souviens plus du nom, mais il existe déjà un langage de programmation ésotérique qui exécute les instructions de manière instable. En concevant soigneusement un programme, on peut faire en sorte qu’une séquence d’instructions s’exécute avec une fiabilité de 99 %, 99,9 %, etc.
Vingt ans plus tard, la même approche est devenue populaire dans l’infrastructure sous le nom de « chaos engineering », sans aucune ironie.
Mise à jour : je viens de publier un chatbot Discord persistant implémenté au-dessus de MemGPT. Vous pouvez l’essayer ici : https://discord.gg/9GEQrxmVyE
Avec le code GitHub, vous pouvez aussi exécuter localement une démo du chatbot ainsi qu’une démo de bot de questions-réponses documentaire permettant de poser des questions à MemGPT sur la documentation de l’API.
À mon avis, la plus grande limite des LLM est la fenêtre de contexte. Même leurs excellentes capacités de raisonnement se heurtent souvent à cette limite dans les cas d’usage réels.
Je suis d’accord avec l’explication selon laquelle le résumé récursif est une méthode simple pour gérer une fenêtre de contexte débordante, mais qu’il est fondamentalement avec perte et finit par créer de gros trous dans la mémoire du système.
Mais MemGPT fait la même chose et a le même problème. La seule différence est qu’au lieu de tout résumer récursivement, il recherche sélectivement dans l’historique et le génère à chaque requête. L’idée est chouette.
Mais je reste sceptique. Cette approche repose fondamentalement sur l’hypothèse que le contexte existant est un contexte résumable à faible entropie et que la requête ne dépend que d’une partie de l’historique.
Cela peut être vrai pour du chat ou pour « répondre à des questions à partir d’un énorme ensemble de documents ». Mais dans des cas comme la génération de code, où le contexte est dense en informations impossibles à jeter, comme des définitions d’API précises, et où il faut un contexte large, comme de nombreuses définitions d’API, les deux hypothèses sont fausses.
La structure et l’implémentation sont intéressantes, et les démos sont impressionnantes, mais je regrette que les articles sur le résumé ne reconnaissent pas les limites fondamentales de cette approche.
Comme indiqué, la file de conversation de MemGPT est gérée par résumé récursif, comme dans des travaux précédents ou dans beaucoup d’implémentations de chatbots. Mais il existe aussi une mémoire de LLM en zone « fixe », lisible et inscriptible, sans rapport avec le résumé récursif, que l’article appelle « contexte de travail ».
MemGPT peut donc accéder à la fois au résumé récursif généré automatiquement et au contexte de travail qu’il maintient activement à jour.
Ces deux éléments sont également distincts du contexte externe de MemGPT, amené dans la file de conversation par appels de fonction. Dans tous les exemples, les lectures du contexte externe ne sont pas compressées et se font par pages, sans résumé.
Quand le résumé de la file est déclenché, MemGPT reçoit une notification système ; s’il doit conserver certains détails de la file de conversation, il peut donc les écrire dans le contexte de travail avant qu’ils soient supprimés ou résumés.
Dans les exemples d’agents conversationnels, le contexte de travail sert à stocker les faits essentiels sur l’utilisateur et l’agent afin de maintenir une conversation cohérente. Comme le contexte de travail est toujours visible par le LLM, il n’a pas besoin d’être recherché séparément.
Dans les questions-réponses documentaires, le contexte de travail peut servir à suivre la tâche/question en cours et son avancement. Pour les requêtes complexes, il aide MemGPT à suivre des détails comme les recherches précédentes et les demandes de pages précédentes.