Aller au contenu principal

Memory

Memory permet à votre agent de mémoriser les messages des utilisateurs, les réponses de l’agent et les résultats des outils au fil des interactions. Il dispose ainsi du contexte nécessaire pour rester cohérent, assurer la continuité de la conversation et produire de meilleures réponses au fil du temps.

Les agents Mastra peuvent être configurés pour stocker l’historique des messages. Vous pouvez également activer les fonctionnalités suivantes :

  • Observational Memory (recommandé) : utilise des agents en arrière-plan pour tenir un journal d’observations dense, qui remplace l’historique brut des messages à mesure qu’il s’allonge. La fenêtre de contexte reste ainsi réduite, sans perdre la mémoire à long terme.
  • Mémoire de travail : stocke de façon persistante des données utilisateur structurées, telles que les noms, les préférences et les objectifs.
  • Rappel sémantique : retrouve les anciens messages pertinents d’après leur sens plutôt que par correspondance exacte de mots-clés.
  • Threads multi-utilisateurs : permet à plusieurs utilisateurs de partager un même thread.

Si l’ensemble de la mémoire dépasse la limite de contexte du modèle, les processeurs de mémoire peuvent filtrer, réduire ou hiérarchiser le contenu afin de préserver les informations les plus pertinentes.

Les résultats de Memory sont stockés auprès d’un ou de plusieurs fournisseurs de stockage configurés.

📹 À regarder

Regardez la vidéo Concepts de Memory dans Mastra pour découvrir les différentes couches de mémoire que les agents peuvent utiliser.

Quand utiliser Memory
Lien direct vers Quand utiliser Memory

Utilisez Memory lorsque votre agent doit mener des conversations en plusieurs échanges qui font référence à des interactions précédentes, se souvenir des préférences de l’utilisateur ou de faits mentionnés plus tôt dans une session, ou encore enrichir progressivement le contexte d’un thread de conversation. Memory est inutile pour les requêtes en un seul échange, où chaque interaction est indépendante.

Démarrage rapide
Lien direct vers Démarrage rapide

  1. Installez le package @mastra/memory.

    npm install @mastra/memory@latest
  2. Memory nécessite un fournisseur de stockage pour conserver l’historique des messages, y compris les messages des utilisateurs et les réponses de l’agent.

    Pour ce démarrage rapide, utilisez @mastra/libsql.

    npm install @mastra/libsql@latest

    Pour en savoir plus sur les fournisseurs disponibles et le fonctionnement du stockage dans Mastra, consultez la documentation sur le stockage.

  3. Ajoutez le fournisseur de stockage à votre instance Mastra principale afin d’activer Memory pour tous les agents configurés.

    src/mastra/index.ts
    import { Mastra } from '@mastra/core'
    import { LibSQLStore } from '@mastra/libsql'

    export const mastra = new Mastra({
    storage: new LibSQLStore({
    id: 'mastra-storage',
    url: ':memory:',
    }),
    })
  4. Créez une instance de Memory et transmettez-la à l’option memory de l’agent.

    src/mastra/agents/memory-agent.ts
    import { Agent } from '@mastra/core/agent'
    import { Memory } from '@mastra/memory'

    export const memoryAgent = new Agent({
    id: 'memory-agent',
    name: 'Memory Agent',
    memory: new Memory({
    options: {
    lastMessages: 20,
    },
    }),
    })

    Consultez la classe Memory pour obtenir la liste complète des options de configuration.

  5. Appelez votre agent, par exemple dans Studio. Dans Studio, démarrez une nouvelle discussion avec votre agent, puis regardez la barre latérale droite. Elle affiche désormais diverses informations relatives à Memory.

Historique des messages
Lien direct vers Historique des messages

Transmettez un objet memory contenant resource et thread pour suivre l’historique des messages.

  • resource : identifiant stable de l’utilisateur ou de l’entité.
  • thread : ID qui isole une conversation ou une session donnée.
const response = await memoryAgent.generate('Remember my favorite color is blue.', {
memory: {
resource: 'user-123',
thread: 'conversation-123',
},
})

Pour retrouver les informations stockées en mémoire, appelez l’agent avec les mêmes valeurs resource et thread que celles utilisées dans la conversation d’origine.

const response = await memoryAgent.generate("What's my favorite color?", {
memory: {
resource: 'user-123',
thread: 'conversation-123',
},
})

// Response: "Your favorite color is blue."
attention

Chaque thread possède un propriétaire (resourceId) qui ne peut plus être modifié après sa création. Évitez de réutiliser le même ID de thread pour des threads appartenant à des propriétaires différents, car cela provoquera des erreurs lors des requêtes.

