我是使用mastra开发,Mastra 是一个开源的 TypeScript AI 代理框架,旨在帮助开发者快速构建 AI 应用。其中的 Memory(内存) 部分是 Mastra 的核心功能之一,用于管理代理的上下文和会话历史,从而实现更自然、连贯的交互体验。以下是 Mastra 中 Memory 部分的系统性介绍
1. Memory 概述
在 Mastra 中,Memory 是代理管理上下文的核心机制,负责存储和检索会话历史、用户相关信息以及语义相关的上下文。Memory 的设计目标是让代理能够像人类一样"记住"之前的交互内容,从而提供更智能的响应。
Memory 的上下文管理基于上下文窗口(Context Window) ,即语言模型在任意时刻可见的总信息。Mastra 将上下文分为以下三个主要部分:
- 系统指令和用户信息(Working Memory) :存储代理的系统提示和用户的关键信息(例如用户名、偏好等)。
- 近期消息(Message History) :保存最近的会话消息,提供即时的对话上下文。
- 语义召回(Semantic Recall) :检索与当前查询语义相关的较旧消息,增强上下文的深度。
此外,Mastra 提供 Memory Processors 来优化上下文管理,例如修剪过长的上下文或移除无关信息。
Memory 的核心优势在于其灵活性和可扩展性,支持多种存储后端(如 LibSQL、PostgreSQL、Upstash)和嵌入模型(如 FastEmbed),适用于从原型开发到生产环境的各种场景。
2. Memory 的核心组件
2.1 Memory 类
Memory
类是 Mastra 中管理会话历史和上下文的核心组件。它支持以下功能:
- 会话历史存储 :将消息存储在线程中,按
resourceId
(用户或实体 ID)和threadId
(会话线程 ID)组织。 - 语义搜索:通过向量数据库和嵌入模型支持语义召回,检索与查询相关的历史消息。
- 工作内存(Working Memory) :存储用户关键信息(如姓名、偏好),并支持跨会话持久化。
- 线程管理:支持创建、更新和检索会话线程,方便管理多个对话。
默认配置下,Memory
使用 LibSQL 作为存储后端,FastEmbed 提供嵌入支持,开发者无需额外配置即可快速上手。
2.2 存储后端
Mastra 的 Memory 系统支持灵活的存储后端,开发者可以根据需求选择合适的数据库:
- LibSQL:默认存储选项,适合本地开发和轻量级应用。
- PostgreSQL(pgvector) :适合需要高性能和扩展性的生产环境。
- Upstash:基于 Redis 的云存储,适合低延迟的分布式应用。
- 其他支持的向量数据库包括 Pinecone、Qdrant、Chroma 等,用于语义搜索和 RAG(检索增强生成)。
存储后端通过统一的接口操作,开发者可以在开发和生产环境中无缝切换,而无需更改代码逻辑。
2.3 上下文管理
Mastra 的 Memory 系统通过以下方式管理上下文:
- 消息历史:默认存储最近 40 条消息(可配置),确保代理能够快速访问近期对话。
- 语义召回:通过嵌入模型和向量搜索,检索与当前查询语义相似的历史消息,增强上下文相关性。
- 工作内存 :以 Markdown 或 XML 格式存储用户关键信息,支持通过文本流标签或工具调用更新。
2.4 Memory API
Mastra 提供了一套 Memory API,用于管理和查询会话线程及消息历史。例如:
- 获取线程 :
client.getMemoryThreads({ resourceId, agentId })
获取指定资源的所有线程。 - 创建线程 :
client.createMemoryThread({ title, metadata, resourceId, agentId })
创建新会话线程。 - 更新线程 :
thread.update({ title, metadata, resourceId })
修改线程元数据。
这些 API 简化了开发者对会话历史的直接操作,适合需要自定义内存管理的场景。
3. Memory 的配置
Memory 的配置通过 Memory
类的 options
对象实现,允许开发者自定义内存行为。以下是主要配置项及其作用:
3.1 lastMessages
- 作用:控制代理在上下文窗口中包含的近期消息数量。
- 默认值:40 条。
- 示例:
arduino
const memory = new Memory({
options: { lastMessages: 20 } // 仅包含最近 20 条消息
});
3.2 semanticRecall
- 作用:配置语义召回,检索与当前查询语义相关的历史消息。
- 子选项:
-
topK
:返回的最相关消息数量(默认:3)。messageRange
:围绕每个相关消息的上下文范围(例如,前 2 条和后 1 条消息)。
- 示例:
yaml
const memory = new Memory({
options: {
semanticRecall: {
topK: 3,
messageRange: { before: 2, after: 1 }
}
}
});
3.3 workingMemory
- 作用:启用工作内存,存储用户关键信息,支持跨会话持久化。
- 子选项:
-
enabled
:是否启用工作内存(默认:false
)。use
:更新模式,text-stream
(通过 XML 标签)或tool-call
(通过工具调用)。template
:定义工作内存的结构(Markdown 格式)。
- 示例:
yaml
const memory = new Memory({
options: {
workingMemory: {
enabled: true,
use: 'text-stream', // 或者tool-call
template: `# User\n- First Name: \n- Last Name: `
}
}
});
- 注意 :
tool-call
模式适合与toDataStream()
配合使用,避免文本流冲突。这种模式提供了对内存更新的更明确控制,当与那些更擅长使用工具而不是管理文本标签的代理一起工作时,可能会更受欢迎
3.4 threads
- 作用:配置线程创建行为,例如是否自动生成线程标题。
- 子选项:
-
generateTitle
:基于用户首条消息的 LLM 摘要生成线程标题。
- 示例:
yaml
const memory = new Memory({
options: {
threads: { generateTitle: true }
}
});
3.5 存储和向量配置
- 存储后端 :通过
storage
参数指定,例如LibSQLStore
或UpstashStore
。 - 向量数据库 :通过
vector
参数指定,例如LibSQLVector
或PineconeVector
。 - 示例:
css
const memory = new Memory({
storage: new LibSQLStore({ url: "file:memory.db" }),
vector: new LibSQLVector({ url: "file:vector.db" })
});
开发者可以通过这些配置灵活调整 Memory 的行为,适应不同的应用场景。
4. Memory 的使用方式
4.1 基本设置
要为代理启用 Memory,只需在创建 Agent
时传入 Memory
实例:
javascript
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
import { openai } from "@ai-sdk/openai";
const memory = new Memory();
const agent = new Agent({
name: "MyMemoryAgent",
instructions: "You are a helpful assistant with memory.",
model: openai("gpt-4o"),
memory
});
4.2 会话交互
在调用代理的 stream()
或 generate()
方法时,必须提供 resourceId
和 threadId
以启用 Memory:
php
await agent.stream("Remember my favorite color is blue.", {
resourceId: "user_alice",
threadId: "preferences_thread"
});
const response = await agent.stream("What's my favorite color?", {
resourceId: "user_alice",
threadId: "preferences_thread"
}); // 代理将回忆并返回 "blue"
4.3 工作内存更新
工作内存可以通过文本流标签或工具调用自动更新。例如,在文本流模式下:
javascript
import { maskStreamTags } from "@mastra/core/utils";
const response = await agent.stream("My name is Jane", {
threadId: randomUUID(),
resourceId: "SOME_USER_ID"
});
for await (const chunk of maskStreamTags(response.textStream, "working_memory")) {
process.stdout.write(chunk); // 隐藏工作内存标签,仅输出用户可见内容
}
4.4 动态内存配置
开发者可以在每次请求中覆盖全局内存配置:
php
await agent.stream("What's the weather today?", {
resourceId: "user_bob",
threadId: "weather_thread",
memoryOptions: {
lastMessages: 10,
semanticRecall: { topK: 2, messageRange: 5 }
}
});
4.5 开发环境支持
Mastra 提供内置的 开发游乐场(Playground) ,允许开发者在本地测试代理的 Memory 功能。运行 mastra dev
后,可以通过 UI 查看代理的状态、内存内容和会话历史,简化调试过程。
5. 实际应用场景
Mastra 的 Memory 系统适用于多种 AI 应用场景,以下是一些典型用例:
5.1 客户支持机器人
- 需求:机器人需要记住用户的偏好、问题历史和上下文,提供连贯的对话。
- 实现 :使用
resourceId
标识用户,threadId
区分不同支持会话,启用工作内存存储用户关键信息(如姓名、问题类型)。 - 示例 :用户报告问题后,代理可召回之前的对话,快速提供解决方案。
5.2 个性化推荐
5.3 知识库助手
- 需求:代理需要结合内部文档和用户查询历史回答复杂问题。
- 实现:结合 RAG 和 Memory,代理通过语义召回检索相关历史消息,并从知识库中提取上下文。
- 示例 :学术研究助手根据用户之前的提问,结合论文内容提供精准答案。
5.4 烹饪助手
- 需求:代理根据用户提供的食材和历史偏好推荐菜谱。
- 实现:使用 Memory 存储用户提供的食材列表和工作内存记录饮食偏好。
- 示例 :用户提到现有食材(面条、番茄),代理推荐意面菜谱,并记住用户偏好低盐口味。
6. 高级功能与扩展
6.1 语义召回与 RAG 集成
Memory 的语义召回功能与 Mastra 的 RAG 系统无缝集成。开发者可以通过向量数据库存储文档嵌入,并在查询时结合会话历史和外部知识库生成响应。例如:
arduino
const memory = new Memory({
vector: new PgVector(process.env.POSTGRES_CONNECTION_STRING),
options: { semanticRecall: { topK: 5 } }
});
6.2 多代理协作
在多代理工作流中,Memory 支持共享会话历史,确保不同代理能够访问相同的上下文。例如,一个支持代理可以将用户问题记录在共享线程中,另一个分析代理随后处理。
6.3 可观测性
Mastra 的 Memory 系统与 OpenTelemetry 集成,支持跟踪消息存储和检索的操作。开发者可以通过 observability 工具(如 SigNoz、Langfuse)监控内存性能和上下文使用情况。
6.4 生产化支持
Memory 支持生产环境的高可用性配置,例如使用 PostgreSQL 或 Upstash 作为存储后端,并通过分布式向量数据库实现低延迟的语义搜索。
7. 注意事项与最佳实践
- 必须提供 ID :代理调用时必须指定
resourceId
和threadId
,否则 Memory 功能不会生效。 - 避免重复历史 :不要在代理调用中手动发送完整会话历史,Mastra 会自动管理历史注入,避免重复。
- 优化上下文 :通过调整
lastMessages
和semanticRecall
参数,平衡上下文丰富度和性能开销。 - 数据迁移 :在切换存储后端(例如从 LibSQL 到 PostgreSQL)时,需要手动迁移数据。
- 调试支持 :利用 Mastra 的 Playground 调试 Memory 配置,检查消息存储和召回效果。
8.Memory Processors
在 Mastra 的 Memory 系统中, 是用于优化和管理上下文的核心组件,负责处理会话历史、语义召回和工作内存,以确保代理能够高效、准确地利用上下文,同时避免上下文窗口过载或无关信息干扰。以下是对 Memory Processors 的系统性介绍,涵盖其定义、功能、实现机制、使用方式、配置选项以及实际应用场景。
1. Memory Processors 概述
Memory Processors 是 Mastra Memory 系统中的一组处理逻辑,设计目标是动态优化代理的上下文管理。它们通过修剪、过滤、增强或重新组织上下文数据,确保语言模型接收到最相关、最精简的输入,从而提升性能和响应质量。
Memory Processors 的主要作用包括:
- 上下文修剪:移除过长或无关的历史消息,保持上下文在模型的窗口限制内。
- 语义增强:通过语义召回,添加与当前查询高度相关的历史消息。
- 工作内存管理:动态更新和格式化用户关键信息,确保跨会话的持久性和一致性。
- 性能优化:减少不必要的计算开销,提升响应速度和内存效率。
Memory Processors 与 Mastra 的 Memory 类紧密协作,通常在代理处理用户请求时自动触发。开发者可以通过配置选项或自定义处理器扩展其功能,适应不同的应用场景。
2. Memory Processors 的工作流程
Memory Processors 在代理处理用户请求时按照以下步骤执行:
- 输入解析:
-
- 处理器接收用户查询、当前线程的
threadId
和resourceId
。 - 提取请求中的内存配置(如
memoryOptions
)。
- 处理器接收用户查询、当前线程的
- 消息检索:
-
- 从数据库中加载指定线程的近期消息(受
lastMessages
限制)。 - 若启用语义召回,执行向量搜索,检索相关历史消息。
- 从数据库中加载指定线程的近期消息(受
- 上下文优化:
-
- 修剪过长的消息,确保总标记数在上下文窗口内。
- 合并工作内存和历史消息,应用优先级排序。
- 工作内存更新:
-
- 解析代理响应中的标签或工具调用,更新工作内存。
- 将更新后的工作内存存储到数据库。
- 输出生成:
-
- 处理器将优化后的上下文注入语言模型的提示中。
- 若使用流式响应,处理器确保工作内存标签对用户不可见。
整个流程通过异步操作实现,确保低延迟和高吞吐量。
9. 总结
Mastra 的 Memory 系统通过灵活的存储、语义召回和工作内存功能,为 AI 代理提供了强大的上下文管理能力。无论是简单的会话历史记录,还是复杂的语义搜索和 RAG 集成,Memory 都能满足从原型到生产的需求。开发者可以通过简单的配置快速上手,并利用高级功能实现复杂的应用场景。