news 2026/6/14 3:41:19

AI Agent 双层记忆系统:从理论到落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI Agent 双层记忆系统:从理论到落地

前言

做过 AI 对话应用的人都遇到过这个问题:用户昨天说"叫我小王",今天问"我是谁",模型一脸茫然。

这就是记忆系统要解决的核心问题。在 Deep Research 项目中,我设计了一套双层记忆架构——短期记忆负责当前对话上下文,长期记忆负责跨会话的用户画像与历史知识。本文完整记录设计思路与关键代码。

记忆模型

参考人脑记忆机制,将 AI 记忆分为三层:

层级类比职责生命周期后端
短期记忆工作记忆当前对话的上下文7天TTLRedis / PostgreSQL / 内存
长期-语义记忆百科知识用户画像、偏好、事实永久PostgreSQL / SQLite + Milvus
长期-情节记忆经历记忆历史任务、对话记录永久PostgreSQL / SQLite + Milvus

架构图

用户提问 │ ▼ MemoryManager.build_personalized_prompt_context() │ ├── 短期记忆(最近N条消息 + 对话摘要) ├── 长期语义记忆(Milvus向量检索 → 用户画像/偏好/事实) └── 长期情节记忆(Milvus向量检索 → 相似历史任务) │ ▼ 拼接为 [跨会话记忆] 注入 System Prompt │ ▼ Agent 处理后,persist_turn() 持久化本轮对话

短期记忆

存储结构

支持三种后端,根据环境自动选择:

def add_short_term_message(self, thread_id, message, user_id, tenant_id): payload = {"role": "human"|"ai", "content": "..."} if self.short_term_backend == "redis": key = f"ma:short:{tenant_id}:{user_id}:{thread_id}" self._redis_client.rpush(key, json.dumps(payload)) self._redis_client.expire(key, self.short_term_ttl) elif self.short_term_backend == "postgres": # INSERT INTO short_term_messages (id, tenant_id, user_id, thread_id, role, content, created_at) ... else: # 内存 dict self.short_term.add_message(thread_id, message)

摘要压缩

消息数量超阈值时自动触发 LLM 摘要压缩:

def _compress_pg_thread(self, tenant_id, user_id, thread_id): history = self._get_pg_short_term_messages(tenant_id, user_id, thread_id) if len(history) <= self.short_term_max_messages: return # 还没到阈值 ​ # 保留最近的消息,压缩旧消息 split_at = len(history) - self.short_term_summary_threshold to_summarize = history[:split_at] keep_messages = history[split_at:] ​ existing_summary = self._get_pg_short_term_summary(...) new_summary = self._summarize_text(existing_summary, to_summarize) ​ # 原子替换:删旧消息 + 保留新消息 + 更新摘要 DELETE ...; INSERT keep_messages; UPSERT summary

LLM 摘要 Prompt 设计:

def _summarize_text(self, existing_summary, history_slice): prompt = ( "你是对话压缩引擎。请在保留事实、偏好、结论、待办和约束的前提下进行递归摘要。\n" f"已有摘要:{existing_summary or '无'}\n" f"新增历史:\n{history_text}\n" "输出要求:100-300字,中文,结构紧凑。" ) response = self._summary_llm.invoke([HumanMessage(content=prompt)]) return str(response.content).strip()

关键点:摘要不是一次性生成,而是递归式——每次合并已有摘要 + 新增消息,类似 git rebase。

长期记忆

Milvus 向量检索

长期记忆的入口是向量检索。用户的提问 embedding 在 Milvus 中找最相似的历史记忆:

def _search_milvus(self, tenant_id, user_id, query, memory_type, limit=5): docs = self._milvus_store.similarity_search(query, k=max(limit * 4, 20)) entries = [] for doc in docs: metadata = doc.metadata or {} # 多租户过滤 if metadata.get("tenant_id") != tenant_id: continue if metadata.get("user_id") != user_id: continue # 类型过滤 if memory_type and metadata.get("memory_type") != memory_type: continue entries.append(MemoryEntry(...)) if len(entries) >= limit: break return entries

注意这里k = limit * 4——从 Milvus 多取一些,因为多租户和类型过滤会筛掉大量结果。如果只取 limit 个,过滤后可能一条不剩。

记忆保存

def save_fact(self, user_id, fact, category, tenant_id): memory_id = str(uuid4()) # 1. 写 PostgreSQL(结构化的元数据 + 全文搜索能力) self._insert_memory_pg(entry, summary=fact[:500]) ​ # 2. 写 Milvus(向量语义搜索) self._index_memory_milvus( text=fact, metadata={ "tenant_id": tenant_id, "user_id": user_id, "memory_id": memory_id, "memory_type": "semantic", "namespace": f"facts/{category}", }, ) return memory_id

