第八章 agent记忆与检索上

第八章 记忆与检索

学习笔记

本章的主要目标是增加memory system和rag功能

那为什么智能体需memory和rag

(1)局限一:无状态导致的对话遗忘

上下文丢失:在长对话中,早期的重要信息可能会因为上下文窗口限制而丢失

个性化缺失:Agent无法记住用户的偏好、习惯或特定需求

学习能力受限:无法从过往的成功或失败经验中学习改进

一致性问题:在多轮对话中可能出现前后矛盾的回答

(2)局限二:模型内置知识的局限性

知识时效性:大模型的训练数据有时间截止点,无法获取最新信息

专业领域知识:通用模型在特定领域的深度知识可能不足

事实准确性:通过检索验证,减少模型的幻觉问题

可解释性:提供信息来源,增强回答的可信度

在实现上,我们将记忆和RAG设计为两个独立的工具:memory_tool负责存储和维护对话过程中的交互信息,rag_tool则负责从用户提供的知识库中检索相关信息作为上下文,并可将重要的检索结果自动存储到记忆系统中。

HelloAgents记忆系统

├── 基础设施层 (Infrastructure Layer)

│ ├── MemoryManager - 记忆管理器(统一调度和协调)

│ ├── MemoryItem - 记忆数据结构(标准化记忆项)

│ ├── MemoryConfig - 配置管理(系统参数设置)

│ └── BaseMemory - 记忆基类(通用接口定义)

├── 记忆类型层 (Memory Types Layer)

│ ├── WorkingMemory - 工作记忆(临时信息,TTL管理)

│ ├── EpisodicMemory - 情景记忆(具体事件,时间序列)

│ ├── SemanticMemory - 语义记忆(抽象知识,图谱关系)

│ └── PerceptualMemory - 感知记忆(多模态数据)

├── 存储后端层 (Storage Backend Layer)

│ ├── QdrantVectorStore - 向量存储(高性能语义检索)

│ ├── Neo4jGraphStore - 图存储(知识图谱管理)

│ └── SQLiteDocumentStore - 文档存储(结构化持久化)

└── 嵌入服务层 (Embedding Service Layer)

├── DashScopeEmbedding - 通义千问嵌入(云端API)

├── LocalTransformerEmbedding - 本地嵌入(离线部署)

└── TFIDFEmbedding - TFIDF嵌入(轻量级兜底)

HelloAgents RAG系统

├── 文档处理层 (Document Processing Layer)

│ ├── DocumentProcessor - 文档处理器(多格式解析)

│ ├── Document - 文档对象(元数据管理)

│ └── Pipeline - RAG管道(端到端处理)

├── 嵌入表示层 (Embedding Layer)

│ └── 统一嵌入接口 - 复用记忆系统的嵌入服务

├── 向量存储层 (Vector Storage Layer)

│ └── QdrantVectorStore - 向量数据库(命名空间隔离)

└── 智能问答层 (Intelligent Q&A Layer)

├── 多策略检索 - 向量检索 + MQE + HyDE

├── 上下文构建 - 智能片段合并与截断

└── LLM增强生成 - 基于上下文的准确问答


这张图描述的是一个 "带多类型记忆系统的 Agent 记忆子系统":把用户输入先判断成「要不要写入记忆 / 要不要检索记忆 / 要不要做管理维护」,然后走不同的流水线;并且把记忆分成 Working / Episodic / Semantic / Perceptual 四类,各自用不同的存储与检索方式,但底层共享同一个 EmbeddingService。

最上面是:

用户输入 → 操作类型判断 →(三分支)

添加记忆(写入)

搜索记忆(检索/召回)

管理操作(清理、整合、统计等维护)

这三条是记忆系统最核心的"写、读、管"。

  1. 添加记忆(写入链路)

路径是:

添加记忆 → Manager.add_memory → 自动分类 → 写入不同记忆类型

1.1 Manager.add_memory 在做什么

它是写入入口:接收一段文本/多模态输入(比如一句话、图片描述等),然后做三件事:

规范化:补齐 user_id、时间戳、来源(对话/工具/外部文件)等元数据

抽取/计算特征:包括 embedding(语义向量)、可能还有实体(人名/地点/技能)

