Agent 的记忆不是向量数据库:三种记忆架构的真实取舍
做 Agent 的人迟早会撞上同一个问题:对话一长,它就开始忘事。
常见的第一反应是「上向量数据库」。文档切片、embedding、检索 Top-K,一套下来,Agent 好像真的记住了。但用两周你会发现:它能翻出你上周说过的那句话,却不记得你已经否决过的方案;能检索到「预算 50 万」,却不知道这个数字后来改成了 30 万。
向量检索擅长「找回原话」,不擅长「记住结论」。 这是两件事。
一、先把「记忆」拆开
Agent 的记忆至少有三个层次,混在一起就会做错决策:
| 层次 | 内容 | 生命周期 | 适合的存储 |
|---|---|---|---|
| 工作记忆 | 当前任务的中间状态 | 分钟级 | 上下文窗口 |
| 情景记忆 | 发生过什么、结论是什么 | 天/周级 | 结构化文件或表 |
| 知识记忆 | 领域事实、文档 | 长期 | 向量库 / 全文索引 |
大多数「Agent 记不住」的问题,其实是情景记忆缺失——它没有记录「用户否决了什么」,而不是知识检索不够。
二、三种架构的真实取舍
方案 A:全量上下文(最朴素,也最容易被低估)
把历史全部塞进上下文。缺点是成本随轮次线性增长,长任务会爆 token。
但它的优点很硬:零检索误差。在 50 轮以内的任务里,它往往比任何 RAG 方案都准。
所以第一步不该是上向量库,而是先回答:这个任务真的需要跨会话记忆吗?如果只是单次任务,把窗口开大就够了。
方案 B:结构化情景记忆(我最推荐)
不存原文,存「结论 + 状态」。用一张简单的表或 JSON 文件:
import json
from datetime import datetime
class EpisodicMemory:
def __init__(self, path="./memory.json"):
self.path = path
try:
self.data = json.load(open(path, encoding="utf-8"))
except FileNotFoundError:
self.data = {"facts": [], "decisions": []}
def remember(self, kind, content, source="user"):
item = {"content": content, "source": source,
"ts": datetime.now().isoformat(timespec="seconds")}
self.data[kind].append(item)
json.dump(self.data, open(self.path, "w", encoding="utf-8"),
ensure_ascii=False, indent=2)
def recall(self, keyword=None, limit=10):
items = self.data["facts"] + self.data["decisions"]
if keyword:
items = [i for i in items if keyword in i["content"]]
return items[-limit:]
用法很直接:用户说「预算改成 30 万」,Agent 记一条 decision;下次涉及预算,先查 decisions,而不是去全文检索里翻旧对话。
关键设计:决策类信息必须带时间戳,并且允许覆盖。向量库做不到「这条作废」,结构化记录可以。
方案 C:压缩摘要(成本最低的折中)
每 N 轮把对话压缩成一段摘要,替换掉原始记录:
def compress(history, llm):
prompt = ("把下面的对话压缩成要点,保留:已确认的结论、被否决的方案、"
"未解决的问题。不要保留闲聊和重复内容。\n\n" + history)
return llm(prompt)
优点是省 token,缺点是有损。压缩掉的细节可能正是后面要用的。所以它适合「长周期、低精度要求」的陪伴型 Agent,不适合严谨任务。
三、我的组合方式
实际项目里我用的是分层:
- 工作记忆:当前任务放上下文,不额外存
- 情景记忆:结构化文件,只存结论和决策,带时间戳
- 知识记忆:文档走向量检索,只在需要查资料时调用
每次调用模型前拼三样东西:任务目标 + 最近的情景记忆 + 按需检索的知识片段。
这样做的效果是可解释的:Agent 说「预算 30 万」,你能立刻在 memory.json 里找到那条决策记录,而不是去猜它是从哪个文档片段里拼出来的。
四、三个容易踩的坑
1. 把所有东西都塞进向量库。
决策、偏好、否决记录放进向量库,检索时和文档混在一起,噪声极大。这类信息应该是结构化查询,不是语义检索。
2. 记忆没有时间维度。
「预算 50 万」和「预算 30 万」同时被检索出来,模型只能猜哪个新。必须带时间戳,并明确「后者覆盖前者」。
3. 不记录「否决」。
用户说「不要用 Kafka」,这句话比任何文档都重要。但它往往被当成闲聊丢掉,导致 Agent 下次又推荐一遍。
结语
Agent 的记忆问题,本质是信息组织问题,不是检索算法问题。
先想清楚你要记的是「原话」还是「结论」,再决定用向量库还是用一张表。多数情况下,一个带时间戳的 JSON 文件,比一套 RAG 流水线更能解决「它怎么又忘了」。
- 点赞
- 收藏
- 关注作者
评论(0)