长期记忆:让 Agent 跨会话认识用户
作者:程序员马丁
Ragent AI —— 从 0 到 1 纯手工打造企业级 Agentic RAG,拒绝 Demo 玩具!AI 时代,助你拿个offer。
前面几篇咱们一路走来,先给 TinyAgent 装上了短期记忆(ChatMemory 接口 + InMemoryChatMemory),又实现了三种记忆管理策略(滑动窗口、摘要压缩、混合策略),最后用 PostgreSQL 做了持久化(JdbcChatMemory + SessionManager),让会话记忆能跨重启保留、在不同用户之间互相隔离。
到目前为止,Agent 的记忆能力已经不错了——同一个会话里能记住之前聊过什么,服务重启也不怕丢,用户和会话之间互不干扰。但还有一个问题没解决:每个会话的记忆是孤立的。
假设一个用户今天上午在比特严选的客服窗口开了一个会话,聊了 6 轮,从查物流到退款到推荐新款扫地机,Agent 表现得像个老朋友——记得订单号、知道退款编号、推荐了 S20 Pro。用户满意地关了窗口。
第二天下午,这个用户又打开客服窗口,开了一个新会话,问了一句:
昨天那个退款到账了吗?
Agent 的回复:
请问您说的是哪个退款呢?能提供一下订单号吗?
用户昨天刚聊了 6 轮,Agent 今天就完全不认识他了。
这不是 Bug——JdbcChatMemory 忠实地把昨天的对话存在了数据库里,只要用户点开昨天那个会话,所有消息都能完整还原。问题在于,用户今天开的是一个新会话,新会话的消息列表是空的,Agent 自然什么都不知道。
会话记忆解决的是单次会话内的连贯性。要让 Agent 跨会话记住用户,需要长期记忆。
本项目中具体代码已上传 GitHub TinyAgent,大家 Clone 项目后,将代码分支切换到 1.8.x,默认主分支是最新代码。运行前复制
.env.example为.env,把自己的 API Key 填进去,默认阿里云百炼平台;.env已加入.gitignore,切分支时不会丢。
会话记忆 vs 长期记忆:边界在哪
先把两者的边界理清楚。
| 维度 | 会话记忆 | 长期记忆 |
|---|---|---|
| 生命周期 | 一次会话(开始到结束) | 跨会话持久化(天、周、月) |
| 存储介质 | 内存 / PostgreSQL(JdbcChatMemory) | Key-Value / 向量库 |
| 写入时机 | 每轮对话实时追加 | 会话结束时提炼关键信息 |
| 读取时机 | 每轮对话构建 messages 时注入 | 新会话开始时按相关性检索 |
| 内容粒度 | 原始消息(用户说了什么、Agent 回了什么) | 提炼后的结构化信息(用户偏好、交互记录) |
| Token 占用 | 随对话轮次线性增长 | 通常固定在几百 Token 以内 |
用一句话概括两者的关系:会话记忆管一次会话内的连贯性,长期记忆管跨会话的个性化。
打个比方:会话 记忆就像你跟朋友的一次电话通话——挂了电话,录音还在(JdbcChatMemory 帮你存着),下次想回顾可以翻出来。但如果你接到一通新电话,你不会自动想起上次聊了什么。长期记忆就像你对这个朋友的了解——他喜欢什么、最近在忙什么、上次帮他办了什么事——这些信息在你接起电话的瞬间就自动浮现在脑海里,不需要翻任何录音。
三层记忆的完整架构
加上之前几篇实现的能力,TinyAgent 的记忆体系现在有三层,各管各的:

有一个容易混淆的地方:会话摘要和交互记录不是一回事。
| 维度 | 会话摘要 | 交互记录 |
|---|---|---|
| 归属 | 会话级(属于某个 session) | 用户级(属于某个 user) |
| 写入时机 | 会话进行中,消息超过阈值时自动压缩 | 会话结束时,调大模型提炼一次 |
| 内容 | 对话的压缩版(为了省 Token) | 关键事件的富文本叙述(为了给未来会话用) |
| 谁管 | HybridChatMemory(第 11 篇) | UserProfileExtractor(本篇) |
| 生命周期 | 随会话存在 | 跨会话持久化,保留数周到数月 |
会话摘要解决的是“当前这通电话太长了,把前面说过的内容压缩一下”;交互记录解决的是“下次来电话时,快速回忆起上次聊了什么”。两者在不同层次解决不同问题, 互不替代。
在实际代码中,两者通过 PersistentHybridChatMemory 和 LongTermMemoryRetriever 分别管理,最终在 ReActAgent 的 messages 数组里各就各位:
messages 数组的完整结构:
[0] system: 系统提示词(你是比特严选的智能客服...)
[1] system: 长期记忆上下文(用户画像 + 相关交互记录) ← 长期记忆层
[2] system: [对话摘要](HybridChatMemory 压缩的) ← 会话记忆层
[3] user: 最近的用户输入(问题) ← 会话记忆层
[4] assistant: 最近的 Agent 回复 ← 会话记忆层
...
[N] user: 当前轮次的用户输入
这一篇聚焦在最上面那一层——长期记忆。会话记忆的持久化和压缩已经在前面的篇章里实现了,这里直接复用。