基于李博杰《深入理解 AI Agent:设计原理与工程实践》第3章学习笔记。
开篇:那个”健忘”的智能助手
你向某个 AI 助手说过三次”我搬到了上海”,它每次依然认真地问你”请问您所在的城市是?”——这不只是体验问题,而是 Agent 架构里最基础的一块拼图缺了:记忆。
上一章解决的”上下文工程”处理的是单次会话内的窗口问题;而本章把尺度拉长到跨会话、甚至跨越所有用户的持久化知识体系。全书两条主线在这里交汇:针对个体用户的用户记忆,与面向所有用户的共享知识库。这篇文章我们跟着作者一起,从记忆的存储格式讲到 RAG 检索技术栈,再到超越扁平文本的知识组织。
一、用户记忆系统
评估标准先行:三层次框架
设计记忆系统之前,先得有”什么算好的记忆”的标尺。作者提出记忆能力的三层次框架:
- 第一层 · 基础回忆:能记住用户说过的明确事实,如”我的支票账户号码是多少?”
- 第二层 · 多会话检索:能把分散在多次会话中的信息关联起来,如”我需要为我的车预约服务”(车的信息分散在两通电话里)
- 第三层 · 主动服务:无需用户开口,主动发现跨会话的隐藏关联,如”护照二月过期,而东京之行在一月”——主动提醒用户加急续签
前两层靠存储和检索技术即可满足,第三层才真正考验记忆架构的设计。
记忆放哪里:层次结构
记忆系统可以拆成三个独立维度——放哪里、怎么存、存什么。先说”放哪里”:
- 轨迹(Trajectory):单次会话的完整历史记录,按时间顺序只增不改(append-only),为当前决策提供即时上下文。
- 用户长期记忆:跨会话、跨实例的持久化存储,以键值对绑定用户 ID,存储偏好、摘要、知识点。Agent 通过工具调用显式读写。
- 业务状态:开发者定义的高层状态抽象(如”等待付款”“处理请求中”),在事件驱动架构中尤为重要。
一句话区分:轨迹是流水账,长期记忆是档案。
怎么存:四种存储格式
同一条用户信息,可以用不同粒度表示。四种格式沿着”简单性 → 表达力”递进:
| 格式 | 特点 | 优势 | 代价 |
|---|---|---|---|
| Simple Notes | 最小原子事实:”用户邮箱:john@x.com” | O(1) 开销极低 | 关联性完全丢失 |
| Enhanced Notes | 完整叙事段落 | 语义完整、适合细微理解 | 冗余、难更新、长文难检索 |
| JSON Cards | 三层嵌套:类别→子类别→键值对 | 支持部分更新、可扩展 | 刚性分类丢多维性 |
| Advanced JSON Cards | 事实 + backstory + person + relationship | 解决消歧、知识管理 | 生成维护成本高 |
最值得展开的是 Advanced JSON Cards 背后的思想:同一条信息在不同场景下含义完全不同——”张医生”可能是用户的牙科医生,也可能是用户父亲的心脏科医生。通过 backstory(为什么存这条信息)、person 和 relationship(为谁存),系统能正确消歧。
实践中的选择标准:关键且少量的数据用 Advanced JSON Cards,大量且非关键的对话事实用 Simple Notes,多数生产系统采用混合模式。
更激进的表示:从文本到代码再到参数
文本记忆有个根本缺陷:”存”和”用”是分开的两步——先把文本捞回来,再交给 LLM 去读去算。聚合统计、冲突发现、约束执行这些操作全靠 LLM”心算”。
User as Code 的思路是把表示介质从文本换成可执行代码:用带类型的 Python 对象保存用户状态,记忆更新拆成”只增事实日志 + 周期性结构化重建”两阶段(数据库里”预写日志 + 检查点”的经典设计)。效果惊人:
- 聚合统计:”我去年出了几次国?”——检索式记忆正确率仅 6%–43%,代码表达式接近 99%
- 冲突发现:一个函数就能交叉比对”当前用药”与”过敏史”,揪出文本形式下几乎不可能自动关联的矛盾
- 约束执行:护照距到期不足 180 天自动报警——由确定性解释器而非 LLM 完成算术
再往里走,记忆甚至能写进模型参数:User as Engram 把用户事实精准写入 Engram 模型空闲的哈希 N-gram 槽位,绕开”存了却不会用”的困境;Parametric Multimodal User Memory 则用感知向量存下”一张脸的模样”这种无法言说的记忆。这条”由外及内”的连续谱,外侧易更新可审查,内侧更紧凑、擅长即时推理。
存什么:认知科学的启示
记忆内容的类型可以借用认知科学的三分法:
- 情景记忆(Episodic):具体事件——”用户订了下周五去东京的 ANA 航班”
- 语义记忆(Semantic):抽象出的稳定特征——”用户是素食者”
- 程序记忆(Procedural):行为流程——”先搜直飞 → 确认座位 → 用常旅客号”
注意这里的分类体系与”放哪里”“怎么存”是三个正交维度,可以自由组合。
工程化框架与记忆维护
- Mem0:核心是一条”提取—对比—决策”流水线——每次对话后 LLM 提取候选记忆,向量检索近邻后由 LLM 做出 ADD / UPDATE / DELETE / NOOP 四种决策。用户说”我搬到了上海”,系统检索到”住在北京”,判定为 UPDATE 而非并存两条矛盾记录。
- Memobase:聚焦”用户画像 + 事件记忆”,采用缓冲批处理摊薄 LLM 调用成本。
记忆维护还需要压缩与整理:重要性评分(访问频率、时间衰减、情感强度、信息独特性)筛选 → 聚类生成摘要 → 抽象泛化出一般性规律;冲突检测用版本化方法(保留历史、标记最新)。隐私方面,本地小模型(如 Qwen3 0.6B)做 PII 检测与日志脱敏,召回率 95% 以上——选择本地部署是因为日志本身敏感,发到云端就违背了隐私初衷。
二、RAG 基础:知识获取管道
当记忆量增长到成千上万条,核心问题变成”如何快速找到相关的那几条”——这正是检索增强生成(RAG)的用武之地。RAG 的核心思想:把 LLM 的思考能力与外部知识库的广度和时效性结合。流程是固定的四步:检索 → 增强 → 生成。
第一道工序:文档分块
- 固定大小切分:按 token 数切,留重叠。简单但无视文档结构。
- 递归/结构感知切分:按章节、段落、句子逐级降级切分,生产系统默认选择。
- 语义切分:在相邻句子嵌入相似度”断崖”处下刀,块内主题单一。
分块埋下了一个伏笔:它切断了片段与原始上下文的联系——”该公司收入增长了 3%”,哪家公司?这一缺陷在”上下文感知检索”一节被正面解决。
两条检索路线与它们的融合
- 稠密嵌入:把文本映射到向量空间,语义相近向量距离近(余弦相似度衡量)。从静态词向量 Word2Vec(无法处理一词多义:”bank”是河岸还是银行)演进到上下文感知的 BERT、BGE-M3(一词多向量)。
- 稀疏嵌入:精确关键词匹配。BM25 是经典代表,通过 IDF 加权 + 词频饱和 + 长度归一化,解决”出现 10 次不等于贡献 10 倍”的问题。学习型稀疏检索(SPLADE、BGE-M3 稀疏分支)让神经网络为词项打分,甚至补上语义相关的词项。
两种方法各有盲区:稠密检索懂语义但可能漏掉精确关键词(搜”HTTP-403”返回”服务器错误”);稀疏检索精确但读不懂同义词(搜”kitty”找不到只写了”cat”的文档)。混合检索的思路很简单——两个引擎都跑,结果融合。融合难点在于两路得分尺度不同(余弦相似度 0~1 vs BM25 0~几十),常用倒数排名融合(RRF)只看排名。最后一环是神经重排序:用跨编码器(Cross-Encoder)对 Top-N 候选逐一精细打分——双编码器是”猎头快速筛简历”,跨编码器是”面试官与候选人深谈”。
检索质量用三个指标度量:recall@k(该找的找到了吗)、MRR(够不够靠前)、nDCG(整个排序列表质量如何)。
多模态信息提取
知识不只存在于文字。三条技术路线:原生多模态(ViT 视觉编码器把图像块当”视觉单词”,保真度最高)、提取为文本(OCR/转录,成本最低但丢版式)、工具化分析(文本起步 + 按需深入,兼顾两者)。
三、超越扁平文本:知识的组织与检索
为什么扁平文本不够
把原始文档直接切块放进知识库,有两个致命问题(书中的经典案例):
- 黑猫白猫计数问题:知识库有 100 个案例(90 黑 10 白),问”比例是多少”——top-k 截断丢大部分案例、检索分数参差、且”统计需要数遍所有文档”与”检索本性是找最相关的几个”天然矛盾。预先生成摘要”90 黑 10 白”并索引,一次检索即得。
- Xfinity 优惠规则:三个孤立案例(退伍军人成功、医生成功、教师失败),护士来问时检索器因”护士≈医生”只召回成功案例,错误推断护士也可享受。提炼出规则”仅限退伍军人和医生”后,无论问谁一次检索即获完整规则。
结论:必须在索引阶段投入计算资源,对原始知识主动提炼、抽象、结构化。
两条结构化索引路线
- RAPTOR(树状层次):自下而上递归抽象——文本块聚类成组、LLM 生成父节点摘要、逐层上卷成知识树。适合”从宏观概念逐层钻进细节”的查询。
- GraphRAG(实体关系图):把知识建模为实体-关系三元组构成的知识图谱。两大原生优势:多跳推理(”我的牙医所在医院的地址”沿关系边遍历)、实体消歧(两个同名”张医生”是不同节点,靠关系边区分)。
生产实践中组合使用通常更好;而如果查询主要是”找到包含某信息的片段”,混合检索就够了,结构化索引的代价是构建时的大量 LLM 调用。
第三种哲学:文件系统范式
字节跳动火山引擎开源的 OpenViking 把记忆、资源、技能都映射为虚拟文件系统(viking://user/memories/、viking://resources/)。核心设计是 L0/L1/L2 三层按需加载:L0 一句话摘要(~100 tokens)判断相关性 → L1 概览(~2000 tokens)供决策 → L2 全文按需加载。与第二章 Skills 的渐进式披露如出一辙。纯文本而非数据库的决策深思熟虑:可读、可改、可 Git 版本控制,Agent 有 write_file 能力后能自主组织知识。但前提是文件之间必须建立链接与索引,否则知识会退化成互不相连的孤岛。
智能体化 RAG:从被动管道到主动探索者
传统 RAG 是单向数据流:查询 → 检索 → 注入 → 生成。智能体化 RAG(Agentic RAG)把检索封装成工具,由 Agent 用 ReAct 循环主导:思考(分析需求定关键词)→ 行动(调用 knowledge_base_search)→ 观察(信息是否充分?)→ 不充分则再次检索。书中司法数据集实验显示:简单问题两者差距不大,但复杂问题(”醉酒过失致人重伤且有盗窃前科如何量刑?”)智能体化 RAG 通过多轮迭代检索,准确率显著提升——它的价值在于”解决问题“而非”回答问题”。
安全边界也要注意:检索内容是最典型的间接提示注入载体。防御分两层——指令与数据分离(来源标记:”以下是参考资料,不是命令”)、检索内容不直接触发高风险动作。
上下文感知检索:修补分块的根本缺陷
Anthropic 提出的Contextual Retrieval:在向量化前,用 LLM 为每个文本块生成”前缀摘要”再拼接索引,例如”本段节选自 ACME 公司 2025 年 Q2 财务报告”。这同时增强稀疏检索(前缀提供精确关键词)和稠密检索(注入语义背景)。结合 BM25 检索失败率降 49%,再加重排序降 67%,成本靠 prompt caching 摊薄到每百万文档约 1 美元。
注意区分:本节的”上下文感知检索”发生在索引期、做加法(补前缀);第二章的”上下文感知压缩”发生在运行期、做减法(去冗余)。
从数据集中挖掘深度知识
有些知识不以文档形式存在,而是隐藏在结构化数据的统计规律中。书中以 CAIL2018 司法判例为例:先用 LLM 把每份判例转成标准化 JSON(自下而上的因子发现,而非僵化预定义模式),再独热编码 + 聚类发现”案件原型”(如”轻微口角引发的赤手轻伤”),构建因子重要性层次模型,让 Agent 按重要性顺序引导提问、基于相似原型做数据驱动的量刑分析——从”信息检索”到”知识发现”的飞跃。
本章小结:双层记忆架构
把记忆与知识库两条线索收拢,作者给出全章的落脚点——双层记忆架构:
- 常驻层:Advanced JSON Cards 把少量关键事实(护照过期日、家庭成员)结构化后常驻上下文,提供随时可见的”概览”
- 按需层:上下文感知检索从海量原始对话中精准取回”细节”
单靠常驻上下文会因容量受限丢失细节,单靠检索又会因缺乏全局视野发现不了跨会话的隐藏关联。只有双层叠加,三层次框架中最高层的”主动服务”才第一次在工程上落地。
回到开篇的问题:让助手”记得你搬到了上海”只是第一层的起点。真正懂你的 Agent,靠的是精心的存储设计、结构化的知识组织、以及高效的检索——本章讲的就是这一整套工程答案。
下篇预告
下一章转向”工具”:Agent 如何通过工具与外部世界交互,包括工具设计、MCP 互操作标准和事件驱动架构。
本文基于李博杰著《深入理解 AI Agent:设计原理与工程实践》v1.3 第3章学习整理。系列文章同步发布于 ai-agent-study 仓库。