前端开发AI Agent之Memory理论篇

我是使用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 条消息
});
  • 注意 :设置为 false 可禁用近期消息限制,包含所有消息(可能增加计算成本)。

3.2 semanticRecall

  • 作用:配置语义召回,检索与当前查询语义相关的历史消息。
  • 子选项:
    • topK:返回的最相关消息数量(默认:3)。
    • messageRange:围绕每个相关消息的上下文范围(例如,前 2 条和后 1 条消息)。
  • 示例:
yaml 复制代码
const memory = new Memory({
  options: {
    semanticRecall: {
      topK: 3,
      messageRange: { before: 2, after: 1 }
    }
  }
});
  • 注意 :可设置为 false 禁用语义召回,或设置为 true 使用默认配置。

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 在代理处理用户请求时按照以下步骤执行:

  1. 输入解析:
    • 处理器接收用户查询、当前线程的 threadId 和 resourceId。
    • 提取请求中的内存配置(如 memoryOptions)。
  1. 消息检索:
    • 从数据库中加载指定线程的近期消息(受 lastMessages 限制)。
    • 若启用语义召回,执行向量搜索,检索相关历史消息。
  1. 上下文优化:
    • 修剪过长的消息,确保总标记数在上下文窗口内。
    • 合并工作内存和历史消息,应用优先级排序。
  1. 工作内存更新:
    • 解析代理响应中的标签或工具调用,更新工作内存。
    • 将更新后的工作内存存储到数据库。
  1. 输出生成:
    • 处理器将优化后的上下文注入语言模型的提示中。
    • 若使用流式响应,处理器确保工作内存标签对用户不可见。

整个流程通过异步操作实现,确保低延迟和高吞吐量。


9. 总结

Mastra 的 Memory 系统通过灵活的存储、语义召回和工作内存功能,为 AI 代理提供了强大的上下文管理能力。无论是简单的会话历史记录,还是复杂的语义搜索和 RAG 集成,Memory 都能满足从原型到生产的需求。开发者可以通过简单的配置快速上手,并利用高级功能实现复杂的应用场景。

10. 参考

  1. Memory API
  2. Memory文档
相关推荐
不可能片场6 小时前
Electron 发布核验 别把没查到当成没发出去
前端·electron
开开心心就好7 小时前
文件被占用删不掉?解锁工具强制删除
java·运维·服务器·开发语言·前端·pdf·ocr
inksci7 小时前
发布Ai生成的html markdown 推荐
前端·javascript·html
在西安放羊的牛油果7 小时前
WebP 图片优化方案详解
运维·前端·架构
coding漫漫长路7 小时前
签名PDF一压就失效,接压缩需求前先查这5件事
前端
Lank_M7 小时前
PDF签完名还能改什么?会签能过,压缩不行
前端
blackappleD7 小时前
REA 30 万 Star 背后:让 AI Agent 无源码读懂软件的 MCP 逆向工具链
aigc·ai编程
补码缩写7 小时前
压缩前查PDF签名,字节搜索会漏掉对象流
前端
星光不问赶路人7 小时前
Vue 项目类型检查:深入理解 vue-tsc --build
前端·vue.js