第 11 章 · Observational Memory 观察记忆
本章目标:理解观察记忆的原理(Observer/Reflector 后台代理),学会配置长期记忆并让 Agent 跨会话记住用户事实。
11.1 为什么需要观察记忆
普通对话历史是"逐字记录":消息越多,上下文越臃肿,token 成本越高,且早期信息容易被截断丢失。Mastra 的 Observational Memory(OM,@mastra/memory@1.1.0+) 用另一种思路解决:
- 两个后台代理 Observer 和 Reflector 持续旁观对话;
- 它们维护一份高密度观察日志(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. 关于观察记忆的成本,正确的说法是?
🛠️ 动手实践
- 启用 OM 并分两轮对话教 Agent 记住你的名字和职业,重启进程后再问它是否记得。
- 把
observationalMemory.model换成更便宜的模型,对比记忆质量差异。 - 为同一个
resource创建两个不同thread,验证在 A 对话中记住的事实能否在 B 对话中召回。