AI Agent 的记忆系统怎么设计?从短期记忆到长期记忆,我踩过的 6 个坑
AI Agent 的记忆系统怎么设计?从短期记忆到长期记忆,我踩过的 6 个坑
适合正在开发 AI Agent、想让 Agent "记住"历史对话和用户偏好的开发者。
本文讲解 AI Agent 记忆系统的 3 层架构设计,附 Python 实现代码。
为什么 Agent 需要记忆
没有记忆的 AI Agent 就像一个每天失忆的人——你今天告诉它"我喜欢简洁的写作风格",明天它就忘了,又写一堆废话。
记忆系统解决的核心问题:
| 问题 | 没有记忆 | 有记忆 |
|---|---|---|
| 用户偏好 | 每次重新交代 | 自动记住 |
| 历史上下文 | 只看当前对话 | 能回忆过去 |
| 知识积累 | 每次从零开始 | 持续学习 |
| 个性化 | 千人一面 | 越用越懂你 |
记忆系统的 3 层架构
┌─────────────────────────────────────┐
│ 长期记忆(Long-term) │ 用户画像、偏好、历史知识
├─────────────────────────────────────┤
│ 工作记忆(Working) │ 当前任务的上下文
├─────────────────────────────────────┤
│ 感官记忆(Sensory) │ 最近几轮对话原文
└─────────────────────────────────────┘
感官记忆:最近几轮对话
最简单的记忆,就是把最近 N 轮对话原文塞进 prompt。
class SensoryMemory:
"""感官记忆:保存最近 N 轮对话"""
def __init__(self, max_turns=10):
self.history = []
self.max_turns = max_turns
def add(self, role, content):
self.history.append({"role": role, "content": content})
# 超过上限,删除最早的
if len(self.history) > self.max_turns * 2:
self.history = self.history[-self.max_turns * 2:]
def get_context(self):
"""返回最近的对话历史"""
return self.history
def clear(self):
self.history = []
问题:对话越来越长,token 超限。10 轮对话可能就占了 3000 token。
工作记忆:当前任务上下文
工作记忆保存当前正在做的事情的关键信息,不是对话原文,而是摘要。
class WorkingMemory:
"""工作记忆:当前任务的关键信息摘要"""
def __init__(self):
self.summary = ""
self.current_task = ""
self.key_facts = []
def update(self, task, facts):
"""更新工作记忆"""
self.current_task = task
self.key_facts = facts
self.summary = f"当前任务: {task}\n关键信息: {', '.join(facts)}"
def get_context(self):
"""返回工作记忆上下文"""
if not self.summary:
return ""
return f"[工作记忆]\n{self.summary}"
def add_fact(self, fact):
"""添加一个关键信息"""
if fact not in self.key_facts:
self.key_facts.append(fact)
self.summary = f"当前任务: {self.current_task}\n关键信息: {', '.join(self.key_facts)}"
长期记忆:用户画像和历史知识
长期记忆存在外部存储(数据库/文件),包含用户偏好、历史交互总结、学到的知识。
import json
from pathlib import Path
class LongTermMemory:
"""长期记忆:持久化存储用户画像和历史知识"""
def __init__(self, storage_path="memory.json"):
self.path = Path(storage_path)
self.data = self._load()
def _load(self):
if self.path.exists():
return json.loads(self.path.read_text(encoding="utf-8"))
return {"user_profile": {}, "preferences": [], "learned": []}
def _save(self):
self.path.write_text(json.dumps(self.data, ensure_ascii=False, indent=2), encoding="utf-8")
def add_preference(self, key, value):
"""记录用户偏好"""
self.data["preferences"] = [p for p in self.data["preferences"] if p["key"] != key]
self.data["preferences"].append({"key": key, "value": value})
self._save()
def add_learned(self, knowledge):
"""记录学到的知识"""
if knowledge not in self.data["learned"]:
self.data["learned"].append(knowledge)
self._save()
def get_context(self):
"""返回长期记忆上下文"""
parts = []
if self.data["preferences"]:
prefs = [f"{p['key']}: {p['value']}" for p in self.data["preferences"]]
parts.append(f"[用户偏好]\n" + "\n".join(prefs))
if self.data["learned"]:
parts.append(f"[历史知识]\n" + "\n".join(self.data["learned"][-10:])) # 最近 10 条
return "\n\n".join(parts)
3 层记忆组合使用
class AgentMemory:
"""Agent 记忆系统:3 层组合"""
def __init__(self):
self.sensory = SensoryMemory(max_turns=10)
self.working = WorkingMemory()
self.long_term = LongTermMemory()
def add_turn(self, role, content):
"""添加一轮对话"""
self.sensory.add(role, content)
def build_prompt(self, system_prompt):
"""组装完整的 prompt,包含所有记忆层"""
messages = [{"role": "system", "content": system_prompt}]
# 长期记忆(放在 system prompt 里)
lt_ctx = self.long_term.get_context()
if lt_ctx:
messages[0]["content"] += f"\n\n{lt_ctx}"
# 工作记忆
wk_ctx = self.working.get_context()
if wk_ctx:
messages[0]["content"] += f"\n\n{wk_ctx}"
# 感官记忆(最近对话)
messages.extend(self.sensory.get_context())
return messages
def learn_from_conversation(self):
"""从对话中提取值得记住的信息"""
# 简化实现:让 LLM 总结对话中的关键信息
recent = self.sensory.get_context()
if len(recent) < 4:
return
summary_prompt = f"""从以下对话中提取值得长期记住的信息(用户偏好、关键知识)。
只输出 JSON 格式:
{{"preferences": [{{"key": "xxx", "value": "xxx"}}], "learned": ["xxx"]}}
对话:
{json.dumps(recent[-6:], ensure_ascii=False)}"""
# 调用 LLM 提取(这里简化处理)
# result = local_chat(summary_prompt)
# parsed = json.loads(result)
# for p in parsed.get("preferences", []):
# self.long_term.add_preference(p["key"], p["value"])
pass
使用示例
# 初始化
memory = AgentMemory()
# 模拟对话
memory.add_turn("user", "帮我写一篇关于 Python 的文章,风格要口语化")
memory.add_turn("assistant", "好的,我来写一篇口语化的 Python 文章...")
memory.add_turn("user", "不错,但代码注释太少了")
memory.add_turn("assistant", "明白了,以后代码我会加更多注释")
# 记住用户偏好
memory.long_term.add_preference("写作风格", "口语化")
memory.long_term.add_preference("代码要求", "需要详细注释")
# 下次对话时,Agent 自动知道用户的偏好
messages = memory.build_prompt("你是一个技术写作助手")
# messages 会包含:[系统提示 + 用户偏好 + 工作记忆 + 最近对话]
记忆压缩:对话太长怎么办
对话超过 20 轮后,token 会超限。这时候需要压缩:把旧对话总结成摘要,只保留最近几轮原文。
def compress_history(history, keep_recent=6):
"""压缩对话历史:旧的总结成摘要,最近的保留原文"""
if len(history) <= keep_recent:
return history
old = history[:-keep_recent]
recent = history[-keep_recent:]
# 让 LLM 总结旧对话
old_text = json.dumps(old, ensure_ascii=False)
summary_prompt = f"用 100 字总结这段对话的要点:\n{old_text}"
summary = local_chat(summary_prompt)
# 用摘要替代旧对话
compressed = [{"role": "system", "content": f"[历史摘要] {summary}"}]
compressed.extend(recent)
return compressed
踩坑记录
坑 1:记忆太多,prompt 超限
症状:长期记忆存了几百条,全部塞进 prompt 直接超 token 限制。
原因:没有限制记忆的长度。
解决:长期记忆只取最近 10 条,偏好只取 top 5 最重要的。
坑 2:记忆过时
症状:用户 3 个月前说"我喜欢蓝色",现在说"我喜欢红色",Agent 还是推荐蓝色。
原因:旧偏好没有被更新,新旧共存。
解决:偏好用 key-value 结构,同 key 的自动覆盖旧值。
坑 3:记忆冲突
症状:用户说"我喜欢简洁",但后来又说"这篇文章太短了,要详细点"。两个偏好矛盾。
原因:没有冲突检测和解决机制。
解决:新偏好优先。或者在 prompt 里告诉 Agent"如果偏好有冲突,以最新的为准"。
坑 4:从对话中自动提取记忆不准
症状:让 LLM 自动总结对话中的关键信息,经常提取错误或者遗漏。
原因:LLM 的总结能力有限,尤其是长对话。
解决:不要完全自动,关键偏好让用户手动确认。或者用更简单的规则提取(正则匹配关键词)。
坑 5:隐私问题
症状:Agent 记住了用户的敏感信息(手机号、地址),存在文件里不安全。
原因:没有做敏感信息过滤。
解决:提取记忆时加一层过滤,手机号、身份证号等不存入长期记忆。
坑 6:多用户记忆混淆
症状:同一个 Agent 服务多个用户,把 A 的偏好用在了 B 身上。
原因:记忆没有按用户隔离。
解决:每个用户一个独立的记忆文件/数据库,按 user_id 隔离。
总结
3 条核心经验:
-
3 层记忆各司其职。感官记忆管最近对话,工作记忆管当前任务,长期记忆管用户画像。不要混在一起。
-
记忆要压缩。对话超过 20 轮就总结旧的,只保留最近几轮原文。否则 token 会爆。
-
新偏好覆盖旧偏好。用户今天说的比 3 个月前说的更重要。用 key-value 结构自动覆盖。
你在开发 AI Agent 时遇到过记忆相关的问题吗?评论区交流。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)