尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
AI Agent 工程实践(10):Memory 不只是聊天记录——长期记忆架构设计
发布时间2026-07-12标签AI AgentLLMMemory向量数据库架构设计工程实现系列导航上一篇AI Agent 工程实践09AI Engineering OS v2——系统如何持续演化下一篇AI Agent 工程实践11Workflow——Agent 如何完成复杂任务本文是 [AI Agent 工程实践] 系列的第 10 篇第二季 · 工程实现。第 03 篇讲清楚了一件事记忆必须分层。Conversation → Working → Long → Archive单向流动定期回收。但讲完那篇后我开始动工实现立刻撞上一个问题长期记忆到底怎么存、怎么检索我把所有东西塞进一个 JSON 文件。10MB 以后查一次要 3 秒。换成向量数据库结果召回了半年前随口聊的天气却没召回上个月的关键架构决策。我终于意识到存对话 ≠ 有记忆检索 ≠ 理解。Memory 的问题从来不在存得下而在找得到对的东西。第 03 篇解决记什么这一篇解决怎么记、怎么找。从架构到落地。本文你将学到✓ 长期记忆的四种分类Working / Episodic / Semantic / Procedural✓ Memory Store 的双通道设计结构化过滤 语义检索✓ Memory Manager 的完整架构User → Conversation → Memory Manager → Vector DB✓ 三大核心流程写入怎么存→ 检索怎么找→ 蒸馏怎么压适合阅读✓ 读完了第 03 篇、想把 Memory 真正实现出来的开发者✓ 在选型向量数据库Chroma/Milvus/Pinecone做 Agent Memory 的人✓ 被检索噪声召回不准困扰的人问题背景第 03 篇 定义了四层记忆和生命周期。但那篇是设计层——它回答该记什么、记多久。到实现层问题变成了怎么存、怎么找。市面上的Agent Memory方案基本是两种极端一端是全存数据库。把所有对话存 PostgreSQL按时间倒序取最近 N 条。问题很明显关键记忆是语义相关不是时间相关——昨天关于代码规范的决定比今天早上的寒暄重要 100 倍。按时间检索等于在倒垃圾。另一端是纯向量检索。把所有内容 embed 成向量塞进 Chroma搜什么就返回相似的 top-K。问题是语义相似 ≠ 记忆相关。用户喜欢简洁风格和用户今天说要简洁语义高度相似但前者是长期偏好要记住后者是一次性对话该丢弃。纯向量检索分不出这两者。两种方案的共同缺陷没有对记忆本身做分类没有对检索做分层。于是长期记忆变成了一个 dump——什么东西都往里扔搜全靠运气。错误尝试第一次全存 Markdown 文件按日期索引最原始的做法——一个memory/目录按日期存 markdown要查什么就全文搜索。结果10MB 以后搜索变慢。更致命的是它只能做字面匹配。数据库设计搜不到Schema 定义代码风格搜不到命名规范。记忆不是日志字面搜索等于没有搜索。第二次纯向量检索靠相似度召回把每条记忆 embed 成向量搜的时候语义匹配返回 top-10。结果一时对话回来了长期偏好也回来了噪声也回来了。用户喜欢 Test-Driven Development和用户问 TDD 是什么向量距离极近但前者是长期偏好该记后者是一次性问答该丢。语义相似掩盖了记忆类型差异——向量检索看不出该不该记只看出字面像不像。两次尝试指向同一个教训Memory 的检索不能只有一个通道。它需要结构化过滤筛掉不该记的再叠加语义检索找到该找的。先分类型再谈检索。关键观察我把每次真正被用到的记忆和其存储特征做了对照记忆类型例子检索触发特征应该用什么检索Working当前任务报错信息当前会话不检索直接注入Episodic情节上周三修过一个类似 bug时间范围 关键词结构化过滤 语义Semantic语义本项目用 FastAPI概念匹配语义检索为主Procedural流程部署前先跑 pre-commit任务类型触发结构化过滤tag/scopepie title 纯向量检索的召回质量问题 真正相关 : 25 语义相似但类型不匹配 : 40 完全不相关噪声 : 35存对话 ≠ 有记忆检索 ≠ 理解。一段对话存进数据库叫日志一段对话被正确分类、能在正确时机被召回才叫记忆。差距不在存储在分类和检索策略。定位真正原因现有方案的共同缺陷把存储和检索当成一个平面操作——什么类型的记忆都存进同一个空间、用同一种方式搜。正确架构应该先分层第 03 篇已定义再给每层设计对应的存储策略和检索策略。于是 Memory 的实现问题拆成三个子问题怎么分类——每条记忆属于什么类型Episodic/Semantic/Procedural怎么存——不同类型走不同的存储路径结构化字段 向量双写怎么检索——先结构化过滤缩小范围再语义检索精准命中这正是 Memory Manager 要做的事。最终方案Memory 分类体系 Memory Manager 架构Memory 四种分类03 篇按生命周期分层10 篇按内容性质分类——两层互补不矛盾分类是什么例子存储策略Working Memory当前任务上下文正在改的文件、当前报错不落盘会话级注入Episodic Memory具体事件/经历上周三修过一个 async bug结构化时间/tag 向量Semantic Memory抽象知识/事实本项目用 FastAPI 和 asyncpg向量为主结构化 scopeProcedural Memory流程/方法部署前先跑 pre-commit结构化trigger/task_type关键不是所有记忆都该进向量库。Procedural 靠 trigger 触发就行不需要语义检索Episodic 需要时间范围 关键词 语义三管齐下Semantic 语义检索为主但要有 scope 过滤区分项目/用户。Memory Store双通道存储每条记忆入库时同时写两个通道# 一条记忆的存储结构 id: mem_20260712_001 type: semantic # 分类标签 → 用于结构化过滤 scope: project # user / project → 用于隔离 content: 本项目使用 FastAPI asyncpg 作为后端栈 embedding: [0.12, -0.34, ...] # 向量 → 用于语义检索 metadata: created_at: 2026-07-12T10:00:00 last_hit: 2026-07-12T14:00:00 hit_count: 5 # 命中次数 → 用于蒸馏/优先级 source: conversation # 来源 → conversation / user_explicit双通道意味着检索时先走结构化过滤typesemantic AND scopeproject缩小候选集再走向量语义匹配。过滤砍掉噪声语义找到精准。Memory Manager 架构这是你给的核心链路——User → Conversation → Memory Manager → Vector DBMemory Manager 的三大流程写入流程会话结束时Conversation 的内容被蒸馏——提取出可能值得长期记的信息分类器判断类型Episodic/Semantic/Procedural双写结构化字段进 PostgreSQLembedding 进向量库检索流程Agent 需要记忆时先构造检索条件typesemantic, scopeproject结构化过滤——缩小候选集语义匹配——在候选集里找最相关的 top-K蒸馏流程定期周复盘检查每条记忆的hit_count和last_hit长期未命中 → 降级到 Archive03 篇定义语义重复 → 合并保留更新版本实际收益指标全量向量检索Memory Manager过滤检索检索精度~25%噪声多显著提升先过滤召回速度慢全库扫快候选集小噪声来源类型不匹配过期基本消除过滤蒸馏为主观估算非严格 A/B Test但反映了双通道对检索质量的结构性改善。代码或配置示例Memory Store 表结构PostgreSQL 端-- 存储记忆元数据和结构化字段 CREATE TABLE memory_store ( id TEXT PRIMARY KEY, type TEXT NOT NULL, -- episodic / semantic / procedural scope TEXT NOT NULL, -- user / project content TEXT NOT NULL, tags TEXT[], -- 结构化标签 [fastapi, backend] hit_count INT DEFAULT 0, last_hit TIMESTAMP, created_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_type_scope ON memory_store(type, scope); CREATE INDEX idx_tags ON memory_store USING GIN(tags);Memory Manager 核心逻辑伪代码class MemoryManager: def __init__(self, pg_store, vector_store): self.pg pg_store # 结构化存储 self.vec vector_store # 向量存储 def write(self, memory: Memory) - None: 写入分类 → 双写 memory.type self.classifier.classify(memory.content) # 双通道写入 pg_id self.pg.insert(memory.to_metadata()) self.vec.insert(idpg_id, embeddingembed(memory.content)) def retrieve(self, query: str, filters: dict, top_k: int 5) - list: 检索先过滤 → 再语义 # 1. 结构化过滤缩小候选集 candidates self.pg.filter( typefilters.get(type), scopefilters.get(scope), tagsfilters.get(tags), time_rangefilters.get(time_range), ) # 2. 语义检索在候选集内匹配 query_vec embed(query) results self.vec.search(query_vec, idscandidates.ids, top_ktop_k) # 3. 更新命中统计 for r in results: self.pg.increment_hit(r.id) return results def distill(self, stale_days: int 30) - None: 蒸馏清理过期 合并重复 stale self.pg.get_stale(daysstale_days) for m in stale: self.archive.move(m) # 长期未命中 → 归档 self.pg.merge_duplicates() # 语义重复 → 合并三段代码拼起来就是 Memory Manager 的全部核心逻辑写的时候双通道分发查的时候先过滤后语义维护的时候按命中率蒸馏。设计权衡候选方案优点缺点为什么不选纯关系型数据库结构化查询强无语义检索只能字面匹配记忆是语义场景字面匹配遗漏率太高纯向量数据库语义检索强噪声多、无结构化过滤语义相似掩盖类型差异召回质量崩双通道PG Vector DB过滤精准语义灵活需维护两套存储选择理由先过滤再检索唯一兼顾准和全的方案双通道不是银弹。如果记忆量很小100 条一个 JSON 文件加全文搜索就够。双通道的价值在记忆量大、类型多时——过滤层缩减候选集语义层精准命中。和第 08 篇一样规模不到别过度设计。总结✅ 第 03 篇解决记什么本篇解决怎么存怎么检索——Memory 的实现依赖于正确分类和检索策略。✅ Memory 分四种Working不落盘/ Episodic事件/ Semantic知识/ Procedural流程各自有不同的存储和检索策略。✅ Memory Store 双通道PostgreSQL 管结构化过滤type/scope/tagVector DB 管语义检索先过滤再检索。✅ Memory Manager 三大流程写入分类→双写→ 检索过滤→语义→ 蒸馏命中率清理。✅ 架构链路User → Conversation → Memory Manager分类/检索/蒸馏→ Memory Store双通道→ Agent。参考资料第 03 篇Memory 设计——Agent 到底应该记住什么→ 记忆四层/生命周期本篇的记什么前置MemGPT: Towards LLMs as Operating Systems→ 分层记忆 分页调度本文分类体系的学术参照Chroma / Milvus 官方文档→ 向量数据库选型与检索策略参考Generative Agents (Park et al., 2023)→ Memory Stream 检索/反思机制蒸馏逻辑的来源系列导航上一篇AI Agent 工程实践09AI Engineering OS v2——系统如何持续演化下一篇AI Agent 工程实践11Workflow——Agent 如何完成复杂任务本文是 [AI Agent 工程实践] 系列的第 10 篇第二季 · 工程实现。
RELATED

