第 11 步:记忆系统¶
这一节学什么¶
- 短期状态和长期记忆的区别
- 正常的 Agent memory 接法是什么
- 本地轻量 memory 和语义 memory 的边界
- 长期记忆最小写入、检索和跨会话读取链路
你会运行什么¶
示例代码:
examples/getting_started/step_11_memory.py
运行:
这一节先建立心智模型¶
这一步会先用一个完全本地可跑的例子,把长期记忆最小链路走通。
你应该先区分:
messages、done、final_answer、rounds这类字段,属于一次运行内的工作状态- memory 属于跨运行、跨会话保留的信息
这个例子里最重要的点是:
- 第一段 agent session 会把用户偏好写进长期记忆
- 第二段会启动一个新的 agent session
- 新 session 不再依赖上一轮
messages,而是通过memory_search取回刚才写入的内容
核心概念¶
Memory 不是 messages 的替代品。
更准确地说:
messages负责当前对话和当前推理链路- memory 负责长期保留、后续检索和按需注入
这一层通常要回答三个问题:
- 记录什么
- 什么时候检索
- 检索结果怎么回到 prompt 或状态里
在 Jianmu 里,getting started 这一节先走最简单也最正常的接法:
- 长期记忆先暴露成 tool
- ReAct agent 在需要时自己调用
memory_add/memory_search
这比“手写 actions 去调 tool”更接近正常使用方式。
这个示例做了什么¶
这个步骤故意不用外部向量库或外部记忆服务,而是走最小本地链路:
SimpleStore:本地 JSON 存储MemoryService:带命名空间的长期记忆门面create_memory_tools(...):把长期记忆暴露成memory_add/memory_searchcreate_react_node(...):把 memory tools 接进一个普通 ReAct agent
也就是说,这一步重点不是“高级语义记忆”,而是先看清框架里的标准接法:
- 准备一个长期记忆 backend
- 用
MemoryService给它加上 namespace - 把 memory 包装成 tool
- 让 agent 在对话里自行决定什么时候写入、什么时候检索
为什么示例里要显式新建第二个 session¶
这是为了避免一个常见误解:
- 如果你在同一个 agent session 里先说“记住 X”,下一轮再问“你记得什么”,模型很可能直接靠当前
messages回答 - 这时即使没有真正命中 long-term memory,表面上也像“记忆生效了”
所以这个步骤故意在写入后重新创建一个 fresh agent:
- 旧的会话历史不再参与回答
- 这时还能答出来,才说明确实走到了长期记忆链路
为什么这里用规范化文本¶
SimpleStore 是一个轻量本地 backend,不是语义检索系统。
它更适合这种写法:
communication style: concise technical explanationspreferred language: Python
也就是把长期信息存成短而明确的字段式文本。
这样做的目的不是追求“最好看的 memory 数据”,而是让你先看清:
- memory 是怎么接进 agent 的
- agent 是怎么通过 tool 写入和读取它的
如果你希望更自然的语义召回,比如:
- 用户随便说一段话
- 后面用另一种表达方式也能稳稳搜回来
那就不该继续强化 SimpleStore,而应该换成语义 memory backend。
SimpleStore 和语义 memory 的边界¶
可以先这样理解:
SimpleStore- 适合 getting started、本地调试、最小链路验证
- 检索更接近关键词匹配
Mem0LongTermMemory- 适合需要语义提取、语义检索、长期偏好归纳的场景
如果你想看语义 memory 的完整示例,继续看:
examples/memory/mem0_long_term_demo.py
常见误区¶
这一节最容易踩的坑主要有三个:
-
把
messages当成 memory -
在同一个 session 里,模型可能直接靠当前对话历史回答
- 这时即使没有真正命中 long-term memory,看起来也像“它记住了”
所以验证长期记忆时,最好像这个示例一样新建一个 fresh session。
-
用
SimpleStore期待语义召回 -
SimpleStore更接近轻量关键词检索 - 它不适合“用户换一种说法也能稳稳搜回来”的场景
如果你需要这种能力,应该换成 Mem0LongTermMemory 之类的语义 memory backend。
-
不做 namespace 隔离
-
如果 demo、测试、真实会话共用同一个 store 和 namespace
- 旧数据就可能串进新结果
这会让你很难判断当前这次 memory 行为到底是不是正确的。
运行后观察什么¶
- 第一段 session 里,agent 会调用
memory_add - 第二段 fresh session 里,agent 会调用
memory_search memory_search会把命中的长期记忆格式化成文本结果messages里会出现 memory tool 的 observation- 同一个
MemoryService既可以被代码直接调用,也可以被包装成 Agent 可用工具 - 示例默认会生成新的 namespace,避免旧 demo 数据污染当前结果
你可以特别关注这几个现象:
- 第二段回答前是否真的出现了
memory_search(...) memory_searchobservation 里是否真的返回了你刚写入的字段式文本Raw stored records是否和当前 namespace 对应
这一步学完后应该会什么¶
你应该能回答:
- 为什么 memory 不等于聊天历史
MemoryService在主路径里扮演什么角色- 怎样把长期记忆以 tool 的形式接进 Agent
- 为什么验证 long-term memory 时要区分“同 session 记得”与“跨 session 还能取回”
- 什么时候应该从
SimpleStore升级到语义 memory backend