路由分发:根据"自动分类"结果写入不同记忆桶

1.2 自动分类:为什么要分 4 类

图里分成四种记忆(紫色框):

A. Working(临时信息)

适合:短期上下文、临时约定、当前任务状态

例:"接下来三轮对话都用中文回答"、"我现在在调试 qdrant"

存储:内存存储 + TTL 管理(橙色框写着 TTL)

特点:快、轻,但会过期

检索:一般直接用 key/规则,或简单相似度(取决于实现)

B. Episodic(具体事件)

适合:发生过的具体经历/对话事实(带时间、场景)

例:"2026-01-18 我说我叫张三,我是 Python 开发者"

存储:SQLite + Qdrant(事件索引)

SQLite:落盘保存原文、时间、标签、可审计

Qdrant:保存向量,用于"语义相似"检索最近似事件

特点:可回溯、可按时间过滤、也可语义召回

C. Semantic(抽象知识)

适合:从多次对话中沉淀出的稳定事实、偏"知识图谱"的东西

例:张三 -> 职业 -> Python开发者,张三 -> 熟悉 -> FastAPI

存储:Qdrant + Neo4j(知识图谱)

Qdrant:解决"语义近似召回"(你换个说法也能找到)

Neo4j:解决"关系查询/多跳推理"(谁-是什么-什么)

特点:可解释、可结构化推理(路径查询、关系约束)

D. Perceptual(多模态)

适合:图片/点云/音频等多模态信息的"感知记忆"

存储:SQLite + Qdrant(多模态向量)

SQLite:存原始引用(文件路径、hash、元信息)

Qdrant:存跨模态 embedding 向量(图里叫"多模态向量")

特点:支持"以文搜图""以图搜图"这类检索(取决于 embedding 模型能力)

  1. EmbeddingService:四类记忆的"统一底座"
    图最下方大框:统一嵌入服务 EmbeddingService,并写了一个降级链路:
    DashScope → Local → TFIDF
    意思是:整个系统生成向量时不关心你用哪个 embedding 提供方,由 EmbeddingService 统一封装,并能在失败时降级:
    DashScope(云端 embedding 服务,优先用)
    Local(本地 embedding 模型兜底)
    TFIDF(再兜底:当没有神经 embedding 时,用传统向量化保证"还能检索")

关键点:Qdrant 的检索质量几乎完全取决于 embedding。

embedding 一致性也很重要:同一套 collection 尽量用同一类向量空间,否则相似度会乱。

  1. 搜索记忆(检索链路)

路径是:

搜索记忆 → Manager.retrieve_memories → 跨类型并行检索 → 各记忆类型 .retrieve → 结果聚合与排序 → 返回 Top-k

3.1 Manager.retrieve_memories 的职责

它是统一检索入口,通常会做:

把用户 query 做 embedding(走 EmbeddingService)

给每种记忆类型构造检索请求(不同类型不同策略)

并行检索(图中写"跨类型并行检索")

把多路结果融合重排("结果聚合与排序")

输出 Top-k 给 Agent(用于拼上下文或直接回答)

3.2 "各记忆类型 .retrieve" 各自怎么查

典型做法(与你图一致):

Working.retrieve:直接查内存 + TTL 未过期;可能按最近写入优先

Episodic.retrieve:Qdrant 语义 topK + SQLite 补全文本/时间(也可按时间窗口过滤)

Semantic.retrieve:

Qdrant:先语义召回相关"概念/事实片段"

Neo4j:再做结构化查询(比如"张三 IS_A 什么"),或者用召回结果做图扩展(多跳)

Perceptual.retrieve:Qdrant 多模态向量检索 + SQLite 找到对应媒体引用

3.3 结果聚合与排序(很关键)

因为每路返回的"分数"不可直接比较(向量相似度、图匹配置信度、时间衰减等),所以要融合:

常见融合策略:

归一化分数:把不同检索的 score 映射到统一区间

加权:例如 Semantic 权重大于 Episodic,Working 最高但只在 TTL 内

去重:同一事实可能既在 episodic 又在 semantic

时间衰减:事件越近越重要;抽象知识越稳定越不衰减