相关推荐

AutoCAD 2026安装失败原因与三阶段可信链实操指南

AutoCAD 2026安装失败原因与三阶段可信链实操指南

1. 这不是“点下一步就行”的安装,而是让AutoCAD 2026真正在你电脑上稳稳扎根的实操指南AutoCAD 2026刚发布那会儿,我收到不下二十条私信:“装完了打不开”“卡在初始化界面不动”“提示缺少.NET组件但明明装了最新版”“管理员权限也给了&am…

📅 2026/9/5 2:13:20
Vue3中hooks详解

Vue3中hooks详解

Vue3中hooks详解一、 核心概念1. 什么是 Composable?2. 为什么需要它?二、 基本结构与规范三、 常见应用场景与示例1. 鼠标位置追踪 (useMouse)2. 网络请求封装 (useFetch)3. 本地存储同步 (useLocalStorage)四、 最佳实践与注意事项五、 总结在 Vue 3 中…

📅 2026/9/6 1:04:50
RSA私钥过短的安全隐患:维纳攻击原理与Python实现详解

RSA私钥过短的安全隐患:维纳攻击原理与Python实现详解

1. 项目概述:当RSA的私钥“太短”时会发生什么?如果你接触过密码学或者CTF比赛,一定对RSA不陌生。它作为非对称加密的基石,其安全性建立在大数分解的困难性上。但很多人可能不知道,RSA的安全性不仅依赖于大素数p和q的保…

