人没有记忆就是金鱼------每次醒来都不记得昨天发生了什么。Agent 也一样,没有记忆的 Agent 只是个「单次对话工具」。要让 AI 助手真正有用,它必须能跨会话记住你是谁、你做过什么、你喜欢什么。这就是记忆系统的价值。
📑 目录
- [为什么 Agent 需要记忆](#为什么 Agent 需要记忆)
- 短期记忆:当前对话上下文
- 长期记忆:跨会话的知识积累
- 向量记忆:语义检索的记忆库
- 记忆总结:防止记忆爆炸
- 记忆系统架构实战
为什么 Agent 需要记忆
没有记忆的 Agent 对话:
Day 1:
用户:我叫小明,用 Python 开发
Agent:好的小明!(忘了)
Day 2:
用户:你还记得我吗?
Agent:抱歉,我没有之前对话的记忆... 😑
Day 30:
用户:我上次让你帮忙看的那个 Bug 修复了吗?
Agent:我不清楚您指的是什么问题... 😵
→ 每次都是陌生人模式,用户体验极差
有记忆的 Agent:
Day 1:
用户:我叫小明,用 Python 开发
Agent:(存入记忆)记住了,小明!Python 开发者~
Day 2:
用户:你还记得我吗?
Agent:(检索记忆)当然!你是小明,Python 开发者。最近怎么样?😊
Day 30:
用户:我上次让你帮忙看的 Bug?
Agent:(检索记忆)你说的是上周那个 Pandas 性能问题吧?
我已经记录了进展状态... 📝
→ 像老朋友一样,越用越懂你
短期记忆:当前对话上下文
一句话定义
当前会话中的消息历史缓冲区。Agent 在本轮对话中能看到的所有过往交互内容。
python
class ShortTermMemory:
"""滑动窗口式的短期记忆"""
def __init__(self, max_turns=10, max_tokens=8000):
self.messages = [] # [{role, content}, ...]
self.max_turns = max_turns
self.max_tokens = max_tokens
def add(self, role, content):
self.messages.append({"role": role, "content": content})
self._trim() # 超出限制时裁剪
def _trim(self):
"""优先保留 System Prompt 和最近的对话"""
while (len(self.messages) > self.max_turns * 2 or
self.token_count() > self.max_tokens):
# 保留 system,移除最早的 user/assistant
for i, msg in enumerate(self.messages):
if msg["role"] in ("user", "assistant"):
self.messages.pop(i)
break
def get_context(self) -> list:
return self.messages.copy()
短期记忆的关键参数
| 参数 | 推荐值 | 说明 |
|---|---|---|
| max_turns | 5-20 轮 | 太少丢失上下文,太多浪费 Token |
| max_tokens | 4000-8000 | 根据模型窗口大小调整 |
| system_prompt 占比 | <20% | System 过大会挤压有效空间 |
长期记忆:跨会话的知识积累
一句话定义
持久化存储的用户画像、偏好、重要事件和历史交互摘要。即使服务重启、会话过期,这些信息也不会丢失。
长期记忆存储的内容类型
| 类型 | 示例 | 更新频率 |
|---|---|---|
| 用户画像 | 姓名、职业、技术栈、沟通风格 | 初次建立,偶尔更新 |
| 偏好设置 | 回答语言、详细程度、格式要求 | 随时更新 |
| 重要事件 | 项目节点、关键决定、里程碑 | 发生时记录 |
| 知识积累 | 学到的业务规则、领域知识 | 逐步积累 |
| 待办追踪 | 未完成任务、后续跟进项 | 动态变化 |
向量记忆:语义检索的记忆库
一句话定义
把每条记忆文本转为向量存入向量数据库,当需要回忆时通过语义相似度检索最相关的记忆片段。不是「翻遍所有聊天记录」,而是「智能联想」。
python
import numpy as np
class VectorMemory:
def __init__(self, vector_store, embed_fn):
self.store = vector_store
self.embed = embed_fn
def save(self, text, metadata={}, importance=0.5):
"""保存一条记忆"""
embedding = self.embed(text)
self.store.add({
"embedding": embedding,
"text": text,
"metadata": {**metadata, "timestamp": now(), "importance": importance}
})
def recall(self, query, top_k=5, min_score=0.3):
"""根据当前上下文召回相关记忆"""
q_vec = self.embed(query)
results = self.store.search(q_vec, top_k=top_k * 2) # 多取一些用于过滤
# 过滤低相关性结果
return [r for r in results if r.score >= min_score][:top_k]
# 使用示例
memory = VectorMemory(chroma_client, get_embedding)
memory.save("用户喜欢简洁的回答,不要太啰嗦",
{"type": "preference", "user_id": "user_001"}, importance=0.8)
memory.save("项目使用 Python + FastAPI 技术栈",
{"type": "project_info"}, importance=0.9)
# 当新对话开始时,自动召回相关记忆
relevant_memories = memory.recall("用户问了一个 Python 问题")
for mem in relevant_memories:
print(mem.text) # 自动关联到相关记忆
记忆总结:防止记忆爆炸
一句话定义
随着对话量增长,原始记忆会无限膨胀。记忆总结就是定期将大量旧记忆压缩为精炼的摘要,在保留关键信息的同时控制存储成本。
记忆膨胀问题:
第1天:3 条记忆
第30天:150 条记忆
第90天:2000 条记忆 ← 检索变慢,噪音增加
第365天:50000 条记忆 ← 已经不可用了!
解决方案:分层总结
Level 0(原始):最近 7 天的所有交互细节
Level 1(周报):每周总结为 ~10 条要点
Level 2(月报):每月总结为 ~5 条关键事件
Level 3(画像):最终沉淀为用户画像的核心属性
效果:无论用了多久,实际检索的始终是精炼过的摘要
python
def summarize_memories(raw_memories, summary_level="weekly"):
"""用 LLM 总结记忆"""
prompt = f"""以下是一段时间内的记忆记录,请总结为{summary_level}级别的摘要:
只保留重要的信息:用户偏好、关键事件、重要决定、学到的知识。
忽略闲聊、临时性问答。
记忆记录:
{chr(10).join([m.text for m in raw_memories])}
请输出结构化的摘要。"""
summary = llm.generate(prompt)
return summary
❌ 常见误区
- ❌ 记忆越多越好 --- 噪音记忆导致「记忆混淆」,定期清理和总结很重要
- ❌ 所有对话都值得记住 --- 闲聊、一次性问答不需要存入长期记忆
- ❌ 向量记忆不需要维护 --- Embedding 模型漂移、用户偏好变化都需要定期刷新