AI Agent 的记忆系统怎么设计?从短期记忆到长期记忆,我踩过的 6 个坑
AI Agent 的记忆系统怎么设计?从短期记忆到长期记忆,我踩过的 6 个坑
适合正在开发 AI Agent、想让 Agent "记住"历史对话和用户偏好的开发者。
本文讲解 AI Agent 记忆系统的 3 层架构设计,附 Python 实现代码。
为什么 Agent 需要记忆
没有记忆的 AI Agent 就像一个每天失忆的人——你今天告诉它"我喜欢简洁的写作风格",明天它就忘了,又写一堆废话。
记忆系统解决的核心问题:
| 问题 | 没有记忆 | 有记忆 |
|---|---|---|
| 用户偏好 | 每次重新交代 | 自动记住 |
| 历史上下文 | 只看当前对话 | 能回忆过去 |
| 知识积累 | 每次从零开始 | 持续学习 |
| 个性化 | 千人一面 | 越用越懂你 |
记忆系统的 3 层架构
┌─────────────────────────────────────┐ │ 长期记忆(Long-term) │ 用户画像、偏好、历史知识 ├─────────────────────────────────────┤ │ 工作记忆(Working) │ 当前任务的上下文 ├─────────────────────────────────────┤ │ 感官记忆(Sensory) │ 最近几轮对话原文 └─────────────────────────────────────┘感官记忆:最近几轮对话
最简单的记忆,就是把最近 N 轮对话原文塞进 prompt。
classSensoryMemory:"""感官记忆:保存最近 N 轮对话"""def__init__(self,max_turns=10):self.history=[]self.max_turns=max_turnsdefadd(self,role,content):self.history.append({"role":role,"content":content})# 超过上限,删除最早的iflen(self.history)>self.max_turns*2:self.history=self.history[-self.max_turns*2:]defget_context(self):"""返回最近的对话历史"""returnself.historydefclear(self):self.history=[]问题:对话越来越长,token 超限。10 轮对话可能就占了 3000 token。
工作记忆:当前任务上下文
工作记忆保存当前正在做的事情的关键信息,不是对话原文,而是摘要。
classWorkingMemory:"""工作记忆:当前任务的关键信息摘要"""def__init__(self):self.summary=""self.current_task=""self.key_facts=[]defupdate(self,task,facts):"""更新工作记忆"""self.current_task=task self.key_facts=facts self.summary=f"当前任务:{task}\n关键信息:{', '.join(facts)}"defget_context(self):"""返回工作记忆上下文"""ifnotself.summary:return""returnf"[工作记忆]\n{self.summary}"defadd_fact(self,fact):"""添加一个关键信息"""iffactnotinself.key_facts:self.key_facts.append(fact)self.summary=f"当前任务:{self.current_task}\n关键信息:{', '.join(self.key_facts)}"长期记忆:用户画像和历史知识
长期记忆存在外部存储(数据库/文件),包含用户偏好、历史交互总结、学到的知识。
importjsonfrompathlibimportPathclassLongTermMemory:"""长期记忆:持久化存储用户画像和历史知识"""def__init__(self,storage_path="memory.json"):self.path=Path(storage_path)self.data=self._load()def_load(self):ifself.path.exists():returnjson.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")defadd_preference(self,key,value):"""记录用户偏好"""self.data["preferences"]=[pforpinself.data["preferences"]ifp["key"]!=key]self.data["preferences"].append({"key":key,"value":value})self._save()defadd_learned(self,knowledge):"""记录学到的知识"""ifknowledgenotinself.data["learned"]:self.data["learned"].append(knowledge)self._save()defget_context(self):"""返回长期记忆上下文"""parts=[]ifself.data["preferences"]:prefs=[f"{p['key']}:{p['value']}"forpinself.data["preferences"]]parts.append(f"[用户偏好]\n"+"\n".join(prefs))ifself.data["learned"]:parts.append(f"[历史知识]\n"+"\n".join(self.data["learned"][-10:]))# 最近 10 条return"\n\n".join(parts)3 层记忆组合使用
classAgentMemory:"""Agent 记忆系统:3 层组合"""def__init__(self):self.sensory=SensoryMemory(max_turns=10)self.working=WorkingMemory()self.long_term=LongTermMemory()defadd_turn(self,role,content):"""添加一轮对话"""self.sensory.add(role,content)defbuild_prompt(self,system_prompt):"""组装完整的 prompt,包含所有记忆层"""messages=[{"role":"system","content":system_prompt}]# 长期记忆(放在 system prompt 里)lt_ctx=self.long_term.get_context()iflt_ctx:messages[0]["content"]+=f"\n\n{lt_ctx}"# 工作记忆wk_ctx=self.working.get_context()ifwk_ctx:messages[0]["content"]+=f"\n\n{wk_ctx}"# 感官记忆(最近对话)messages.extend(self.sensory.get_context())returnmessagesdeflearn_from_conversation(self):"""从对话中提取值得记住的信息"""# 简化实现:让 LLM 总结对话中的关键信息recent=self.sensory.get_context()iflen(recent)<4:returnsummary_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 会超限。这时候需要压缩:把旧对话总结成摘要,只保留最近几轮原文。
defcompress_history(history,keep_recent=6):"""压缩对话历史:旧的总结成摘要,最近的保留原文"""iflen(history)<=keep_recent:returnhistory 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)returncompressed踩坑记录
坑 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 时遇到过记忆相关的问题吗?评论区交流。
