Skip to content

第 11 章 · Observational Memory 观察记忆

本章目标:理解观察记忆的原理(Observer/Reflector 后台代理),学会配置长期记忆并让 Agent 跨会话记住用户事实。

11.1 为什么需要观察记忆

普通对话历史是"逐字记录":消息越多,上下文越臃肿,token 成本越高,且早期信息容易被截断丢失。Mastra 的 Observational Memory(OM,@mastra/memory@1.1.0+) 用另一种思路解决:

  • 两个后台代理 ObserverReflector 持续旁观对话;
  • 它们维护一份高密度观察日志(observation log)——"用户偏好蓝色"、"项目用 pnpm 而非 npm"这类提炼后的事实;
  • 当历史增长到激活条件阈值时,原始旧消息被观察日志替换,上下文保持紧凑而不丢关键信息。

与 Working Memory 的区别

Working Memory 是显式的"便签本",由模型按指令读写固定格式内容;Observational Memory 是自动的、持续运行的长期记忆管线,无需用户提示。

11.2 最小可用配置

OM 需要持久化存储支撑。以下脚本创建本地 LibSQL 数据库并启用观察记忆:

typescript
// src/observational-memory.ts
import { Agent } from '@mastra/core/agent'
import { LibSQLStore } from '@mastra/libsql'
import { Memory } from '@mastra/memory'

const memory = new Memory({
  // 观察日志和历史消息都需要落盘
  storage: new LibSQLStore({
    id: 'memory-storage',
    url: 'file:./memory.db',
  }),
  options: {
    // 指定后台代理用于提炼观察的模型;true 则使用默认模型
    observationalMemory: {
      model: 'openai/gpt-5-mini',
    },
  },
})

export const agent = new Agent({
  id: 'memory-agent',
  name: 'Memory Agent',
  instructions: 'You are a helpful assistant.',
  model: 'openai/gpt-5-mini',
  memory,
})

11.3 跨调用验证记忆

resource 标识用户实体,thread 标识一段对话。复用两者即可延续同一上下文:

typescript
// src/demo.ts
import { agent } from './observational-memory'

const memoryOptions = { resource: 'user-123', thread: 'conversation-123' }

// 第一轮:告知一个个人事实
const first = await agent.generate(
  '记住:我最喜欢的颜色是蓝色。',
  { memory: memoryOptions },
)
console.log(first.text)

// 第二轮(甚至重启进程后的新对话):模型能回忆起该事实
const second = await agent.generate(
  '我最喜欢什么颜色?',
  { memory: memoryOptions },
)
console.log(second.text) // → 你最喜欢的颜色是蓝色。

11.4 在 Mastra 实例上挂载存储

生产项目中推荐把 storage 配置在 Mastra 实例上,所有 Agent 共享:

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

export const mastra = new Mastra({
  // 全局默认存储:memory / workflow 快照 / 追踪数据共用
  storage: new LibSQLStore({ url: 'file:./mastra.db' }),
  agents: { memoryAgent: agent },
})

11.5 检查记忆状态

排查记忆问题时可直接读取存储中的线程与资源:

typescript
// src/check-memory.ts —— 列出某用户的所有会话线程
const memory = agent.memory!
const threads = await memory.getThreadsByResourceId({
  resource: 'user-123',
})
for (const t of threads) {
  console.log(`thread=${t.id} 标题=${t.title} 创建于 ${t.createdAt}`)
}

11.5 使用注意事项

  • OM 会消耗额外的后台 LLM 调用(Observer/Reflector),低配模型即可胜任;
  • 激活条件可调:历史多长才触发压缩,需在成本与一致性间权衡;
  • 敏感信息会被写进观察日志——合规场景应在 Processor 层做脱敏。

本章小结

  • Observational Memory 由 Observer/Reflector 后台代理自动提炼长期记忆;
  • 必须配置持久化 storage 才能跨会话生效;
  • resource + thread 定位用户与对话;旧消息达到阈值后被观察日志替换;
  • 后台提炼有额外 token 开销,选便宜的小模型即可。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. Observational Memory 中负责提炼和维护观察日志的是?

2. 启用 Observational Memory 的必要前提是?

3. generate() 时传入的 memory 选项中,resource 和 thread 分别代表什么?

4. 关于观察记忆的成本,正确的说法是?

🛠️ 动手实践

  1. 启用 OM 并分两轮对话教 Agent 记住你的名字和职业,重启进程后再问它是否记得。
  2. observationalMemory.model 换成更便宜的模型,对比记忆质量差异。
  3. 为同一个 resource 创建两个不同 thread,验证在 A 对话中记住的事实能否在 B 对话中召回。