一、为什么 Agent 需要记忆?
没有记忆的 Agent,就像一条金鱼:你刚说完“我住在杭州”,下一轮它又问“您住在哪里?”。每次对话都从零开始,用户会疯掉。
记忆让 Agent 能做到三件事:
连续性:记住上次聊到哪,不用重复。
个性化:知道你的偏好、习惯、历史。
可积累:从成功和失败中学习,越用越聪明。
但“给 Agent 加记忆”远不是接一个向量数据库那么简单。下面我们从“存什么”讲到“怎么管”,再到“怎么不踩坑”。
二、记忆不是“一个向量库”那么简单
最常见的错误:把所有东西——对话、事实、偏好、工具输出——全扔进一个向量库,检索时 top-k 相似度一搜,塞给 LLM。
这就像把操作系统内存、硬盘、备份磁带全倒进一个文件夹,然后用 grep 搜索。能用,但很快会乱。
正确的做法是先分两个维度:
存什么(Memory Type)
怎么管(Memory Architecture)
2.1 存什么:四种记忆类型
类型 存什么 类比 例子
工作记忆 当前对话上下文 电脑内存 刚才用户说的“帮我订机票”
情景记忆 过去发生的事件 日记 “上周三用户问过退款流程”
语义记忆 事实、偏好、实体关系 档案卡 “用户偏好深色主题”
程序记忆 成功的执行模式 操作手册 “处理退款工单的步骤”
例子:个人助理 Agent。
工作记忆:当前对话窗口。
情景记忆:昨天用户让我订了去北京的机票。
语义记忆:用户住在杭州,喜欢靠窗座位。
程序记忆:订机票要先查航班,再确认时间,再支付。
把这四类全塞进同一个向量库,用同一套 top-k 检索,就是反模式。
2.2 怎么管:分层存储
生产级记忆系统通常分三层:
热存储:工作记忆 + 近期情景记忆。要求极低延迟,可用 SQLite + 向量扩展。
温存储:语义记忆、结构化用户画像。可用图数据库或关系库,支持复杂关联查询。
冷存储:全量历史归档。文件系统或对象存储,按需“水合”回热存储。
检索时采用置信度驱动的升级策略:先在热存储快速搜,置信度不够再查温存储,再不够查冷存储。不要一上来就全库扫描。
三、难题一:时间变了,事实冲突怎么办?
例子:用户 2023 年住北京,2025 年搬到杭州。Agent 之前存了“用户住北京”,现在用户说“我搬到杭州了”。
错误做法:直接 UPDATE,把“北京”覆盖成“杭州”。结果用户问“2023 年我住哪?”Agent 答“杭州”,错了。
正确做法:双时态建模。每个事实记录两个时间轴:
有效时间:事实在现实世界中为真的时段。比如“北京”有效时间是 2023-01-01 到 2025-01-01。
事务时间:系统记录这个事实的时间。
这样系统能区分“世界变了”和“我后来才知道”。
具体机制
软替代:新事实与旧事实矛盾时,不删除旧事实,而是把旧的标记为“已被替代”(invalid_at = 2025-01-01)。旧事实保留,供历史查询。
仲裁操作符:
SUPPORT:新证据支持旧事实。
REFINE:新证据是旧事实的细化。
SUPERSEDE:新事实取代旧事实,旧事实失效。
BRANCH-CONFLICT:矛盾且无法判定,标记待解决。
关键工程经验:检索交给 LLM,仲裁交给确定性代码。让 LLM 找相关候选,然后用 Python max(timestamp) 选最新版本。基准测试中,这能把单跳冲突解决准确率从约 54% 提升到 94.8%。
检索时:默认只返回 invalid_at IS NULL 的事实(当前有效)。问“2023 年”则做时间点查询,过滤 valid_at <= 2023-01-01 AND (invalid_at IS NULL OR invalid_at > 2023-01-01)。
四、难题二:Agent 怎么知道是不是事实?
Agent 本身不能“知道”真假。LLM 没有真值判断能力,它只会生成看起来合理的文本。所以工程上要做的是:不追求绝对真理,而是把每条信息当作“有来源、有置信度、有验证状态、有时间范围的信念”来管理。
4.1 先分类:不是所有信息都叫事实
类型 例子 处理方式
客观事实声明 “北京是中国的首都” 需外部验证
用户个人事实 “我住在杭州” 用户对自己有权威,但时间敏感
偏好/观点 “我喜欢深色主题” 以用户为准,存为偏好
指令/意图 “帮我订机票” 存为任务,不存为事实
假设/推断 “用户可能有孩子” 低置信度,需确认
工具输出 API 返回“汇率 7.2” 高置信但时效短,记录来源
LLM 生成摘要 “用户对退款不满” 必须附证据,否则不写入
只有“事实声明”和“用户个人事实”才进入事实候选池。
4.2 事实判定流程
来源归因:每条信息带来源——用户直接输入、工具返回、检索文档、LLM 推断。来源决定默认可信度。
声明提取:用 LLM 或规则拆成结构化声明:主语、谓语、宾语、时间、来源、证据片段。
置信度评分:综合来源权威性、明确性、可验证性、一致性、时效性,打 0~1 分。
验证策略:高风险事实(医疗、金融)必须调权威 API;可验证事实做 RAG 交叉验证;用户个人事实默认采信但标记可修正;偏好无需验证;LLM 推断默认低置信。
状态标记:candidate → verified → superseded / invalidated / disputed。写入默认 candidate,验证通过才升 verified。
冲突仲裁:新事实与旧事实矛盾时,触发 SUPPORT / REFINE / SUPERSEDE / BRANCH-CONFLICT。
4.3 一条事实的 Schema
json
{
"content": "用户住在杭州",
"source": "user_direct",
"source_type": "user_statement",
"confidence": 0.85,
"status": "verified",
"valid_at": "2025-01-01",
"invalid_at": null,
"evidence": "用户原话:我搬到杭州了",
"last_verified_at": "2025-01-01",
"verified_by": "user_authority"
}
检索时就能问:“当前有效的、高置信的、关于用户住址的事实是什么?”而不是简单 top-k 相似检索。
核心认知:不要问“LLM 怎么判断真假”,要问“系统如何管理信念的生命周期”。把事实判定从模型黑盒转移到确定性策略层。
五、难题三:回答问题如何检索事实?
例子:用户问“我现在住哪?”
错误做法:向量搜索“住哪”,返回一堆相关文本,塞给 LLM 让它自己判断。
正确做法:查当前有效的信念状态,并附上证据。流程如下:
查询解析:抽出实体=用户,关系=住址,as_of=now。若问“2023 年我住哪?”,则 as_of=2023-01-01。
多源路由:当前会话查工作记忆;用户长期事实查结构化事实库;实时数据查 API;可验证知识查 RAG。
候选召回:结构化查表 + 语义检索混合。SQL 示例:
sql
SELECT * FROM facts
WHERE subject='user' AND relation='residence'
AND valid_at <= :as_of
AND (invalid_at IS NULL OR invalid_at > :as_of)
AND status='verified'
AND confidence >= 0.7
ORDER BY source_authority DESC, valid_at DESC
LIMIT 1;
硬过滤:只保留 status=verified、valid_at <= as_of、invalid_at IS NULL OR invalid_at > as_of、来源可信、未过期的事实。
冲突仲裁:多个候选时,按来源权威 > 时间新近 > 置信度 > 用户确认 > 证据强度排序。无法裁决则标记 disputed,回答时说明冲突。
证据注入:把事实和证据一起给 LLM:
json
{
"fact": "用户住在杭州",
"valid_at": "2025-01-01",
"source": "用户原话:我搬到杭州了",
"confidence": 0.85,
"evidence_id": "evt_123"
}
要求 LLM 基于证据回答,并引用 [evt_123]。
生成与后处理:回答只使用检索到的事实,带引用。实时事实必须调工具。回答后把新确认信息写回,触发冲突检测。
完整例子:
问“我现在住哪?” → 过滤后返回杭州,答:“你现在住在杭州(你于 2025-01-01 提到搬到了杭州)。”
问“2023 年我住哪?” → as_of=2023-01-01,过滤后返回北京。
关键:检索事实 = 状态查询 + 证据检索,不是相似度检索。
六、开发中容易踩的坑
6.1 数据完整性与治理
覆盖式更新:直接 UPDATE 导致历史丢失。正确做法:旧值写 history,删除执行物理级联。
记忆漂移:无策展的记忆会把一次性错误固化成永久谎言。必须只将“成功”步骤提升为长期记忆。
检索偏差(富者愈富):常被检索的记忆不断刷新“新鲜度”,挤占其他记忆。近期性应按“最近被确认/更新”计算,只刷新真正被用到的记忆。
6.2 检索质量与上下文
上下文膨胀与“Lost in the Middle”:Top-K 记忆直接注入导致 Token 爆炸,中间信息被忽略。需 Token 预算守护和原子化召回。
单一向量检索局限:无法处理时间、状态、冲突。需混合检索(向量+BM25+元数据过滤)与图遍历结合,确定性仲裁。
Prompt Cache 冲突:记忆写入使 Prompt Cache 失效,增加延迟和成本。需批量写入、异步更新。
6.3 安全与隐私(重灾区)
记忆投毒(OWASP ASI06):工具输出(网页、API 响应)是投毒主要入口。攻击者植入恶意指令,被 Agent 当作“事实”存入长期记忆。必须在写入路径做来源验证和内容扫描。
多 Agent 虚假共识:一个 Agent 的错误值被其他 Agent 复制,系统显示“虚假同意”。需信任门和来源追踪,根据结果而非重复次数结算信任。
隐私泄露与合规:记忆可能在不同上下文间泄露敏感信息(如 API 密钥)。需 PII 检测,支持“被遗忘权”的物理级联删除。
6.4 架构与运维
拼凑式架构脆弱:向量库+Redis+PostgreSQL+胶水代码,缺乏统一生命周期管理。趋势是统一记忆操作系统或分层存储。
模型替换迁移成本:更换 Embedding 模型后历史向量需全部重建。需 Embedding 版本管理,或采用对模型替换更鲁棒的存储结构。
写入路径延迟税:每条消息触发 1-2 次模型调用做抽取/决策,增加用户等待。必须将记忆写入移出用户响应路径,放入后台异步队列按用户串行处理。
Agent 自产内容治理:Agent 自主编写 Skill 或反思洞察时,谁负责审计?无证据的反思不得写入记忆,核心记忆写入必须经过检查、审计和可回滚。
6.5 评估与可观测性
指标错位与基准饱和:仅看召回率不够,需关注 FAMA(遗忘感知记忆准确率)、更新传播、一致性。
缺乏系统级成本度量:需关注索引构建时间、查询延迟(p50/p95/p99)、每次操作 Token 成本。
可观测性缺失:监控每个用户的记忆条数、ADD/UPDATE/DELETE 比例、被检索比例,以及“用户纠正”次数(记忆质量最直接的信号)。
七、总结:核心权衡与设计原则
Agent Memory 的工程化,本质是从“功能实现”转向“数据治理与系统运维”。核心权衡:
权衡 说明
灵活 vs 纪律 Agent 自由写入 vs 严格写入检查与审计
性能 vs 安全 低延迟检索 vs 投毒防御与隐私合规
丰富 vs 成本 存储海量记忆 vs Token 成本与上下文窗口
记忆 vs 遗忘 记住一切 vs 受控遗忘与物理删除
设计原则:
记忆不是向量库,是认知基础设施。
事实不是真理,是可追溯、可修正、带置信度的信念。
检索不是搜相似,是查当前有效状态 + 证据。
时间冲突用双时态建模 + 软替代。
安全先行,写入路径和检索路径都要防御投毒。
从 MVP 开始,逐步加固,不要一开始就追求完美。
记住:Agent 的记忆系统,决定了它是一周后还在犯同样的错,还是越用越懂你。设计好了,它是资产;设计不好,它是负债。