《LangChain 系列》Long-term Memory:跨会话如何记住用户偏好?

1. 长期记忆到底是什么?
短期记忆解决“这轮对话怎么接上”。长期记忆解决“这个用户下次再来,我还认不认识他”。
在 LangChain / LangGraph 里,短期记忆通常跟 thread 绑定;长期记忆放在 Store 里,按 namespace 和 key 组织。换一个 thread_id,长期记忆仍然可以被召回。
一句话:messages 是工作台,Store 是档案柜。

2. Store:长期记忆真正落地的地方
LangGraph 的 Store 把长期记忆保存成 JSON 文档。每条记忆都有 namespace、key、value 和元数据。
namespace 像文件夹。key 像文件名。value 才是真正的记忆内容。

开发环境可以用 InMemoryStore。生产环境建议用数据库型 Store,例如 PostgresStore,或者平台托管 Store。InMemoryStore 重启就丢,不适合生产。
3. 什么该记?什么不该记?
长期记忆不是把聊天记录永久保存。那叫日志,不叫记忆。
真正该记的是稳定、可复用、对后续任务有价值的信息。
该记:用户偏好、语言风格、业务画像、明确事实、长期任务经验。
不该记:一次性上下文、验证码、隐私敏感信息、模型推测、未经确认的结论。

4. 三种长期记忆:Semantic、Episodic、Procedural
4.1 Semantic Memory:事实记忆
记事实。比如:用户偏好中文、喜欢短句、关注 A 股短线、风险承受能力低。
这是最常见的长期记忆。它通常用于个性化回答。
4.2 Episodic Memory:经验记忆
记经历。比如:上次这个用户投诉物流,最后转人工解决;上次某个策略执行失败。
它常用于“下次别再犯同样的错”。
4.3 Procedural Memory:规则记忆
记行为规则。比如:金融场景必须提示风险;客服回答先确认订单号;输出永远简短。
它更像长期 Prompt 或策略配置。
5. LangChain 怎么把 Store 注入 Agent?
核心只有两步。第一步,创建 Agent 时传入 store。第二步,工具函数里通过 ToolRuntime 访问 runtime.store。

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.tools import ToolRuntime, tool
from langgraph.store.memory import InMemoryStore
@dataclass
class Context:
user_id: str
store = InMemoryStore()
@tool
def save_user_profile(profile: dict, runtime: ToolRuntime[Context]) -> str:
user_id = runtime.context.user_id
runtime.store.put(("users",), user_id, profile)
return "saved"
agent = create_agent(
model="openai:gpt-4o-mini",
tools=[save_user_profile],
store=store,
context_schema=Context,
)
这段代码的重点不是模型,也不是工具名。重点是 runtime.store。它就是长期记忆的入口。
6. 从 create_agent 到 BaseStore
把源码链路压缩后,就是下面这条线。

6.1 create_agent(..., store=store)
create_agent 会把 store 挂到 Agent 运行时。Agent 执行工具时,ToolNode 会从运行时拿到 store,再封装进 ToolRuntime。
6.2 ToolNode 构造 ToolRuntime
ToolNode 执行工具前,会解析模型返回的 tool_calls。然后为每个工具调用构造 ToolRuntime。这个对象里包含 state、context、store、tool_call_id、stream_writer 等。
所以工具函数不需要自己查全局变量,也不需要自己找用户上下文。runtime 里已经带好了。
6.3 BaseStore 是统一接口
BaseStore 不是某个数据库。它是接口。真正存到哪里,取决于你用 InMemoryStore、PostgresStore,还是平台 Store。
源码里,get/search/put 并不直接落库,而是包装成 GetOp、SearchOp、PutOp,再交给 batch()。具体 Store 实现 batch()。
# 源码逻辑可以压缩理解成这样:
store.get(namespace, key)
-> batch([GetOp(namespace, key)])
store.search(namespace, query=..., filter=...)
-> batch([SearchOp(namespace, query, filter)])
store.put(namespace, key, value, index=...)
-> batch([PutOp(namespace, key, value, index)])
6.4 Item 和 SearchItem
store.get 返回 Item。Item 里有 value、key、namespace、created_at、updated_at。
store.search 返回 SearchItem 列表。SearchItem 比 Item 多一个 score,用来表示相关性。
7. 写记忆:在线写,还是后台写?
写长期记忆有两种方式。

7.1 Hot Path:在线写
用户说“以后都用中文回答我”。Agent 当场调用 save_user_profile。下一句话马上生效。
优点是及时。缺点是慢,而且容易把模型的误判写进长期记忆。
7.2 Background:后台写
主流程先回答。回答结束后,后台任务抽取稳定事实,再写入 Store。
优点是主链路更快。缺点是记忆不是马上生效。
企业项目更推荐:重要偏好在线写;普通画像后台写;敏感信息不自动写。
8. 读记忆:get、search、filter
读记忆也不要复杂化。常见就三种。

8.1 get:精确读取
你知道用户 ID,也知道要读用户画像,就用 get。
item = runtime.store.get(("users",), runtime.context.user_id)
profile = item.value if item else {}
8.2 search:语义搜索
你不知道具体 key,只知道当前问题需要找相关历史偏好,就用 search。
items = runtime.store.search(
(runtime.context.user_id, "memories"),
query="用户喜欢什么回答风格",
limit=3,
)
8.3 filter:结构化过滤
你只想查某个业务、某个类型、某个租户的数据,就加 filter。
items = runtime.store.search(
("tenant_001", "users"),
filter={"type": "preference", "status": "active"},
limit=5,
)
9. 企业级架构:记忆必须被业务系统管住
长期记忆不能只放在 AI 服务里自嗨。它要接入账号体系、租户体系、权限体系、审计体系。

推荐架构:Spring Boot 管用户、权限、审计;Python AI 服务管 Agent、Tools、Memory;Store 管长期记忆;数据库管持久化和删除。
Agent 可以建议保存记忆,但最终要经过业务规则。尤其是金融、医疗、客服、企业内部系统。
10. 长期记忆最容易踩的坑

最常见的错误,是把 thread_id 当 user_id。thread_id 是会话线程。user_id 是用户身份。两个概念不能混。
第二个错误,是把所有消息都塞进 Store。长期记忆应该是提炼后的事实,不是原始流水账。
第三个错误,是没有删除能力。用户说“不要再记住这个”,系统必须能删。
11. 总结
长期记忆的核心不是“存”。而是“存什么、怎么存、什么时候召回、谁能删除”。
LangChain / LangGraph 给你的不是一个神秘记忆魔法,而是一套清晰的工程接口:Store、namespace、key、value、runtime.store、BaseStore。
记住最后这句话:短期记忆让对话不断片;长期记忆让 Agent 真正认识用户。
内容来源:《LangChain 系列》Long-term Memory:跨会话如何记住用户偏好?:功能变化与行业影响解析_热闻岛
更多推荐

所有评论(0)