PostgreSQL 和 Milvus双写:PG 支撑精确匹配和 ILIKE 模糊搜索,Milvus 支撑语义相似搜索。任一挂了不影响另一路。

自动记忆提取

persist_turn中检测用户是否触发了"记住我"意图:

def persist_turn(self, tenant_id, user_id, thread_id, query, answer): # 1. 保存短期记忆 self.add_short_term_messages(...) ​ # 2. 检测记忆触发词 remember_markers = ["记住", "我叫", "我的偏好", "remember", "my name is", ...] if any(marker in query.lower() for marker in remember_markers): extracted = extract_memory_from_messages([user_message]) # 提取 facts 和 preferences,分别存储 for fact in extracted["facts"]: self.save_fact(user_id, fact, category="user_fact") for pref in extracted["preferences"]: self.save_user_profile(user_id, {"preferences": [pref]}, merge=True)

上下文注入

每次用户提问前,build_personalized_prompt_context组装记忆上下文:

def build_personalized_prompt_context(self, user_id, thread_id, query, max_memories=8): context = self.get_context_for_agent(user_id, thread_id, query, max_memories) sections = [] if profile_text := context.get("user_profile"): sections.append(f"## 用户画像\n{profile_text}") if recent_text := context.get("recent_messages"): sections.append(f"## 最近对话\n{recent_text}") if summary_text := context.get("conversation_summary"): sections.append(f"## 对话摘要\n{summary_text}") if memory_text := context.get("memory_text"): sections.append(memory_text) return "\n\n".join(sections)

注入到每个节点的 prompt 中:

def with_memory_context(state, user_prompt): memory_context = state.get("memory_context", "").strip() if not memory_context: return user_prompt return f"{user_prompt}\n\n[跨会话记忆]\n{memory_context}"

追踪与调试

每次记忆注入后记录完整 trace,方便排查"为什么给我注入了这段记忆":

self._last_trace = { "query": query, "memory_count": len(memory_entries), "source_count": {"milvus": 3, "postgres": 1}, # 来自哪个检索源 "items": [ {"id": "xxx", "type": "semantic", "source": "milvus", "snippet": "..."}, ], "milvus_raw_hits": [...], # Milvus 原始命中(含被过滤的) "injected_chars": len(injected), }

用户输入/memory-trace即可查看最近一次的注入详情。

总结

  • 短期记忆:消息累积 + 递归 LLM 摘要压缩,多后端自动降级

  • 长期记忆:PG + Milvus 双写,向量检索为主、全文搜索兜底

  • 自动提取:触发词检测 + LLM 信息抽取,零手动标注

  • 可观测性:每次注入记录完整 trace,排错不靠猜

这个架构的可扩展性不错——如果想接入对话推荐、情感分析、知识图谱,只需要在新的 Agent 节点中读取memory_context即可。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 3:39:20

IR-UWB和FMCW雷达,谁才是智能家居和养老监护的“隐形守护神”?

IR-UWB与FMCW雷达&#xff1a;智能健康监护的技术博弈与场景化选择清晨六点&#xff0c;养老院的走廊还沉浸在静谧中。值班护士的手机突然收到一条预警&#xff1a;317房间的呼吸频率出现异常波动。这套基于毫米波雷达的监护系统&#xff0c;在老人毫无察觉的情况下完成了整夜的…

作者头像 李华
网站建设 2026/6/14 3:37:12

d2s-editor技术解析:暗黑破坏神2存档编辑器的架构设计与实用指南

d2s-editor技术解析&#xff1a;暗黑破坏神2存档编辑器的架构设计与实用指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor d2s-editor是一款基于Vue.js开发的暗黑破坏神2存档编辑器&#xff0c;通过可视化界面提供专业级的存档…

作者头像 李华
网站建设 2026/6/14 3:28:59

yolov26改进 | Neck/颈部创新篇 | 独创HFPN利用分层特征融合块HFFB模块融合多层次特征改进yolov26(全网独家创新)

一、本文介绍 本文给大家带来的最新改进是利用分层特征融合块HFFB创新yolov26的neck部分我称之为HFPN&#xff0c;这个模块可以融合局部特征、全局特征、中间特征将三种特征融合在一起辅助yolov26进行检测&#xff0c;经过我的设计分为三种可以针对大目标、小目标、标准目标的…

作者头像 李华
网站建设 2026/6/14 3:26:52

联想刃7000k BIOS隐藏选项终极解锁指南:释放硬件潜能的完整教程

联想刃7000k BIOS隐藏选项终极解锁指南&#xff1a;释放硬件潜能的完整教程 【免费下载链接】Lenovo-7000k-Unlock-BIOS Lenovo联想刃7000k2021-3060版解锁BIOS隐藏选项并提升为Admin权限 项目地址: https://gitcode.com/gh_mirrors/le/Lenovo-7000k-Unlock-BIOS 联想刃…

作者头像 李华