你有没有遇到过这种情况:和 AI 聊了很长的上下文之后,它突然”忘记”了前面说过的事情——不是因为它不聪明,而是因为它的记忆系统到达了物理上限。
记忆是 Agent 区别于普通 LLM 调用的核心能力之一。但”记忆”在工程上远比听起来复杂。
四种记忆类型
认知科学把人类记忆分为工作记忆、情节记忆、语义记忆等类型。AI Agent 的记忆系统有类似的分层:
1. In-context Memory(短期/工作记忆)
最基础的记忆形式——就是模型的上下文窗口(Context Window)。
- 容量:GPT-4 128K tokens,Claude 3.5 200K tokens,Gemini 1.5 Pro 1M tokens
- 速度:最快,直接参与推理
- 持久性:零,会话结束即消失
- 本质:把需要”记住”的内容全部塞进 prompt
这是 Agent 的默认记忆模式,也是最大的瓶颈所在。
2. External DB Memory(长期记忆)
把信息持久化到外部存储,需要时检索回来。
- 向量数据库(Pinecone、Weaviate、Chroma、Qdrant):语义检索
- 传统数据库(PostgreSQL、Redis):精确查询
- 文件系统:结构化文档存储
这是 RAG(Retrieval-Augmented Generation)的基础。
3. Episodic Memory(情节记忆)
记录”发生过什么”——具体的交互历史、任务执行轨迹。
类比人类:你不记得所有知识是怎么学到的,但你记得”上周我做了一个项目,遇到了这个问题,用这个方法解决了”。
Agent 的情节记忆通常存储:
- 过去的对话摘要
- 任务执行日志
- 错误和修复记录
4. Semantic Memory(语义记忆)
长期积累的知识和事实,不依附于具体情节。
类比人类:你知道”Python 的 GIL 是什么”,但你不记得是什么时候学的。
Agent 的语义记忆通常是:
- 微调进模型权重(最彻底,但昂贵)
- 知识库文档(通过 RAG 访问)
- 系统提示中的固定知识
上下文窗口:本质限制与压缩策略
即使是 1M tokens 的超长上下文,也有用完的一天。更实际的问题是:长上下文不仅有容量限制,还有推理质量下降的问题。
研究表明,当关键信息被埋在超长上下文的中间时,模型表现会显著变差(“Lost in the Middle”现象)。
常见压缩策略
滑动窗口(Sliding Window)
[系统提示] [最近 N 轮对话] → 超出部分直接丢弃
最简单粗暴。缺点:丢失的信息无法恢复。适合对话连贯性要求不高的场景。
摘要压缩(Summary Compression)
当上下文超过阈值时:
旧对话 → LLM 生成摘要 → 摘要替换原始对话
保留了语义信息,损失了细节。适合长对话的渐进式压缩。
重要性排序(Importance Ranking)
对上下文中的每段信息打分 → 保留高分内容 → 丢弃低分内容
可以基于规则(包含关键词)或模型评分。更精细,但计算开销大。
层级记忆(Hierarchical Memory)
工作记忆(最近 N 轮)
↓ 定期 consolidate
情节记忆(摘要 + 关键事件)
↓ 提炼
语义记忆(核心知识/偏好)
模拟人类记忆的自然层级。MemGPT 是这一思路的代表实现。
RAG:用向量数据库实现外部记忆
RAG(Retrieval-Augmented Generation)是当前最主流的 Agent 长期记忆方案。
工作原理
写入阶段(Indexing):
原始文档(PDF/网页/代码)
↓ 切片(Chunking)
文本块(512 tokens 左右)
↓ Embedding 模型
向量(1536 维浮点数组)
↓ 写入
向量数据库(存储向量 + 原始文本)
检索阶段(Retrieval):
用户查询:"Python 如何处理并发?"
↓ 同一 Embedding 模型
查询向量
↓ cosine similarity 计算
向量数据库返回 top-k 最相似文本块
↓ 注入上下文
[系统提示 + 检索到的文档 + 用户问题] → LLM
Embedding 的本质
Embedding 把文本映射到高维向量空间,语义相近的文本在向量空间中距离更近。
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('BAAI/bge-m3') # 支持中文的模型
texts = [
"Python 处理并发的方式",
"如何用 asyncio 写异步代码",
"今天天气真好"
]
embeddings = model.encode(texts)
# embeddings[0] 和 embeddings[1] 的余弦相似度会远高于和 embeddings[2]
Cosine similarity 公式:
similarity(A, B) = (A · B) / (|A| × |B|)
值域 [-1, 1],1 表示完全相同,0 表示无关,-1 表示相反。
记忆写入时机:何时 Consolidate
不是所有信息都值得存入长期记忆。关键决策点:
| 触发条件 | 写入内容 | 存储类型 |
|---|---|---|
| 用户明确说”记住这个” | 原始信息 | 情节/语义记忆 |
| 任务成功完成 | 执行摘要 + 关键决策 | 情节记忆 |
| 发现用户偏好/习惯 | 偏好描述 | 语义记忆 |
| 上下文窗口达到 70% | 旧对话摘要 | 情节记忆 |
| 遇到错误并修复 | 错误模式 + 修复方法 | 语义记忆 |
不应该写入:中间推理步骤、临时变量、冗余信息。
三种典型失败模式
失败模式 1:记忆爆炸(Memory Explosion)
症状:把所有东西都写进长期记忆,没有淘汰机制,检索结果越来越噪。
根本原因:缺少重要性评估和过期清理机制。
解决:设置 TTL(Time To Live),低相关度内容定期清理;写入时评估重要性得分。
失败模式 2:记忆遗忘(Memory Amnesia)
症状:明明存了信息,需要时却检索不到。
常见原因:
- Chunking 策略不当(上下文被切断在块边界)
- 查询和文档的 embedding 语义漂移(问法和存法不一致)
- top-k 值太小,相关内容排在 k 之后被截断
解决:调整 chunk 大小和重叠度;使用 HyDE(Hypothetical Document Embedding)增强查询;增大 top-k 后用 reranker 精选。
失败模式 3:记忆污染(Memory Poisoning)
症状:错误信息被存入记忆,后续推理被持续误导。
场景:Agent 执行失败但误判为成功,把错误结论写入记忆;用户故意输入误导信息。
解决:写入长期记忆前增加验证步骤;高风险信息标记置信度;支持记忆修正机制。
工程选型:本地 Embedding vs 云端 API
| 维度 | 本地(sentence-transformers) | 云端(OpenAI / 智谱 / 硅基流动) |
|---|---|---|
| 延迟 | 低(GPU 上 <10ms/chunk) | 高(网络 RTT + 排队,50–200ms) |
| 成本 | 一次性硬件投入 | 按 token 计费 |
| 隐私 | 完全本地,数据不出境 | 数据上传第三方 |
| 质量 | 中文:BGE-M3 ≈ OpenAI ada-002 | OpenAI text-embedding-3-large 最强 |
| 维护 | 需要自己管理模型更新 | 零维护 |
推荐组合:
- 隐私敏感 / 本地部署:
BAAI/bge-m3+ Qdrant(本地 Docker) - 快速原型 / 质量优先:OpenAI
text-embedding-3-small+ Pinecone - 中文场景 + 性价比:智谱 embedding-3 + Chroma
# 本地方案示例
from sentence_transformers import SentenceTransformer
import chromadb
model = SentenceTransformer('BAAI/bge-m3')
client = chromadb.Client()
collection = client.create_collection("agent_memory")
def remember(text: str, metadata: dict):
embedding = model.encode(text).tolist()
collection.add(
documents=[text],
embeddings=[embedding],
metadatas=[metadata],
ids=[f"mem_{hash(text)}"]
)
def recall(query: str, top_k: int = 5) -> list[str]:
query_embedding = model.encode(query).tolist()
results = collection.query(
query_embeddings=[query_embedding],
n_results=top_k
)
return results['documents'][0]
总结
Agent 的记忆系统是一个工程问题,不只是 API 调用问题。设计时需要回答:
- 哪些信息需要长期保存?(重要性评估)
- 如何在需要时找到它?(检索策略)
- 如何防止记忆腐烂和污染?(生命周期管理)
没有完美的记忆系统,只有适合当前任务的记忆系统。从最简单的滑动窗口开始,按需增加复杂度——这是最务实的工程路径。