Pour répertorier tous les threads d’une ressource ou récupérer un thread précis, utilisez directement l’API Memory.

Observational Memory
Lien direct vers Observational Memory

Lors des conversations longues, l’historique brut des messages s’allonge jusqu’à remplir la fenêtre de contexte, ce qui dégrade les performances de l’agent. Observational Memory résout ce problème en exécutant des agents en arrière-plan qui condensent les anciens messages en observations denses. La fenêtre de contexte reste ainsi réduite, sans perdre la mémoire à long terme.

src/mastra/agents/memory-agent.ts
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'

export const memoryAgent = new Agent({
id: 'memory-agent',
name: 'Memory Agent',
memory: new Memory({
options: {
observationalMemory: true,
},
}),
})

Consultez Observational Memory pour en savoir plus sur le fonctionnement des observations et des réflexions, ainsi que la référence pour connaître toutes les options de configuration.

Ce que voit le modèle
Lien direct vers Ce que voit le modèle

Chaque fonctionnalité de mémoire est ajoutée soit aux messages système, soit aux messages de conversation dans la requête envoyée au modèle. Les couches présentes dépendent des fonctionnalités activées. La mémoire de travail et le rappel sémantique n’apparaissent que s’ils sont configurés. Il en va de même pour Observational Memory, tandis que l’historique des messages est activé par défaut. Le schéma montre où chaque couche activée est placée dans la requête. La liste ci-dessous décrit la contribution de chaque couche :

Diagram showing how Mastra assembles the model context: system messages containing agent instructions, call-time system messages, working memory, cross-thread semantic recall, and Observational Memory, followed by conversation messages where message history and same-thread semantic recall interleave by timestamp, then call-time context messages, and finally the new user message
  • La mémoire de travail est injectée sous la forme d’un message système contenant le gabarit et les données stockées. Avec useStateSignals, elle est plutôt transmise sous forme de signal d’état.
  • Les correspondances du rappel sémantique issues du thread actuel sont insérées comme des messages ordinaires et intercalées dans l’historique des messages selon leur horodatage. Les correspondances provenant d’autres threads sont plutôt regroupées dans un message système.
  • L’historique des messages ajoute les N derniers messages dans l’ordre chronologique. Votre nouveau message arrive toujours en dernier.
  • Observational Memory remplace l’ancien historique brut : les réflexions et les observations figurent dans un message système, tandis que seuls les messages qui n’ont pas encore été observés restent dans la conversation. Un court rappel de continuité est placé au début des messages de conversation.
  • Les messages de contexte correspondent au tableau facultatif context transmis lors d’un appel, par exemple agent.generate(msg, { context: [...] }). Utilisez-les pour fournir ponctuellement du contexte, comme l’état de l’application ou vos propres résultats RAG. Ils apparaissent comme des messages de conversation ordinaires uniquement pour cette requête et ne sont jamais enregistrés dans Memory.

Les messages de conversation sont classés par horodatage et dédupliqués selon leur ID. Les anciens messages retrouvés apparaissent donc avant l’historique récent. Les messages de contexte transmis au moment de l’appel reçoivent l’horodatage actuel, ce qui les place après l’historique et le rappel, mais avant votre nouveau message. Pour examiner le contexte exact d’une requête réelle, utilisez le traçage et ouvrez les spans d’appel au LLM ; consultez la section Observabilité ci-dessous.

Memory dans les systèmes multi-agents
Lien direct vers Memory dans les systèmes multi-agents

Lorsqu’un agent superviseur délègue une tâche à un sous-agent, Mastra isole automatiquement la mémoire de ce dernier. Aucun indicateur n’est nécessaire, car cette isolation s’applique à chaque délégation. Comprendre le fonctionnement de cette portée vous permet de choisir ce qui reste privé et ce que vous souhaitez partager délibérément.

Portée de la mémoire lors d’une délégation
Lien direct vers Portée de la mémoire lors d’une délégation

Chaque délégation crée un nouveau threadId et un resourceId déterministe pour le sous-agent :

  • ID du thread : unique pour chaque délégation. Le sous-agent commence avec un historique de messages vierge à chaque appel.
  • ID de la ressource : dérivé sous la forme {parentResourceId}-{agentName}. Comme l’ID de la ressource reste stable d’une délégation à l’autre, la mémoire dont la portée est la ressource persiste entre les appels. Un sous-agent se souvient des faits issus des délégations précédentes effectuées par le même utilisateur.
  • Instance de Memory : un sous-agent qui ne possède pas sa propre mémoire hérite de l’instance Memory du superviseur et de toutes ses options configurées. Si le sous-agent définit sa propre instance, celle-ci est prioritaire.