📅 2026/9/5 23:44:16
MORE NEWS

更多资讯

📰

VSCode MCP Server配置指南:解决Windows下error -32000 Connection closed

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

【滚雪球学数学建模】第26节·建模论文与模型复现

🎓 本文收录于《滚雪球学数学建模》系列专栏 数学建模真正的难点,往往不在于掌握某一个公式或算法,而在于面对实际问题时,能否完成从 问题分析 → 模型构建 → 算法求解 → 结果验证 → 论文表达 的完整闭环。 本专栏正是围绕这一目标打造:从零基础出发,通过“滚雪球式”…

📰

幼儿园礼仪教育:3-6岁关键期的习惯养成与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

配电网N-1扩展规划Matlab实现:从校验到优化决策

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Element Plus Menu 导航菜单组件完全指南:水平/垂直模式、折叠与完整 API 详解

Element Plus Menu 导航菜单组件完全指南:水平/垂直模式、折叠与完整 API 详解 【免费下载链接】element-plus 🎉 A Vue.js 3 UI Library made by Element team 项目地址: https://gitcode.com/GitHub_Trending/el/element-plus Menu 是 Element …

📰

Claude Code 如何用 claude ultrareview 做非交互式 PR 审查?claude-howto 的 CI 门禁与 JSON 输出

Claude Code 如何用 claude ultrareview 做非交互式 PR 审查?claude-howto 的 CI 门禁与 JSON 输出 【免费下载链接】claude-howto A visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bri…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