最终返回 Top-k 记忆 供 LLM 使用。

  1. 管理操作("管"的链路)

路径是:

管理操作 → Manager.管理功能 → 管理策略 → 三类策略分支

图里绿色框写了 3 个:

4.1 记忆整合:Working → Episodic

含义:把"短期工作记忆"里重要的东西沉淀成长期事件记忆。

Working 中反复出现、或被标记重要的信息 → 写入 Episodic(落 SQLite + 向量库)

或者把一段任务过程的多个 Working 状态,汇总成一次 Episodic 事件

目的:避免 Working 无限膨胀,同时让关键上下文可长期回忆。

4.2 智能遗忘:多策略清理

目的:控制成本、减少噪声、提升召回精度。

典型策略:

TTL 到期直接删(Working)

事件类(Episodic)按"重要度 + 访问频率 + 时间衰减"清理

语义类(Semantic)按"冲突检测 / 过期知识 / 低置信"更新或合并

Perceptual 按"引用是否有效 / 是否重复"清理

4.3 统计分析:跨类型汇总

做可观测性:你记了多少、哪类多、命中率怎样、最近常用哪些实体/关系。

这对调参很有用,比如:

Top-k 召回太多噪声 → 说明 episodic 太"碎"

semantic 图谱边太多太乱 → 需要更强的实体消歧/关系抽取

  1. 用一个具体例子串起来(最直观)
    用户说:
    "你好!请记住我叫张三,我是一名Python开发者"
    写入
    Manager.add_memory 收到文本
    自动分类:
    "我叫张三/我是Python开发者"更像稳定事实 → Semantic
    同时作为一次对话事件也可进 Episodic(看实现)
    EmbeddingService 生成向量
    写:
    Episodic:SQLite 存事件 + Qdrant 存向量

Semantic:Qdrant 存向量 + Neo4j 写 (张三)-[:IS_A]->(Python开发者)


现在让我们采用自顶向下的方式,从MemoryTool支持的具体操作开始,逐步深入到底层实现。MemoryTool作为记忆系统的统一接口,其设计遵循了"统一入口,分发处理"的架构模式:

def execute(self, action: str, **kwargs) -> str:

"""执行记忆操作

复制代码
支持的操作:
- add: 添加记忆(支持4种类型: working/episodic/semantic/perceptual)
- search: 搜索记忆
- summary: 获取记忆摘要
- stats: 获取统计信息
- update: 更新记忆
- remove: 删除记忆
- forget: 遗忘记忆(多种策略)
- consolidate: 整合记忆(短期→长期)
- clear_all: 清空所有记忆
"""

if action == "add":
    return self._add_memory(**kwargs)
elif action == "search":
    return self._search_memory(**kwargs)
elif action == "summary":
    return self._get_summary(**kwargs)
# ... 其他操作

Copy to clipboardErrorCopied

这种统一的execute接口设计简化了Agent的调用方式,通过action参数指定具体操作,使用**kwargs允许每个操作有不同的参数需求。


现在让我们深入了解四种记忆类型的具体实现,每种记忆类型都有其独特的特点和应用场景:

(1)工作记忆(WorkingMemory)

工作记忆是记忆系统中最活跃的部分,它负责存储当前对话会话中的临时信息。工作记忆的设计重点在于快速访问和自动清理,这种设计确保了系统的响应速度和资源效率。

工作记忆采用了纯内存存储方案,配合TTL(Time To Live)机制进行自动清理。这种设计的优势在于访问速度极快,但也意味着工作记忆的内容在系统重启后会丢失。这种特性正好符合工作记忆的定位,存储临时的、易变的信息。


首先尝试使用TF-IDF向量化进行语义检索,如果失败则回退到关键词匹配

TF-IDF 是什么

TF-IDF 是一种把文本变成"向量"的经典方法,全名 Term Frequency--Inverse Document Frequency(词频-逆文档频率)。它的核心思想很朴素:

一段文本里 某个词出现得越多 → 这个词越能代表这段文本(TF)

但如果这个词在所有文档里都很常见(比如"的、是、我们")→ 这个词就没那么"有区分度"(IDF 会把它压低)

也就是词重合度越高,tfidf越高,然后这个重合的词,如果是稀有的词,那这个tfidf值更高

