Skip to content

智能体记忆

到现在为止,我们的智能体都是"金鱼脑"——重启就忘,换个会话就忘。本章讲怎么给智能体加记忆:短期记忆让它在一次会话里保持上下文,长期记忆让它跨会话记住用户偏好。

一、两种记忆

类型范围实现类比
短期记忆本次会话内checkpointer + thread_id工作记忆
长期记忆跨会话/跨用户StoreInMemoryStore/PostgresStore笔记本

人类记忆还有更细的分类,对应到智能体:

  • 语义记忆:事实知识("用户叫张三")—— 存 Store。
  • 情景记忆:过往事件("上周用户问过退货")—— 存 Store 带时间戳。
  • 程序记忆:技能/习惯("用户喜欢简洁回复")—— 存 Store 的 profile 区。

二、短期记忆:checkpointer + thread_id

这块在工具智能体实战里提过,这里系统讲。

2.1 原理

LangGraph 在每个图节点执行后会存档当前状态(checkpoint)。下次用相同 thread_id 调用时,自动从上次的状态继续。所以"记忆"本质是状态快照。

2.2 用法

python
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

agent = create_react_agent(
    model=ChatOpenAI(model="gpt-4o-mini", temperature=0),
    tools=[],
    checkpointer=MemorySaver(),
)

config = {"configurable": {"thread_id": "user-001"}}

# 第一轮:告诉它名字
agent.invoke({"messages": [{"role": "user", "content": "我叫张三"}]}, config=config)

# 第二轮:换一次 invoke,但同一个 thread_id
r = agent.invoke({"messages": [{"role": "user", "content": "我刚才说我叫什么?"}]}, config=config)
print(r["messages"][-1].content)   # 会答"张三"

thread_id 就换"会话",互不干扰。MemorySaver 是进程内存储,重启进程丢失;生产环境用 PostgresSaver 等持久化方案。

2.3 查看历史快照

python
# 列出所有快照
for snapshot in agent.get_state_history(config):
    print(snapshot.config["configurable"]["checkpoint_id"],
          "消息数:", len(snapshot.values.get("messages", [])))

get_state_history 可用于"时光倒流"——回到某个历史点重新执行。

三、长期记忆:Store

短期记忆绑死 thread_id,换会话就没了。长期记忆用 Store 跨会话共享。

3.1 InMemoryStore

最简单的 Store,进程内:

python
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()

生产环境用 PostgresStore,用法一致,只是后端换数据库。

3.2 namespace 隔离

Store 用 namespace(命名空间)分层隔离数据,类似文件夹。典型做法:按用户隔离:

python
# 存:namespace 是元组,key 是字符串
store.put(("user", "zhangsan"), "name", {"value": "张三"})
store.put(("user", "zhangsan"), "preference", {"value": "喜欢简洁回复"})

# 取
item = store.get(("user", "zhangsan"), "name")
print(item.value)   # {"value": "张三"}

# 按 namespace 前缀搜索
items = store.search(("user", "zhangsan"))
for it in items:
    print(it.key, it.value)

namespace 用元组(tuple)而非字符串,是为了层级匹配,类似 (部门, 小组, 成员)

3.3 三层 API

方法作用
put(namespace, key, value)写入/更新
get(namespace, key)精确取一条
search(namespace_prefix)按前缀模糊搜多条
delete(namespace, key)删除

注意 search 用的是前缀匹配(user,) 能匹配 (user, zhangsan)(user, lisi)

四、让 agent 主动记忆

光有 store 还不够,agent 得自己决定记什么、何时记。做法是给它两个工具:save_memoryrecall_memory

4.1 定义记忆工具

python
from langchain_core.tools import tool
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()

@tool
def save_memory(key: str, content: str) -> str:
    """把一条信息保存到长期记忆。key 是简短标识如 'name'/'hobby'。
    content 是要记住的内容。"""
    # namespace 写死为当前用户,实际可从 config 取
    store.put(("user", "default"), key, {"content": content})
    return f"已记住 {key}: {content}"

@tool
def recall_memory(key: str = "") -> str:
    """回忆长期记忆。key 留空则返回所有记忆。"""
    if key:
        item = store.get(("user", "default"), key)
        return str(item.value) if item else "无此记忆"
    items = store.search(("user", "default"))
    return "\n".join(f"{i.key}: {i.value['content']}" for i in items)

4.2 构建 agent 并在 prompt 里引导记忆

python
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

