发布时间:2026-07-12
标签:AI Agent|LLM|Memory|向量数据库|架构设计|工程实现
系列导航
上一篇:AI Agent 工程实践(09):AI Engineering OS v2——系统如何持续演化?
下一篇:AI Agent 工程实践(11):Workflow——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/scope) |

pie 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" | 向量为主,结构化 scope |
| Procedural 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
双通道意味着:检索时先走结构化过滤(type=semantic AND scope=project),缩小候选集,再走向量语义匹配。过滤砍掉噪声,语义找到精准。
Memory Manager 架构
这是你给的核心链路——User → Conversation → Memory Manager → Vector DB:

Memory Manager 的三大流程:
写入流程:
- 会话结束时,Conversation 的内容被蒸馏——提取出"可能值得长期记"的信息
- 分类器判断类型(Episodic/Semantic/Procedural)
- 双写:结构化字段进 PostgreSQL,embedding 进向量库
检索流程:
- Agent 需要记忆时,先构造检索条件(
type=semantic, scope=project) - 结构化过滤——缩小候选集
- 语义匹配——在候选集里找最相关的 top-K
蒸馏流程:
- 定期(周复盘):检查每条记忆的
hit_count和last_hit - 长期未命中 → 降级到 Archive(03 篇定义)
- 语义重复 → 合并,保留更新版本
实际收益
| 指标 | 全量向量检索 | 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(id=pg_id, embedding=embed(memory.content))
def retrieve(self, query: str, filters: dict, top_k: int = 5) -> list:
"""检索:先过滤 → 再语义"""
# 1. 结构化过滤:缩小候选集
candidates = self.pg.filter(
type=filters.get("type"),
scope=filters.get("scope"),
tags=filters.get("tags"),
time_range=filters.get("time_range"),
)
# 2. 语义检索:在候选集内匹配
query_vec = embed(query)
results = self.vec.search(query_vec, ids=candidates.ids, top_k=top_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(days=stale_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/tag),Vector 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 工程实践(09):AI Engineering OS v2——系统如何持续演化?
下一篇:AI Agent 工程实践(11):Workflow——Agent 如何完成复杂任务?
本文是 [AI Agent 工程实践] 系列的第 10 篇(第二季 · 工程实现)。
:Memory 不只是聊天记录——长期记忆架构设计&spm=1001.2101.3001.5002&articleId=162920716&d=1&t=3&u=15a863bda8584d409c45b9c37a4287df)
2106

被折叠的 条评论
为什么被折叠?



