跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

Memory

Memory 让 Agent 能访问先前的消息和工具结果。Agent 可以利用这些上下文回答后续问题,并回忆之前交互中的信息。

Mastra agents 可以配置存储消息历史。此外,你还可以启用:

  • 观察式记忆(Observational Memory)(推荐):使用后台 agents 维护一份密集的观察日志;随着日志增长,它会取代原始消息历史。这样既能保持上下文窗口精简,又能保留长期记忆。
  • 工作记忆:存储持久化的结构化用户数据,例如姓名、偏好和目标。
  • 语义召回:基于语义而非精确关键词检索相关的历史消息。
  • 多用户线程:在多个用户之间共享同一个线程。

如果组合后的记忆超出模型的上下文限制,记忆处理器可以过滤、裁剪或调整内容优先级,从而保留最相关的信息。

记忆结果会存储在你配置的一个或多个存储提供商中。

📹 观看

观看 Mastra memory 概念,从概念层面了解 Agent 可使用的各层记忆。

何时使用 memory
何时使用 memory的直接链接

当 Agent 需要维护多轮对话(引用先前的交流)、回忆会话早期用户的偏好或事实,或在对话线程中逐步积累上下文时,使用 memory。对于每次交互都相互独立的单轮请求,则无需使用 memory。

快速开始
快速开始的直接链接

  1. 安装 @mastra/memory 包。

    npm install @mastra/memory@latest
  2. Memory 需要存储提供商来持久化消息历史,包括用户消息和 Agent 响应。

    本快速开始使用 @mastra/libsql。

    npm install @mastra/libsql@latest

    关于可用提供商以及 Mastra 中存储工作原理的更多细节,请访问存储文档。

  3. 将存储提供商添加到主 Mastra 实例,从而为所有已配置的 agents 启用记忆。

    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. 创建 Memory 实例,并将其传给 Agent 的 memory 选项。

    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,
    },
    }),
    })

    完整配置选项参见 Memory 类。

  5. 调用你的 Agent,例如在 Studio 中。在 Studio 内与该 Agent 开始新对话,查看右侧边栏。现在它会显示记忆详情。

消息历史
消息历史的直接链接

传入包含 resource 和 thread 的 memory 对象以跟踪消息历史。

  • resource:用户或实体的稳定标识符。
  • thread:隔离特定对话或会话的 ID。
const response = await memoryAgent.generate('Remember my favorite color is blue.', {
memory: {
resource: 'user-123',
thread: 'conversation-123',
},
})

要回忆存储在 memory 中的信息,请使用与原始对话相同的 resource 和 thread 值调用 Agent。

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

// Response: "Your favorite color is blue."
注意

每个线程都有一个所有者(resourceId),创建后无法更改。避免为不同所有者的线程复用同一个线程 ID,否则查询时会报错。

要列出某个资源的所有线程,或检索特定线程,可直接使用 memory API。

使用作用域标识记忆
使用作用域标识记忆的直接链接

除了 memory 对象,你还可以传入 scopes:即一次运行所代表的地址,格式为 <type>:<value>。Memory 从 resource: 作用域读取资源,从 thread: 作用域读取线程。其他作用域(例如 org:acme)会传递给工具和处理器。

const response = await memoryAgent.generate('Remember my favorite color is blue.', {
scopes: ['org:acme', 'resource:user-123', 'thread:conversation-123'],
})

作用域也可以来自 Agent 和请求上下文。Mastra 会合并这三个来源:

src/mastra/agents/memory-agent.ts
export const memoryAgent = new Agent({
id: 'memory-agent',
name: 'Memory Agent',
scopes: ({ requestContext }) => {
// Set by your auth middleware. Request bodies can fill unreserved keys.
const orgId = requestContext.get('org-id')
return orgId ? [`org:${orgId}`] : []
},
memory: new Memory(),
})

解析器的输入必须来自服务端,而不是客户端:请求体可以设置任何未保留的请求上下文键。受信任的服务端中间件也可以通过 MASTRA_SCOPES_KEY 请求上下文键直接设置作用域。详情参见请求上下文。客户端无法在请求体中发送作用域。

你可以将作用域与 memory.resource、memory.thread 或资源/线程请求上下文键混用,只要它们一致即可。如果 resource: 或 thread: 作用域与其他来源指定的值不同,调用会抛出错误。

工具、处理器和子 Agents 会收到本次运行的其他作用域,但不会收到 resource: 和 thread: 作用域。每个嵌套的 Agent 调用都会选择自己的资源和线程。

观察式记忆(Observational Memory)
观察式记忆(Observational Memory)的直接链接

长对话可能让原始消息历史填满上下文窗口,并降低 Agent 表现。观察式记忆使用后台 agents 将较早的消息压缩为观察记录。这会减少消息历史占用的上下文,同时为后续轮次保留信息。

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,
},
}),
})

关于观察记录和反思如何工作的细节,参见观察式记忆;所有配置选项参见参考文档。

模型看到的内容
模型看到的内容的直接链接

