上一篇处理的是单次会话里窗口怎么组织。会话一关,上下文学习(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):可复用流程——「先搜直飞 → 确认座位 → 填常旅客号」

评估可用三层递进(书中归纳,便于自己写回归集):

  1. 基础回忆:精确返回用户给过的结构化事实
  2. 多会话检索:跨对象、跨时间拼齐信息(两辆车预约保养时要先问哪一辆)
  3. 主动服务:无明确指令时,从旧记忆预见问题(护照将过期仍订国际机票)

开源框架对照: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 库回答「退款政策是什么」够用;但两类问题会系统性失败:

  1. 聚合统计:「100 个案例里黑白猫比例」——检索是 top-k,不是全库扫描;应在索引期预写统计摘要。
  2. 规则归纳:孤立成功/失败案例靠语义近邻会误推——应在索引期提炼显式规则。

两条常见结构化路线:

  • 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,也减轻注意力稀释。

本篇收束

  1. 用户记忆是跨会话的预测模型,不是全文聊天备份;轨迹与长期记忆职责不同。
  2. 存储格式在简单性与表达力之间权衡;关键关系可结构化,大量事实可原子化。
  3. RAG 质量首先卡在 分块与混合检索;统计与规则类问题要在索引期提炼。
  4. 结构化索引、文件系统、Agentic RAG 是三条增强轴,按查询形态加码,而不是默认全上。
  5. 隐私与注入:脱敏、来源标记、记忆写入审查,与「个性化」同步设计。

下一篇进入第 4 章:工具设计——感知/执行/协作/事件/用户沟通五类工具,粒度、描述、MCP,以及异步事件驱动。

版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:03. 记忆与知识库:跨会话之后,Agent 还记得什么

本文链接:https://www.sshipanoo.com/blog/ai/ai-agent-indepth/03-记忆与知识库/

本文最后一次更新为 天前,文章中的某些内容可能已过时!