remarque

La génération de titres (generateTitle) concerne les threads de premier niveau et ne s’applique pas aux threads hérités des sous-agents. Comme chaque délégation crée un thread éphémère que personne ne voit, générer un titre pour celui-ci gaspillerait un appel au LLM par délégation. Pour générer les titres des propres threads d’un sous-agent, attribuez-lui sa propre configuration de mémoire.

Le superviseur transmet le contexte de sa conversation au sous-agent afin que celui-ci dispose de suffisamment d’informations pour accomplir la tâche. Seuls le prompt de délégation et la réponse du sous-agent sont enregistrés ; l’intégralité de la conversation parente ne l’est pas. Vous pouvez contrôler les messages transmis au sous-agent grâce à la fonction de rappel messageFilter.

remarque

Les ID de ressource des sous-agents se terminent toujours par le nom de l’agent ({parentResourceId}-{agentName}). Des sous-agents différents rattachés au même superviseur ne partagent jamais un ID de ressource par le biais d’une délégation.

Pour dépasser cette isolation par défaut, vous pouvez partager la mémoire entre plusieurs agents en leur transmettant les mêmes identifiants lorsque vous les appelez directement.

Partager la mémoire entre plusieurs agents
Lien direct vers Partager la mémoire entre plusieurs agents

Lorsque vous appelez directement des agents, en dehors du flux de délégation, le partage de la mémoire est contrôlé par deux identifiants : resourceId et threadId. Les agents qui utilisent les mêmes valeurs lisent et écrivent les mêmes données. Ce mécanisme est utile lorsque plusieurs agents collaborent dans un contexte commun, par exemple un chercheur qui enregistre des notes et un rédacteur qui les consulte.

Le partage à l’échelle de la ressource est le modèle le plus courant. La mémoire de travail et le rappel sémantique utilisent par défaut scope: 'resource'. Si deux agents partagent un resourceId, ils partagent les observations, la mémoire de travail et les embeddings, même dans des threads différents :

// Both agents share the same resource-scoped memory
await researcher.generate('Find information about quantum computing.', {
memory: { resource: 'project-42', thread: 'research-session' },
})

await writer.generate('Write a summary from the research notes.', {
memory: { resource: 'project-42', thread: 'writing-session' },
})

Comme les deux appels utilisent resource: 'project-42', le rédacteur peut accéder aux observations et à la mémoire de travail du chercheur. Les embeddings sémantiques sont également partagés par l’intermédiaire de la ressource. Chaque agent conserve néanmoins son propre thread, de sorte que les historiques de messages restent distincts.

Le partage à l’échelle du thread crée un couplage plus étroit. Observational Memory utilise par défaut scope: 'thread'. Si deux agents utilisent les mêmes resource et thread, ils partagent l’intégralité de l’historique des messages. Chaque agent voit tous les messages écrits par l’autre. Ce mécanisme est utile lorsque les agents doivent s’appuyer précisément sur les résultats produits par les autres.

Observabilité
Lien direct vers Observabilité

Activez le traçage pour surveiller et déboguer le fonctionnement de la mémoire. Les traces montrent exactement quels messages et quelles observations l’agent a inclus dans son contexte pour chaque requête. Elles vous aident ainsi à comprendre le comportement de l’agent et à vérifier que la récupération des éléments mémorisés fonctionne comme prévu.

Ouvrez Studio, puis sélectionnez l’onglet Observabilité dans la barre latérale. Ouvrez la trace d’une requête récente de l’agent et recherchez ses spans d’appel au LLM.

Changer de mémoire selon la requête
Lien direct vers Changer de mémoire selon la requête

Utilisez RequestContext pour accéder aux valeurs propres à une requête. Vous pouvez ainsi sélectionner de manière conditionnelle différentes configurations de mémoire ou de stockage selon le contexte de la requête.

src/mastra/agents/memory-agent.ts
export type UserTier = {
'user-tier': 'enterprise' | 'pro'
}

const premiumMemory = new Memory()
const standardMemory = new Memory()

export const memoryAgent = new Agent({
id: 'memory-agent',
name: 'Memory Agent',
memory: ({ requestContext }) => {
const userTier = requestContext.get('user-tier') as UserTier['user-tier']

return userTier === 'enterprise' ? premiumMemory : standardMemory
},
})

Consultez la page Contexte de requête pour en savoir plus.