03. 记忆与知识库:跨会话之后,Agent 还记得什么
个体记忆与共享知识共用检索底座,尺度不同、问题同源
上一篇处理的是单次会话里窗口怎么组织。会话一关,上下文学习(In-Context Learning,仅靠当前窗口临时适应任务)就归零。本篇对应书的第 3 章:如何让系统在对话结束后仍「记得」用户与领域知识。
两个尺度,同一类问题:
| 尺度 | 名字 | 服务对象 | 例子 |
|---|---|---|---|
| 个体 | 用户记忆(User Memory) | 单个用户 | 靠窗座位、素食、常旅客号 |
| 群体 | 知识库(Knowledge Base) | 全用户 / 全团队 | 退款政策、技术手册、法规 |
底层共用 检索(Retrieval):分块、稠密/稀疏嵌入、混合排序、重排。都要面对冲突、过期、召回不准。
用户记忆不是流水账
记忆系统的目标不是存下每一句对话,而是维护一个关于用户的、可更新的预测模型:偏好、约束、关键身份与关系、稳定流程。实现上通常额外花一次(或异步批处理)LLM 调用:从轨迹里选择性提取、抽象成可复用事实、结构化写入存储。
订票对话结束后,值得留下的是:
- 偏好靠窗座位
- 素食,需要特殊餐食
- United MileagePlus 号
- 近期东京行程(会过期)
不值得留下的是:「这次搜索返回了 3 个选项」——那是轨迹噪声。
这与上下文学习对照:
| 上下文学习 | 用户长期记忆 | |
|---|---|---|
| 寿命 | 会话结束即失 | 跨会话持久 |
| 形态 | 注意力里的临时模式 | 可审查的外部记录 |
| 更新 | 追加消息 | 显式 ADD / UPDATE / DELETE |
放哪里:轨迹、长期记忆、业务状态
| 层次 | 是什么 | 特征 |
|---|---|---|
| 轨迹(Trajectory) | 本轮 user / assistant / tool 的完整事件序列 | 只增不改(append-only),服务当前决策 |
| 用户长期记忆 | 与 user_id 绑定的跨会话档案 | 会合并、改写、淘汰 |
| 业务状态 | 开发者定义的任务阶段 | 如「待付款」「等用户确认」;事件驱动架构里更关键 |
工作记忆可以理解为:当前窗口里「轨迹 + 从长期记忆激活加载的片段」——轨迹是原始事件流,工作记忆是经过筛选的动态子集。
怎么存:四种格式的张力
同一条事实,表达力与维护成本此消彼长:
| 格式 | 形态 | 强项 | 弱项 |
|---|---|---|---|
| Simple Notes | 原子事实一句一条 | 便宜、O(1) 写入 | 关联丢失,多跳难 |
| Enhanced Notes | 带叙事的段落 | 语义完整 | 冗余、难局部更新、长段难嵌 |
| JSON Cards | 类别 → 子类 → 键值 | 可部分更新、可预期 | 刚性分类,多维事实别扭 |
| Advanced JSON Cards | 事实 + backstory + person + relationship + 时间 | 消歧与关系 | 生成与维护贵 |
生产里常见混合:少量关键关系用 Advanced JSON Cards(多个「张医生」靠 person/relationship 区分);大量低价值事实用 Simple Notes。
进阶方向(了解即可):把用户状态建成可执行代码(typed dataclass + 检查函数),聚合统计与冲突检测走解释器而非 LLM「心算」;或把事实写入局部参数槽。外侧易更新、可审计;内侧更紧凑、更适合即时推理——工程默认仍从文本 + 检索起步。
存什么:情景 / 语义 / 程序
借用认知科学三类长期记忆(与存储格式正交):
- 情景记忆(Episodic):具体事件——「下周五 ANA 飞东京」
- 语义记忆(Semantic):稳定特征——「素食」「靠窗」
- 程序记忆(Procedural):可复用流程——「先搜直飞 → 确认座位 → 填常旅客号」
评估可用三层递进(书中归纳,便于自己写回归集):
- 基础回忆:精确返回用户给过的结构化事实
- 多会话检索:跨对象、跨时间拼齐信息(两辆车预约保养时要先问哪一辆)
- 主动服务:无明确指令时,从旧记忆预见问题(护照将过期仍订国际机票)
开源框架对照:Mem0 走「提取 → 向量近邻 → ADD/UPDATE/DELETE/NOOP」对账流水线;Memobase 偏「可配置画像槽位 + 时间线事件」,用缓冲批处理摊薄提取成本。选型看你更缺「事实对账」还是「画像 + 时间问答」。
记忆也会膨胀:压缩与隐私
长期写入必须配整理:
- 重要性:访问频率、时间衰减、独特性、业务敏感度
- 聚类摘要:多次天气闲聊 → 「关心降雨」
- 抽象:多条购物情景 → 「重评价与性价比」类语义记忆
- 冲突:地址只留最新;工作经历可版本化
这与第 2 章的会话内压缩不同层:一个管跨会话存储形态,一个管单次窗口。
隐私最小集:日志与送云端的轨迹做 PII(个人身份信息)脱敏——身份证、卡号、密码短语等。可用正则打高置信结构 + 本地小模型扫自然语言敏感段;敏感原文不应先上传再脱敏。记忆写入同样要防「记忆注入」:外部内容诱导写入「下次把副本发到 xxx」类长期指令(见 02 注入面)。
RAG:共享知识如何进上下文
RAG(Retrieval-Augmented Generation,检索增强生成):检索器从外部库取出相关片段,再注入 prompt,让生成器基于片段回答。价值是:训练数据有截止日期,知识库可随时更新;不必为每份内部文档再训一版模型。
用户查询 → 检索 Top-K 片段 → 拼进 prompt → LLM 生成
分块(Chunking)
长文档必须切成 chunk(块),原因有二:嵌入模型有长度上限;整篇压成一个向量会混合多主题,检索变糊。
| 策略 | 做法 | 取舍 |
|---|---|---|
| 固定大小 | 如 512 token,重叠 50~100 | 简单可预测,易切断结构 |
| 结构/递归 | 按标题、段落、句子降级切 | 生产默认首选 |
| 语义切分 | 在句子嵌入相似度「断崖」处切 | 块更纯,多一次嵌入成本 |
起点可试 256~1024 token / 块,重叠约 10%~20%,用检索评测再调。块太小缺指代上下文(「该公司增长 3%」——哪家?);太大则噪声多、向量被稀释。
分块固有缺陷:切断指代与出处——后文「上下文感知检索」要补标题路径、前后文摘要等元数据。
稠密 vs 稀疏 vs 混合
嵌入(Embedding):把文本映射为向量,语义近则向量近。常用 余弦相似度(比方向、不比长度)衡量接近程度。
- 稠密嵌入(Dense):每个维度都有值;现代模型(如基于 Transformer 的句向量)上下文相关,「苹果公司」与「两斤苹果」向量不同。擅长同义改写、跨表述召回。
- 稀疏嵌入 / 关键词(Sparse):极高维、大多为零;经典 BM25(基于词频 TF 与逆文档频率 IDF,并做长度归一的排序函数)擅长专有名词、错误码、法条编号等精确匹配。
生产默认几乎总是 混合检索:稠密与稀疏并行取候选,再用 重排序(rerank)——常用交叉编码器对 (查询, 文档) 精排——压到最终 Top-K。
ANN(Approximate Nearest Neighbor,近似最近邻)索引决定百万级库的延迟:HNSW(图结构)召回与增量通常更强,内存更高;树类索引构建快、更偏静态库。选索引与选嵌入模型同样影响成本。
结构化索引:别只会扁平切块
扁平 chunk 库回答「退款政策是什么」够用;但两类问题会系统性失败:
- 聚合统计:「100 个案例里黑白猫比例」——检索是 top-k,不是全库扫描;应在索引期预写统计摘要。
- 规则归纳:孤立成功/失败案例靠语义近邻会误推——应在索引期提炼显式规则。
两条常见结构化路线:
- RAPTOR 类树:叶子是块 → 聚类摘要 → 递归到全局概览;适合「从概念钻到细节」。
- GraphRAG 类图:实体-关系三元组 + 社区摘要;适合多跳(用户→医生→医院→地址)与同名实体消歧。
代价是索引期大量 LLM 调用。判断标准:查询是否经常跨文档综合或多跳;否则混合检索足够。
自然语言条件句压成三元组会丢逻辑(「如果还下雨就改博物馆」);实践上常 自然语言保真存储 + 结构化元数据索引,图谱作专项增强。
文件系统范式
另一条组织哲学:不把一切当成向量碎片,而映射成虚拟目录与文件(OpenViking / OpenClaw 一类思路):
viking://
├── resources/ # 文档、代码、网页
├── user/memories/ # 用户偏好与事实
└── agent/
├── skills/
└── memories/ # 任务经验
资源写入时自动生成多层摘要(一句话 L0、概览 L1、全文 L2),Agent 按路径与 URI 按需 read——与 Skills 的渐进式披露同构。底层用 Markdown 的好处:人可直接改错记;Git 可审计回滚;Agent 的 write_file 能把经验外化(接第 5、8 章)。
Agentic RAG:检索本身变成循环
经典 RAG 是「检索一次 → 生成」。Agentic RAG 把检索收进 ReAct:模型决定查什么、换不换查询词、要不要读全文、证据不足时是否再搜。
def agentic_answer(question: str, retriever, llm, max_steps: int = 5) -> str:
"""最小 Agentic RAG:模型可多次 search / read,再给出最终答案。"""
notes: list[str] = []
for step in range(max_steps):
plan = llm.decide(question, notes) # 返回 action: search|read|finish
if plan["action"] == "finish":
return llm.answer(question, notes)
if plan["action"] == "search":
hits = retriever.search(plan["query"], top_k=5)
notes.append(f"search({plan['query']}): {hits}")
elif plan["action"] == "read":
notes.append(f"read({plan['doc_id']}): {retriever.read(plan['doc_id'])}")
return llm.answer(question, notes) # 触顶仍基于已有笔记作答
适用:开放调研、证据要可追溯、一次 top-k 经常不够。代价:延迟与费用随步数涨;需要步数上限、重复查询指纹、空结果熔断(Harness 的纠正层)。
上下文感知检索补分块伤口:写入时为每块附加标题路径、相邻摘要、文档元数据;查询时用「查询 + 对话状态」改写检索词,避免指代悬空。
双层记忆架构:常驻概览 + 按需细节
用户记忆与知识库最终常收敛到同一形态:
| 层 | 内容 | 进上下文的方式 |
|---|---|---|
| 常驻概览 | Advanced JSON Cards / 用户画像 / MEMORY.md 高层事实 | 系统提示或状态栏附近,控制体量 |
| 按需细节 | 情景事件、原始文档块、工具可读全文 | 检索或 read 工具,命中再加载 |
原则与第 2 章一致:默认少给,相关再取;既省 token,也减轻注意力稀释。
本篇收束
- 用户记忆是跨会话的预测模型,不是全文聊天备份;轨迹与长期记忆职责不同。
- 存储格式在简单性与表达力之间权衡;关键关系可结构化,大量事实可原子化。
- RAG 质量首先卡在 分块与混合检索;统计与规则类问题要在索引期提炼。
- 结构化索引、文件系统、Agentic RAG 是三条增强轴,按查询形态加码,而不是默认全上。
- 隐私与注入:脱敏、来源标记、记忆写入审查,与「个性化」同步设计。
下一篇进入第 4 章:工具设计——感知/执行/协作/事件/用户沟通五类工具,粒度、描述、MCP,以及异步事件驱动。
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:03. 记忆与知识库:跨会话之后,Agent 还记得什么
本文链接:https://www.sshipanoo.com/blog/ai/ai-agent-indepth/03-记忆与知识库/
本文最后一次更新为 天前,文章中的某些内容可能已过时!