(2)情景记忆(EpisodicMemory)

情景记忆负责存储具体的事件和经历,它的设计重点在于保持事件的完整性和时间序列关系。情景记忆采用了SQLite+Qdrant的混合存储方案,SQLite负责结构化数据的存储和复杂查询,Qdrant负责高效的向量检索。

(3)语义记忆(SemanticMemory)

语义记忆是记忆系统中最复杂的部分,它负责存储抽象的概念、规则和知识。语义记忆的设计重点在于知识的结构化表示和智能推理能力。语义记忆采用了Neo4j图数据库和Qdrant向量数据库的混合架构,这种设计让系统既能进行快速的语义检索,又能利用知识图谱进行复杂的关系推理。

语义记忆的添加过程体现了知识图谱构建的完整流程。系统不仅存储记忆内容,还会自动提取实体和关系,构建结构化的知识表示:

语义记忆的检索实现了混合搜索策略,结合了向量检索的语义理解能力和图检索的关系推理能力: 也就是说,什么是混合检索,就是同时用向量检索和图检索

向量检索就是看语义上最详尽的,选limit*2个,然后图检索就是不是算相似度,而是从 query

中找"锚点",再沿着图里的关系走几步,把"结构上相关"的节点捞出来 然后对这两个的结构就行合并、去重

然后进行多因子打分,这个权重是自己设定的

语义记忆的评分公式为:(向量相似度 × 0.7 + 图相似度 × 0.3) × (0.8 + 重要性 × 0.4)。这种设计的核心思想是:

向量检索权重(0.7):语义相似度是主要因素,确保检索结果与查询语义相关 图检索权重(0.3):关系推理作为补充,发现概念间的隐含关联

重要性权重范围[0.8, 1.2]:避免重要性过度影响相似度排序,保持检索的准确性

(4)感知记忆(PerceptualMemory)

感知记忆支持文本、图像、音频等多种模态的数据存储和检索。它采用了模态分离 的存储策略,为不同模态的数据创建独立的向量集合,这种设计避免了维度不匹配的问题,同时保证了检索的准确性:

感知记忆的检索支持同模态和跨模态两种模式。同模态检索利用专业的编码器进行精确匹配,而跨模态检索则需要更复杂的语义对齐机制

感知记忆的评分公式为:(向量相似度 × 0.8 + 时间近因性 × 0.2) × (0.8 + 重要性 × 0.4)。感知记忆的评分机制还支持跨模态检索,通过统一的向量空间实现文本、图像、音频等不同模态数据的语义对齐。当进行跨模态检索时,系统会自动调整评分权重,确保检索结果的多样性和准确性。

此外,感知记忆中的时间近因性计算采用了指数衰减模型


相关推荐
雨大王5122 小时前
如何通过工业智造超级智能体实现汽车制造工厂数字化转型
人工智能·自动化·汽车·制造·ai-native
薛不痒2 小时前
计算机视觉opencv之图片旋转&模版匹配&银行卡号的识别
人工智能·opencv·学习·计算机视觉
LDG_AGI2 小时前
【机器学习】深度学习推荐系统(二十九):X 推荐算法多样性打散机制详解
人工智能·深度学习·算法·机器学习·推荐算法
果粒蹬i2 小时前
使用 LangChain 与 CrewAI 实现 AI Agent 的多步任务规划(零基础入门)
人工智能·langchain
果粒蹬i2 小时前
RAG 技术进阶:GraphRAG + 私有数据,打造工业级问答系统
人工智能·cnn·prompt·transformer·easyui
得贤招聘官2 小时前
AI 驱动招聘变革:从流程电子化到决策智能化的跨越
人工智能
大江东去浪淘尽千古风流人物2 小时前
【SEVIS】An Efficient Schmidt-EKF for 3D Visual-Inertial SLAM
人工智能·机器学习·3d
腾视科技2 小时前
腾视科技AIBOX双版本重磅发布!本地安全与全球适配,解锁视频智能新可能
人工智能·科技·安全
Jinkxs2 小时前
AI - 测试工程师会被 AI 取代吗?我用 AI 测试工具干了 3 个月,结论很意外
人工智能·测试工具