Memory 会向发送给模型的消息添加系统消息或对话消息上下文。消息历史默认启用,其他记忆功能仅在配置后才会提供上下文。下图展示了各功能分别在哪里添加上下文,下面的列表解释了它们贡献的内容:

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
  • 工作记忆会作为系统消息注入,包含模板和已存储的数据。使用 useStateSignals 时,则改为以状态信号的形式传递。
  • 语义召回中来自当前线程的匹配项会作为普通消息插入,并按时间戳与消息历史交错排列。来自其他线程的匹配项则会格式化为系统消息。
  • 消息历史按时间顺序添加最近 N 条消息。你的新消息始终位于最后。
  • 观察式记忆会替换旧的原始历史:反思和观察记录存放在系统消息中,只有尚未被观察的消息会保留在对话中。对话消息开头会放置一条简短的延续提醒。
  • 上下文消息是调用时传入的可选 context 数组,例如 agent.generate(msg, { context: [...] })。它们用于一次性的背景信息,例如应用状态或你自己的 RAG 结果。它们仅在该请求中作为普通对话消息出现,且永远不会保存到 memory。

对话消息按时间戳排序,并按消息 ID 去重,因此召回的历史消息会出现在最近历史之前。调用时传入的上下文消息会标记为当前时间,因此位于历史和召回之后、你的新消息之前。要检查真实请求的确切上下文,请使用链路追踪并打开 LLM 调用 spans,参见下文可观测性。

多 Agent 系统中的记忆
多 Agent 系统中的记忆的直接链接

当监督者 Agent委派给子 Agent 时,Mastra 会自动隔离子 Agent 的记忆。这一行为在每次委派时都会发生,无需开关。理解这种作用域机制,可以让你决定哪些内容保持私有、哪些有意共享。

委派如何划定记忆作用域
委派如何划定记忆作用域的直接链接

每次委派都会为子 Agent 创建一个新的 threadId 和一个确定性的 resourceId:

  • Thread ID:每次委派都唯一。子 Agent 每次被调用时都从干净的消息历史开始。
  • Resource ID:由 {parentResourceId}-{agentName} 推导而来。由于该 resource ID 在多次委派之间保持稳定,资源级记忆会在调用之间延续。子 Agent 能记住同一用户先前委派中的事实。
  • Memory 实例:没有自己 memory 的子 Agent 会继承监督者的 Memory 实例及所有已配置选项。如果子 Agent 定义了自己的 memory,则以它为准。
备注

标题生成(generateTitle)属于顶层线程的职责,不会应用于继承的子 Agent 线程。由于每次委派创建的都是无人查看的临时线程,为其运行标题生成会浪费每次委派的一次 LLM 调用。要为子 Agent 自己的线程生成标题,请为该子 Agent 配置独立的 memory。

监督者会把自身的对话上下文转发给子 Agent,使其拥有足够的背景来完成任务。只有委派提示词和子 Agent 的响应会被保存,完整的父对话不会被存储。你可以通过 messageFilter 回调控制哪些消息会到达子 Agent。

备注

子 Agent 的 resource ID 始终带有 Agent 名称后缀({parentResourceId}-{agentName})。同一监督者下的不同子 Agents 通过委派永远不会共享 resource ID。

若要突破这种默认隔离,可以在直接调用 agents 时传入匹配的标识符,从而在 agents 之间共享记忆。

在 agents 之间共享记忆
在 agents 之间共享记忆的直接链接

当你直接调用 agents(不经过委派流程)时,记忆共享由两个标识符控制:resourceId 和 threadId。使用相同值的 agents 会读写同一份数据。当多个 agents 协作处理共享上下文时(例如研究者保存笔记、写作者读取笔记),这很有用。

资源级共享是最常见的模式。工作记忆和语义召回默认使用 scope: 'resource'。如果两个 agents 共享同一个 resourceId,即使处于不同线程,它们也会共享工作记忆和 embeddings:

// 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' },
})

由于两次调用都使用 resource: 'project-42',写作者可以访问研究者的工作记忆。语义 embeddings 也会通过该资源共享。每个 Agent 仍拥有自己的线程,因此消息历史相互独立。

线程级共享提供更紧密的耦合。观察式记忆默认使用 scope: 'thread'。如果两个 agents 使用相同的 resource 和 thread,它们会共享完整的消息历史。每个 Agent 都能看到另一个 Agent 写下的每条消息。当 agents 需要基于彼此的确切输出继续工作时,这很有用。

可观测性
可观测性的直接链接

启用链路追踪,以监控和调试 memory 的实际运行。Traces 会准确显示每次请求中 Agent 在上下文里包含了哪些消息和观察记录,帮助你理解 Agent 行为,并验证记忆检索是否按预期工作。

打开 Studio,在侧边栏选择 Observability 标签页。打开一个近期 Agent 请求的 trace,查看其 LLM 调用 spans。

按请求切换 memory
按请求切换 memory的直接链接

使用 RequestContext 访问请求特定的值。这样可以根据请求上下文有条件地选择不同的 memory 或存储配置。

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
},
})

更多信息参见请求上下文。

相关内容
相关内容的直接链接