PROMPT = """你是一个贴心的助手。
- 用户告诉你个人信息(名字、喜好、习惯)时,主动用 save_memory 记下来。
- 回答前如果有必要,用 recall_memory 回忆一下用户偏好。
- 简短交流不要每次都回忆,避免啰嗦。"""

agent = create_react_agent(
    model=ChatOpenAI(model="gpt-4o-mini", temperature=0),
    tools=[save_memory, recall_memory],
    prompt=PROMPT,
    checkpointer=MemorySaver(),   # 短期记忆也要
)

4.3 体验"跨会话记忆"

python
# 会话 1
config1 = {"configurable": {"thread_id": "session-1"}}
agent.invoke({"messages": [{"role": "user", "content": "我叫张三,喜欢简洁回复,不爱看长篇大论。"}]}, config1)

# 会话 2(不同 thread_id,但 store 是共享的)
config2 = {"configurable": {"thread_id": "session-2"}}
r = agent.invoke({"messages": [{"role": "user", "content": "你还记得我是谁吗?"}]}, config2)
print(r["messages"][-1].content)
# 会回答"你是张三,喜欢简洁回复",因为 agent 会先调 recall_memory

注意:第二个会话的 thread_id 变了,短期记忆(messages 历史)没了,但 agent 通过 recall_memory 工具从 store 里"想起来了"。这就是长期记忆的魔力。

五、完整可运行示例

python
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()

@tool
def save_memory(key: str, content: str) -> str:
    """保存长期记忆。key 如 'name'/'hobby'。"""
    store.put(("user", "default"), key, {"content": content})
    return f"已记住 {key}: {content}"

@tool
def recall_memory(key: str = "") -> str:
    """回忆长期记忆。key 畺空返回全部。"""
    if key:
        item = store.get(("user", "default"), key)
        return str(item.value) if item else "无此记忆"
    items = store.search(("user", "default"))
    return "\n".join(f"{i.key}: {i.value['content']}" for i in items) if items else "暂无记忆"

PROMPT = """你是贴心助手。用户告诉你个人信息时用 save_memory 记下。
回答前必要时用 recall_memory 回忆。简短交流别每次都回忆。"""

agent = create_react_agent(
    ChatOpenAI(model="gpt-4o-mini", temperature=0),
    [save_memory, recall_memory],
    prompt=PROMPT,
    checkpointer=MemorySaver(),
)

# 会话 1:自报家门
agent.invoke({"messages": [{"role": "user", "content": "我叫张三,喜欢喝美式咖啡,最近在学LangGraph。"}]},
             {"configurable": {"thread_id": "s1"}})

# 会话 2:换个 thread_id
r = agent.invoke({"messages": [{"role": "user", "content": "你还记得我喜欢喝什么吗?"}]},
                 {"configurable": {"thread_id": "s2"}})
print("助手:", r["messages"][-1].content)

六、记忆膨胀与清理

长期记忆会越存越多,导致 recall_memory 返回超长文本。对策:

  • 定期清理:在节点里按时间戳删旧记忆。
  • 自动摘要:把多条老记忆压成一条摘要。
  • 按需检索:用带语义搜索的 Store(index=True),让 search 按相似度返回 Top-K 而非全部。LangGraph 的 PostgresStore 支持向量检索。

七、常见踩坑

1. 隐私问题

长期记忆会存用户敏感信息(姓名、地址、偏好)。生产环境务必:

  • 提供用户"查看/删除我的记忆"功能。
  • 敏感字段加密存储。
  • prompt 里声明哪些信息不存(密码、支付信息)。

2. namespace 写错导致记忆串用户

namespace 用元组时,写错一层就会把 A 的记忆存到 B 名下。建议封装一个 get_namespace(config) 函数,从 config 取 user_id 拼 namespace,别到处硬编码。

3. agent 不主动记忆

模型可能"懒得调" save_memory,光嘴上答应"好的我记下了"实际没调工具。在 prompt 里强化:"必须用 save_memory 工具实际保存,不要只是口头说记住了。" 或者在节点后置钩子里检测用户是否给了新信息,强制调用 save。

4. MemorySaver 重启丢失

MemorySaver 是进程内存,服务一重启全没了。开发够用,生产必须换 PostgresSaver / SqliteSaver

八、小结

  • 短期记忆:checkpointer + thread_id,存会话内 messages。
  • 长期记忆:Store + namespace,跨会话共享。
  • 让 agent 主动记忆:给它 save_memory / recall_memory 工具 + prompt 引导。
  • 注意隐私、清理、namespace 正确性、生产环境用持久化存储。

记忆是智能体"个性化"的关键。下一模块我们转向模型集成,看怎么把不同的大模型接进 LangGraph。