Hello-Agents 第二部分-第八章总结:记忆与检索

作者:逆境不可逃

技术永无止境

希望我的内容可以帮助到你!!!!!


大家吼 ! 我是 逆境不可逃 今天给大家带来文章《Hello-Agents 第二部分-第八章总结:记忆与检索》.

Hello-Agents 官方地址: datawhalechina/hello-agents: 📚 《从零开始构建智能体》------从零开始的智能体原理与实践教程

本章的核心目标是给 HelloAgents 增加两类能力:记忆系统 Memory System 和检索增强生成 RAG。前者让 Agent 能保存、检索、整合和遗忘交互经验;后者让 Agent 能从外部知识库获取最新、专业、可溯源的信息。两者都遵循第 7 章的工具化思想:不为每种能力新建 Agent 类,而是把能力封装成标准工具 MemoryToolRAGTool,再通过 ToolRegistry 挂载到 Agent 上。

配套代码建议按下面顺序阅读:

文件 关注点
01_MemoryTool_Basic_Operations.py MemoryTool 的 add/search/summary/stats/forget/consolidate 基础操作
02_MemoryTool_Architecture.py MemoryTool 与 MemoryManager 的分层架构
03_WorkingMemory_Implementation.py 工作记忆的容量、TTL、混合检索和性能特征
04_RAGTool_MarkItDown_Pipeline.py MarkItDown 文档转换、Markdown 分块、嵌入流程
05_RAGTool_Advanced_Search.py 基础检索、MQE、HyDE、组合高级检索与性能对比
06_Memory_Consolidation_Demo.py 记忆整合条件、整合流程、生命周期管理
07_RAGTool_Intelligent_QA.py RAG 智能问答、上下文构建、引用和答案质量
08_Agent_Tool_Integration.py MemoryTool 与 RAGTool 在 Agent 中协同工作
09_Memory_Types_Deep_Dive.py 四类记忆的差异、用法和协作方式
10_RAG_Pipeline_Complete.py 从文档摄取到智能问答的完整 RAG 管道
11_Q&A_Assistant.py 基于 Gradio 的智能文档问答助手案例

1. 为什么 Agent 需要记忆与 RAG

大语言模型本身通常是无状态的。每一次 API 调用都只看当前输入和显式传入的上下文,不会天然记住之前发生的事情。这会造成四类问题:

  • 上下文丢失:长对话中,早期信息会因上下文窗口限制被挤出。
  • 个性化缺失:模型无法稳定记住用户偏好、身份、习惯和长期目标。
  • 学习能力受限:不能从过往成功或失败经验中积累改进。
  • 一致性问题:多轮对话中容易出现前后回答不一致。

RAG 解决的是另一类问题:模型的内置知识是静态的、有限的,且容易出现事实幻觉。通过先检索外部知识,再把检索结果作为上下文交给模型,RAG 可以提升时效性、专业性、可解释性和可信度。

因此,本章的设计可以概括为:

  • MemoryTool:面向 "历史交互、用户状态、经验和偏好" 的长期能力。
  • RAGTool:面向 "外部文档、知识库、专业资料" 的检索增强能力。
  • 两者协同:RAG 找知识,Memory 记历程;RAG 回答当下问题,Memory 支撑长期个性化。

2. 总体架构

2.1 记忆系统架构

记忆系统采用分层设计,重点是把 "统一管理" 和 "不同类型记忆的专业化实现" 分开。

复制代码
HelloAgents 记忆系统
├── 基础设施层
│   ├── MemoryManager:统一调度和协调
│   ├── MemoryItem:标准化记忆项
│   ├── MemoryConfig:系统参数配置
│   └── BaseMemory:记忆类型基类
├── 记忆类型层
│   ├── WorkingMemory:工作记忆,短期上下文,TTL 管理
│   ├── EpisodicMemory:情景记忆,具体事件和时间序列
│   ├── SemanticMemory:语义记忆,抽象知识和图谱关系
│   └── PerceptualMemory:感知记忆,多模态数据
├── 存储后端层
│   ├── QdrantVectorStore:向量检索
│   ├── Neo4jGraphStore:知识图谱
│   └── SQLiteDocumentStore:结构化持久化
└── 嵌入服务层
    ├── DashScopeEmbedding:云端嵌入
    ├── LocalTransformerEmbedding:本地嵌入
    └── TFIDFEmbedding:轻量兜底

这个结构的好处是职责清晰:MemoryTool 面向 Agent 调用,MemoryManager 负责编排,具体记忆类型负责自己的存储、检索和评分。

2.2 RAG 系统架构

RAG 被设计成一条 pipeline,而不是一个庞大的 Agent:

复制代码
用户层:RAGTool 统一接口
  ↓
应用层:智能问答、搜索、知识库管理
  ↓
处理层:文档解析、Markdown 分块、向量化
  ↓
存储层:向量数据库、文档存储
  ↓
基础层:嵌入模型、LLM、数据库连接

RAG 的主要工程链路是:

复制代码
任意格式文档
→ MarkItDown 转换为 Markdown
→ 标题层次和段落语义分割
→ token 控制与 chunk overlap
→ 文本预处理和嵌入
→ 写入 Qdrant
→ 检索、构建上下文、LLM 生成答案

3. MemoryTool:让 Agent 拥有记忆

3.1 记忆生命周期

本章借鉴认知科学,把记忆过程拆成五步:

  1. 编码 Encoding:把感知到的信息转成可保存的结构。
  2. 存储 Storage:写入对应类型的记忆模块。
  3. 检索 Retrieval:根据查询找回相关记忆。
  4. 整合 Consolidation:把重要短期记忆提升为长期记忆。
  5. 遗忘 Forgetting:删除不重要、过期或超容量的信息。

这五步对应到工具层,就是 add/search/summary/stats/forget/consolidate 等操作。

3.2 基础用法

对应代码:01_MemoryTool_Basic_Operations.py

复制代码
from hello_agents.tools import MemoryTool

memory_tool = MemoryTool(
    user_id="demo_user",
    memory_types=["working", "episodic", "semantic", "perceptual"],
)

memory_tool.run({
    "action": "add",
    "content": "正在学习 HelloAgents 框架的记忆系统",
    "memory_type": "working",
    "importance": 0.7,
    "task_type": "learning",
})

memory_tool.run({
    "action": "search",
    "query": "记忆系统",
    "limit": 3,
})

memory_tool.run({"action": "summary", "limit": 5})
memory_tool.run({"action": "stats"})

MemoryTool 的统一入口是 execute(action, **kwargs) 或脚本中常用的 run({"action": ...})。它支持的主要动作如下:

动作 作用 常用参数
add 添加记忆 content, memory_type, importance, metadata
search 搜索记忆 query, limit, memory_type/memory_types, min_importance
summary 获取记忆摘要 limit
stats 获取统计信息
update 更新记忆 memory_id, 新内容或元数据
remove 删除指定记忆 memory_id
forget 按策略遗忘记忆 strategy, threshold, max_age_days
consolidate 短期记忆转长期记忆 from_type, to_type, importance_threshold
clear_all 清空记忆 谨慎使用

3.3 add:记忆编码

add 不只是保存一段文本,还会补齐会话 ID、时间戳、重要性、多模态信息和业务元数据。importance 默认 0.5,范围通常是 0 到 1,用来影响检索排序、整合和遗忘。

复制代码
# 工作记忆:当前任务上下文
memory_tool.execute(
    "add",
    content="用户刚才问了关于 Python 函数的问题",
    memory_type="working",
    importance=0.6,
)

# 情景记忆:具体事件
memory_tool.execute(
    "add",
    content="用户完成了第一个 Python 项目",
    memory_type="episodic",
    importance=0.8,
    event_type="milestone",
)

# 语义记忆:抽象知识
memory_tool.execute(
    "add",
    content="Python 是解释型、面向对象的编程语言",
    memory_type="semantic",
    importance=0.9,
    knowledge_type="factual",
)

# 感知记忆:多模态信息
memory_tool.execute(
    "add",
    content="用户上传了一张 Python 代码截图",
    memory_type="perceptual",
    importance=0.7,
    modality="image",
    file_path="./uploads/code_screenshot.png",
)

3.4 search:记忆检索

搜索支持按单一记忆类型或多个记忆类型过滤,也支持最低重要性阈值。

复制代码
# 全局搜索
memory_tool.execute("search", query="Python 编程", limit=5)

# 指定类型
memory_tool.execute(
    "search",
    query="学习进度",
    memory_type="episodic",
    limit=3,
)

# 多类型 + 重要性过滤
memory_tool.execute(
    "search",
    query="函数定义",
    memory_types=["semantic", "episodic"],
    min_importance=0.5,
)

检索的重点不是 "找到包含关键词的文本",而是把语义相似度、时间近因性、重要性、结构过滤等因素组合起来排序。

3.5 forget:选择性遗忘

遗忘机制模拟人类选择性遗忘,避免记忆无限增长。基础策略有三类:

复制代码
# 删除重要性低于阈值的记忆
memory_tool.execute("forget", strategy="importance_based", threshold=0.2)

# 删除超过指定天数的记忆
memory_tool.execute("forget", strategy="time_based", max_age_days=30)

# 容量接近上限时删除低价值记忆
memory_tool.execute("forget", strategy="capacity_based", threshold=0.3)

需要注意:生产系统中的 "遗忘" 不仅是节省空间,也涉及隐私、合规和数据生命周期管理。

3.6 consolidate:记忆整合

consolidate 把重要的短期记忆转为长期记忆。默认思路是把重要性超过阈值的 working 记忆提升为 episodic,也可以把情景记忆进一步抽象成语义记忆。

复制代码
# 重要工作记忆转为情景记忆
memory_tool.execute(
    "consolidate",
    from_type="working",
    to_type="episodic",
    importance_threshold=0.7,
)

# 重要情景记忆抽象为语义记忆
memory_tool.execute(
    "consolidate",
    from_type="episodic",
    to_type="semantic",
    importance_threshold=0.8,
)

整合的判断不能只看重要性。更合理的触发条件还应考虑:是否被多次访问、是否与长期目标相关、是否被用户显式要求记住、是否跨会话仍有价值、是否包含结构化知识。

3.7 MemoryManager:工具与底层记忆的分工

对应代码:02_MemoryTool_Architecture.py

MemoryTool 负责统一接口、参数规范化、会话元数据和结果格式化;MemoryManager 负责调用不同记忆类型的实现。这个分层避免让工具层直接关心 SQLite、Qdrant、Neo4j 或 embedding 细节。

复制代码
memory_tool = MemoryTool(
    user_id="demo_user",
    memory_types=["working", "semantic"],
)

只启用部分记忆类型是一个实用设计。例如本地轻量 demo 可以只开 workingsemantic;多模态应用再启用 perceptual;需要长期事件回顾时启用 episodic

4. 四种记忆类型

对应代码:03_WorkingMemory_Implementation.py06_Memory_Consolidation_Demo.py09_Memory_Types_Deep_Dive.py

类型 存什么 存储方式 检索重点 典型场景
工作记忆 working 当前会话、临时任务上下文 内存 + TTL + 容量限制 快速访问、时间衰减、关键词 / TF-IDF 混合 当前问题、刚刚上传的信息、短期状态
情景记忆 episodic 具体事件、交互经历、学习历程 SQLite + Qdrant 语义相似 + 时间近因性 + 会话过滤 "上次我问了什么""我什么时候完成了任务"
语义记忆 semantic 概念、事实、规则、长期知识 Qdrant + Neo4j 向量语义 + 图关系推理 用户偏好、领域概念、知识关联
感知记忆 perceptual 图像、音频、文档等多模态感知数据 分模态向量集合 同模态 / 跨模态检索 + 时间近因性 截图、语音、图片、PDF 特征

4.1 工作记忆

工作记忆强调速度和短期性,默认容量有限,带 TTL 自动清理。它适合保存当前任务状态,不适合保存长期知识。

评分思路:

复制代码
base_relevance = TF-IDF/向量相似度 * 0.7 + 关键词匹配 * 0.3
final_score = base_relevance * 时间衰减 * (0.8 + importance * 0.4)

如果向量检索不可用,系统可以退回关键词匹配,保证基础可用性。

4.2 情景记忆

情景记忆保存具体事件,重点是 "发生了什么、何时发生、在哪个会话中发生"。它适合回顾学习历程、任务里程碑、用户历史操作。

评分公式:

复制代码
score = (向量相似度 * 0.8 + 时间近因性 * 0.2) * (0.8 + importance * 0.4)

情景记忆强调时间近因性,是因为事件天然与时间顺序有关。用户问 "最近一次""上次""今天做了什么" 时,时间因素直接影响答案质量。

4.3 语义记忆

语义记忆保存抽象知识、实体、概念和关系。它的关键不是 "什么时候发生",而是 "概念之间如何关联"。因此它使用向量检索加图检索的混合策略。

评分公式:

复制代码
score = (向量相似度 * 0.7 + 图相似度 * 0.3) * (0.8 + importance * 0.4)

图检索权重虽然只有 0.3,但非常关键。它能支持多跳关系、路径查询、实体关联等纯向量检索不擅长的问题。例如 "张三学习了哪些与 RAG 相关的概念" 不仅需要匹配文本,还需要沿着 "用户 - 学习 - 概念 - 技术领域" 的关系找答案。

4.4 感知记忆

感知记忆支持文本、图像、音频等模态。它通常为不同模态使用独立向量集合,避免不同编码器维度不一致。

评分公式:

复制代码
score = (向量相似度 * 0.8 + 时间近因性 * 0.2) * (0.8 + importance * 0.4)

时间近因性通常采用指数衰减。这样可以让最近上传的截图、音频或文档在检索中更靠前,但又不会完全抹掉旧信息的价值。

5. RAGTool:知识检索增强

对应代码:04_RAGTool_MarkItDown_Pipeline.py05_RAGTool_Advanced_Search.py07_RAGTool_Intelligent_QA.py10_RAG_Pipeline_Complete.py

5.1 RAG 的基本流程

RAG 分为两个阶段:

  1. 数据准备阶段:提取外部文档内容,切分成片段,向量化后写入数据库。
  2. 应用阶段:接收用户问题,检索相关片段,构建上下文,让 LLM 基于证据回答。

基础用法:

复制代码
from hello_agents.tools import RAGTool

rag_tool = RAGTool(
    knowledge_base_path="./knowledge_base",
    collection_name="test_collection",
    rag_namespace="test",
)

rag_tool.execute(
    "add_text",
    text="RAG 是结合信息检索和文本生成的 AI 技术。",
    document_id="rag_concept",
)

rag_tool.execute(
    "search",
    query="RAG 的作用是什么",
    limit=3,
    min_score=0.1,
)

rag_tool.execute("stats")

在完整应用里,更常用的是 add_documentask

复制代码
rag_tool.run({
    "action": "add_document",
    "file_path": "./docs/tutorial.pdf",
    "chunk_size": 1000,
    "chunk_overlap": 200,
})

rag_tool.run({
    "action": "ask",
    "question": "文档中如何解释 RAG?",
    "limit": 5,
    "enable_advanced_search": True,
    "enable_mqe": True,
    "enable_hyde": True,
})

5.2 文档转换:MarkItDown

RAGTool 使用 MarkItDown 把多种文件统一转成 Markdown。这样后续处理可以只面对一种结构化文本格式。

支持的类型包括:

  • PDF、Word、Excel、PowerPoint
  • 图片 OCR
  • 音频转录
  • TXT、CSV、JSON、XML、HTML
  • Python、JavaScript 等代码文件

统一成 Markdown 的价值在于:标题层次、段落、列表和代码块可以成为分块依据,而不是粗暴按字符数切割。

5.3 智能分块

本章的分块不是简单固定长度切片,而是结构感知的流程:

复制代码
Markdown 文本
→ 标题层次解析
→ 段落语义分割
→ token 计算
→ chunk_size 控制
→ chunk_overlap 保持连续性
→ 准备嵌入

关键点:

  • 标题路径 heading_path 可作为元数据保存,帮助回答时定位上下文。
  • 分块不能太大,否则检索粒度粗、上下文噪声多。
  • 分块不能太小,否则语义不完整,容易丢失上下文。
  • chunk_overlap 用于保留跨块信息,但过大又会增加重复内容和存储成本。
  • 中英文混合文本需要特殊 token 估算,不能只按英文空格切词。

5.4 嵌入模型与向量存储

本章给出三类嵌入方案:

方案 优点 缺点 适用场景
百炼 API / DashScope 语义质量较好、维护成本低 需要网络和 API 成本 生产应用、中文语义要求高
本地 Transformer 可离线、数据不出本地 依赖模型部署和算力 私有化部署、内网环境
TF-IDF 简单、快、无模型依赖 语义能力弱,只擅长字面匹配 兜底方案、小规模 demo

向量数据库使用 Qdrant,关键是通过 rag_namespace 做命名空间隔离,并将 memory_type=rag_chunkis_rag_data=Truedata_source=rag_pipeline 等元数据写入向量,方便过滤检索范围。

5.5 高级检索:MQE 与 HyDE

基础检索常见问题是 "用户问法" 和 "文档写法" 不一致。第 8 章实现了两种补强策略。

MQE Multi-Query Expansion:让 LLM 把原始问题扩展成多个语义等价或互补的问题,再并行检索并合并结果。

适合:

  • 用户提问模糊。
  • 同一概念有多种叫法。
  • 需要提高召回率。

HyDE Hypothetical Document Embeddings:先让 LLM 生成一段 "假设答案",再用这段答案去检索真实文档。它的核心是 "用答案形态去匹配答案型文档",缓解问题句和文档陈述句之间的语义鸿沟。

适合:

  • 专业领域问题。
  • 问题很抽象,直接检索命中率低。
  • 文档内容更像解释性段落,而不是问句。

组合策略:

复制代码
原始查询
→ MQE 生成多个扩展查询
→ HyDE 生成假设答案文档
→ 对每个查询执行向量检索
→ 扩大候选池
→ 按 memory_id 去重
→ 按最高分排序
→ 返回 top-k

工程取舍:

  • 普通查询:优先开启 MQE。
  • 专业复杂查询:MQE + HyDE 同时开启。
  • 性能敏感场景:只用基础检索或只开 MQE。
  • 高准确问答:检索后可加重排序、引用来源和答案质量评估。

6. Memory 与 RAG 的协同

对应代码:08_Agent_Tool_Integration.py

MemoryTool 和 RAGTool 都是标准工具,可以挂到同一个 Agent:

复制代码
from hello_agents import SimpleAgent, HelloAgentsLLM, ToolRegistry
from hello_agents.tools import MemoryTool, RAGTool

agent = SimpleAgent(
    name="智能助手",
    llm=HelloAgentsLLM(),
    system_prompt="你是一个有记忆和知识检索能力的 AI 助手",
)

registry = ToolRegistry()
registry.register_tool(MemoryTool(user_id="user123"))
registry.register_tool(RAGTool(knowledge_base_path="./knowledge_base"))
agent.tool_registry = registry

两者协作的典型模式:

  • 学习新资料:RAG 存文档,Memory 记录 "用户加载了什么资料"。
  • 提问回答:RAG 检索资料生成答案,Memory 记录问题、学习轨迹和重要结论。
  • 复盘学习:Memory 回顾用户历史问题和笔记,RAG 补充知识细节。
  • 制定计划:RAG 提供领域知识,Memory 提供用户进度和偏好。

7. 智能文档问答助手案例

对应代码:11_Q&A_Assistant.py

第 8.4 节把 MemoryTool 和 RAGTool 组合成一个 Gradio Web 应用,核心类是 PDFLearningAssistant。它的职责不是重新实现底层检索或记忆,而是把工具编排成一个学习闭环。

核心结构:

复制代码
class PDFLearningAssistant:
    def __init__(self, user_id="default_user"):
        self.user_id = user_id
        self.session_id = f"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
        self.memory_tool = MemoryTool(user_id=user_id)
        self.rag_tool = RAGTool(rag_namespace=f"pdf_{user_id}")
        self.stats = {
            "session_start": datetime.now(),
            "documents_loaded": 0,
            "questions_asked": 0,
            "concepts_learned": 0,
        }

关键方法:

方法 RAGTool 作用 MemoryTool 作用
load_document(pdf_path) add_document 处理 PDF、分块、入库 记录 "加载文档" 事件到情景记忆
ask(question) ask 执行高级检索和问答 工作记忆记录当前问题,情景记忆记录问答事件
add_note(content, concept) 不直接用 RAG 保存学习笔记到语义记忆
recall(query) 不直接用 RAG 搜索历史学习记忆
get_stats() 可读取 RAG 统计 汇总学习过程指标
generate_report() 读取知识库状态 读取记忆摘要,生成学习报告

这个案例的关键不是 UI,而是数据流:

复制代码
上传 PDF
→ RAGTool 转换、分块、向量化、入库
→ MemoryTool 记录加载事件
→ 用户提问
→ RAGTool 执行 MQE/HyDE/向量检索/答案生成
→ MemoryTool 记录问题和学习事件
→ 用户写笔记
→ MemoryTool 写入语义记忆
→ 统计和报告

8. 实践注意事项

  1. 不要把所有信息都塞进工作记忆。工作记忆应该短小、即时、可丢弃。
  2. 情景记忆适合事件,不适合抽象规则。比如 "用户今天问了 RAG" 是情景,"用户偏好中文解释" 更像语义。
  3. 语义记忆要注意实体关系质量。自动抽取会出错,生产中应加入人工校验或置信度机制。
  4. RAG 的效果高度依赖分块和嵌入模型。模型再强,分块糟糕也会检索失败。
  5. MQE 和 HyDE 会增加 LLM 调用成本。只有在召回不足或问题复杂时才值得开启。
  6. 多用户应用必须做数据隔离。至少需要 user_idsession_idrag_namespace 和数据库层面的过滤。
  7. 遗忘敏感信息时,不能只删业务表。向量库、图数据库、缓存、日志、备份都要纳入删除范围。

9. 习题解析

题 1:四种记忆类型、评分机制与健康助手设计

问题一:为什么情景记忆更强调时间近因性,而语义记忆更强调图检索?

情景记忆保存的是事件。事件的价值往往和时间顺序强相关,例如 "上次对话""最近一次学习""昨天上传的文档"。因此它的评分把时间近因性纳入权重:

复制代码
情景记忆 = (向量相似度 * 0.8 + 时间近因性 * 0.2) * 重要性权重

语义记忆保存的是概念、规则和知识关系。知识不一定因为 "新" 就更正确,真正重要的是概念之间的关联。例如 "RAG 和向量数据库的关系""用户偏好与推荐策略的关系"。因此语义记忆更强调图检索:

复制代码
语义记忆 = (向量相似度 * 0.7 + 图相似度 * 0.3) * 重要性权重

问题二:个人健康管理助手如何组合四种记忆?

记忆类型 健康助手中的用途 示例
工作记忆 当前对话状态、当天临时数据 "用户刚输入今天午餐:米饭、鸡胸肉、沙拉"
情景记忆 带时间戳的健康事件 "2026-05-19 晚上跑步 5 公里,睡眠 7 小时"
语义记忆 长期健康偏好、规则和知识 "用户乳糖不耐受""减脂期每日蛋白目标 120g"
感知记忆 手环数据、体重秤图片、餐盘照片 食物照片估算热量,睡眠曲线截图,运动轨迹图

推荐流程:

复制代码
用户上传饮食/运动/睡眠数据
→ 工作记忆保存当前输入
→ 情景记忆记录每天事件
→ 语义记忆维护长期偏好、禁忌、目标
→ 感知记忆处理图片、音频、设备截图
→ 定期整合:把连续多天模式抽象为长期健康建议

问题三:重要工作记忆何时整合为长期记忆?

可设计自动触发条件:

  • 重要性超过阈值,如 importance >= 0.75
  • 被用户明确要求 "记住"。
  • 在多个会话中反复出现。
  • 与长期目标相关,如健康、学习、项目计划。
  • 被频繁检索或引用。
  • 包含稳定偏好或关键事实,而不是一次性临时状态。

示例策略:

复制代码
def should_consolidate(memory):
    return (
        memory.importance >= 0.75
        or memory.metadata.get("user_explicit_save") is True
        or memory.metadata.get("access_count", 0) >= 3
        or memory.metadata.get("goal_related") is True
    )

题 2:RAG 分块、MQE/HyDE 对比与嵌入模型选型

问题一:无明确标题结构的文档如何优化分块?

小说、法律条文、聊天记录等文档不一定有 Markdown 标题。此时不能只依赖 # / ## / ###,应改为 "语义边界 + 长度约束" 的混合分块。

可用边界:

  • 段落边界:空行、自然段。
  • 句子边界:句号、问号、分号、编号。
  • 结构边界:法律条文的 "第 x 条"、合同的 "甲方 / 乙方"、小说章节中的场景转换。
  • 语义边界:相邻段落 embedding 相似度明显下降。
  • 长度边界:达到 chunk_size 后优先在最近的自然边界切分。

算法草案:

复制代码
def semantic_chunk(paragraphs, embed, max_tokens=800, overlap_tokens=120, drop_threshold=0.55):
    chunks = []
    current = []
    current_tokens = 0
    prev_vec = None

    for para in paragraphs:
        vec = embed(para)
        tokens = approx_token_len(para)

        semantic_break = False
        if prev_vec is not None:
            semantic_break = cosine(prev_vec, vec) < drop_threshold

        too_long = current_tokens + tokens > max_tokens

        if current and (semantic_break or too_long):
            chunks.append("\n\n".join(current))
            current = keep_tail_by_tokens(current, overlap_tokens)
            current_tokens = sum(approx_token_len(x) for x in current)

        current.append(para)
        current_tokens += tokens
        prev_vec = vec

    if current:
        chunks.append("\n\n".join(current))

    return chunks

问题二:基础检索、MQE、HyDE 的效果差异。

以 "技术文档问答" 为例:

方法 优点 缺点 适用场景
基础向量检索 快、成本低、稳定 用户问法和文档写法差异大时召回不足 明确术语查询,如 "Transformer 注意力机制"
MQE 扩展多种问法,提高召回 多一次 LLM 调用,可能引入偏题扩展 模糊问题,如 "怎么提升模型效果"
HyDE 用假设答案贴近文档语义,适合专业问答 假设答案可能带偏检索,成本更高 专业复杂问题,如 "为什么注意力机制适合长距离依赖"

经验结论:

  • 查定义、查术语:基础检索通常够用。
  • 用户表达不清:优先 MQE。
  • 问题和答案语义形态差异明显:用 HyDE。
  • 高质量问答:MQE + HyDE + 重排序 + 引用来源。

问题三:三种嵌入方案选型。

维度 百炼 API 本地 Transformer TF-IDF
准确性 通常较高,中文语义较强 取决于模型,合适模型效果好 语义弱,偏关键词
速度 网络延迟影响明显 本地推理稳定,可批处理 很快
成本 有 API 成本 有机器和部署成本 几乎无成本
离线 不适合 适合 适合
维护 中等,需要模型管理

选型建议:

  • 生产中文知识库:优先百炼 API 或同等级云端 embedding。
  • 私有化 / 敏感数据:本地 Transformer。
  • Demo、兜底、关键词强匹配:TF-IDF。
  • 最稳妥的工程方案:统一 embedding 接口,按可用性降级:云端 API → 本地模型 → TF-IDF。

题 3:智能遗忘、记忆归档与敏感信息删除

问题一:设计智能遗忘策略。

基础遗忘只看重要性、时间或容量,容易误删 "旧但关键" 的记忆。更合理的是综合评分:

复制代码
retention_score =
    importance * 0.40
  + normalized_access_frequency * 0.25
  + recency_score * 0.20
  + goal_relevance * 0.10
  + user_pin * 0.05

retention_score 低于阈值时进入遗忘候选;如果只是长期不用但仍可能有价值,应归档而不是直接删除。

示例实现思路:

复制代码
def retention_score(memory, now):
    age_days = (now - memory.timestamp).days
    recency = math.exp(-0.05 * age_days)
    access = min(memory.metadata.get("access_count", 0) / 10, 1.0)
    goal = 1.0 if memory.metadata.get("goal_related") else 0.0
    pinned = 1.0 if memory.metadata.get("pinned") else 0.0

    return (
        memory.importance * 0.40
        + access * 0.25
        + recency * 0.20
        + goal * 0.10
        + pinned * 0.05
    )

问题二:记忆归档机制如何设计?

归档不是删除,而是冷热分层:

  • 热存储:工作记忆、近期情景记忆、高频语义记忆,保留在内存、Qdrant、Neo4j 活跃集合中。
  • 温存储:低频但仍可能检索的长期记忆,降低检索优先级。
  • 冷存储:长期不用但有价值的记忆,转移到压缩文件、对象存储、归档表或低成本数据库。

与四类记忆集成:

记忆类型 归档策略
工作记忆 一般不归档,过期后整合或删除
情景记忆 超过时间窗口后归档原始事件,保留摘要和索引
语义记忆 保留核心实体关系,归档低置信或低访问知识
感知记忆 原始大文件进冷存储,保留缩略图、向量和元数据

恢复机制:

复制代码
用户查询
→ 热存储无结果或低置信
→ 搜索归档索引
→ 命中后恢复到温/热存储
→ 更新 access_count 和 last_accessed

问题三:敏感信息删除是否只删数据库即可?

不够。敏感数据可能存在多个副本:

  • SQLite 文档表。
  • Qdrant 向量与 payload。
  • Neo4j 实体和关系。
  • embedding 缓存。
  • LLM 请求日志。
  • 应用日志。
  • 备份和归档文件。

彻底删除方案:

  1. 为每条记忆维护全局 memory_id 和数据血缘索引。
  2. 删除 SQLite 原文记录。
  3. 删除 Qdrant 中对应向量和 payload。
  4. 删除 Neo4j 中由该记忆创建的实体关系;若实体被其他记忆引用,则只删除该来源边。
  5. 清理 embedding 缓存、检索缓存和报告文件。
  6. 对日志做脱敏,避免记录原始敏感文本。
  7. 对备份执行到期删除或加密擦除策略。
  8. 生成删除审计记录,但审计记录不能包含敏感原文。

题 4:智能学习助手中的 RAG 与 Memory 协同

问题一:什么时候优先 RAG,什么时候优先 Memory?

优先 RAG:

  • 用户问文档内容、专业知识、外部事实。
  • 问题需要引用来源。
  • 问题涉及最新资料或上传文件。
  • 用户问 "文档里怎么说""这篇 PDF 的结论是什么"。

优先 Memory:

  • 用户问自己的历史行为、学习进度、偏好。
  • 问题和会话上下文强相关。
  • 用户问 "我之前问过什么""我学到哪里了"。
  • 需要个性化建议。

智能路由机制可以先做意图分类,再决定检索路径:

复制代码
def route_query(question):
    if mentions_document(question) or asks_external_knowledge(question):
        return "rag"
    if asks_user_history(question) or asks_preference(question):
        return "memory"
    if asks_personalized_recommendation(question):
        return "hybrid"
    return "hybrid"

更稳的方案是并行检索后再融合:

复制代码
问题
→ 意图识别
→ RAG 检索外部知识
→ Memory 检索用户状态
→ 按问题类型加权
→ 构建最终上下文
→ LLM 生成回答

问题二:如何扩展学习报告?

当前 generate_report() 主要统计文档数、提问数、笔记数和记忆摘要。更智能的报告应包含:

  • 学习轨迹:按时间整理加载文档、提问、笔记、复习记录。
  • 知识点覆盖:从语义记忆中抽取概念,统计学习频次。
  • 知识盲点:识别多次提问但低置信回答、重复搜索、错误笔记或没有形成笔记的主题。
  • 学习节奏:分析会话时长、问题密度、复习间隔。
  • 推荐内容:用 RAG 搜索相邻主题,用 Memory 匹配用户目标。
  • 行动建议:输出下一步学习计划。

需要用到的能力:

能力 用途
情景记忆 还原学习时间线
语义记忆 抽取概念掌握情况
工作记忆 汇总当前会话任务
RAG 检索 推荐相关文档片段
MQE/HyDE 对薄弱知识点扩展检索

问题三:多用户 Web 服务如何隔离数据?

Qdrant 隔离方案:

  • 简单方案:同一 collection,payload 中写入 user_idrag_namespace,每次检索加过滤条件。
  • 强隔离方案:按租户或用户创建 collection,例如 rag_user_123
  • 折中方案:按组织 / 租户 collection,用户级 payload 过滤。

Neo4j 隔离方案:

  • 所有节点和边写入 user_idtenant_id
  • 查询时强制加用户过滤。
  • 对高隔离要求的租户使用独立 database 或独立实例。
  • 关系边也要带来源记忆 ID,避免跨用户共享关系污染。

性能优化:

  • user_idrag_namespacememory_type 建过滤索引。
  • 用户集合过多时避免每人一个 collection,可按租户合并。
  • 热门知识库可共享只读索引,用户私有记忆单独存储。
  • 检索时先过滤命名空间,再做向量相似度。
  • 缓存高频查询,但缓存键必须包含用户和命名空间。

题 5:语义记忆、知识图谱质量与图检索价值

问题一:自动实体关系抽取的准确性如何评估?

自动抽取会受文本质量、语言歧义、分词、实体边界和关系表达影响。常见错误包括:

  • 实体边界错误:把 "向量数据库 Qdrant" 拆成错误实体。
  • 实体类型错误:把产品名识别成人名或组织。
  • 关系方向错误:把 "A 依赖 B" 抽成 "B 依赖 A"。
  • 隐含关系缺失:文本没有显式动词时漏掉关系。
  • 同义实体未合并:RAG检索增强生成Retrieval-Augmented Generation 被当成三个概念。

质量评估机制:

复制代码
抽取结果
→ 实体置信度评分
→ 关系置信度评分
→ 与 schema/ontology 校验
→ 同义词归一化
→ 冲突检测
→ 抽样人工审核
→ 低置信结果进入待确认区

可量化指标:

  • 实体 precision /recall。
  • 关系 precision /recall。
  • 同义实体合并准确率。
  • 图中孤立节点比例。
  • 关系冲突数量。
  • 人工审核通过率。

问题二:设计一个利用 Neo4j 多跳关系的查询场景。

场景:学习助手回答 "我学习 RAG 还缺哪些前置知识?"

图谱结构:

复制代码
(User)-[:LEARNED]->(Concept)
(Concept)-[:REQUIRES]->(Prerequisite)
(Concept)-[:RELATED_TO]->(Concept)
(Document)-[:COVERS]->(Concept)

查询逻辑:

复制代码
MATCH (u:User {id: $user_id})-[:LEARNED]->(c:Concept {name: "RAG"})
MATCH (c)-[:REQUIRES*1..2]->(pre:Concept)
WHERE NOT (u)-[:LEARNED]->(pre)
RETURN pre.name, pre.importance
ORDER BY pre.importance DESC

纯向量检索只能找 "和 RAG 语义相似的文本",但很难稳定回答 "缺哪些前置知识"。图查询可以沿着明确关系做推理。

问题三:混合检索相比纯向量检索在哪些查询中提升明显?

图检索提升明显的查询类型:

  • 关系型查询:谁依赖谁、谁属于谁、谁影响谁。
  • 多跳推理:A 的前置知识的相关应用是什么。
  • 路径查找:从 "Python 基础" 到 "RAG 应用" 需要经过哪些知识点。
  • 约束查询:找出用户学过但未复习、且与当前目标相关的概念。
  • 实体消歧:区分同名实体或缩写。

例子:

复制代码
查询:我已经学过 embedding 和 Qdrant,下一步学习 RAG 还缺什么?
纯向量检索:可能返回几段 RAG 介绍文本。
图检索:可以根据 prerequisites 找出 chunking、retrieval、prompt construction、reranking 等缺口。
混合检索:先用图找知识缺口,再用向量找每个缺口的解释文档。

结论:向量检索适合 "语义相似",图检索适合 "结构关系",混合策略适合需要既理解语义又利用知识结构的场景。

相关推荐
Fabarta技术团队5 小时前
模数共振・智能就位|枫清科技以企业级 AI Agent,响应国家 “智能体即服务” 战略
人工智能·科技
Terrence Shen5 小时前
Agent面试八股文(系列之三)
人工智能·大模型·agent·rag·智能体·大模型技术
十六年开源服务商5 小时前
2026网站建设方案内容审批避坑指南
大数据·人工智能
DisonTangor5 小时前
【上篇】SenseNova-U1:基于NEO-unify架构统一多模态理解与生成
人工智能·ai作画·开源·aigc
团象科技5 小时前
跨境业务频繁卡顿遇瓶颈?谷歌云AI算力补齐链路短板破局增收
大数据·人工智能·深度学习
AI医影跨模态组学5 小时前
Eur Radiol 哈尔滨医科大学附属肿瘤医院王瑞涛团队:多模态深度学习探究肿瘤与内脏脂肪对结直肠癌隐匿性腹膜转移的影响
人工智能·深度学习·论文·医学影像·影像组学
Keano Reurink5 小时前
AI内容检测:用SERP对比识别搜索引擎眼中的“优质内容“
人工智能·搜索引擎·chatgpt
easy_coder5 小时前
Kubernetes 域名解析问题排查实战:短名为什么有时能解析,有时不行
人工智能·kubernetes·云计算
机器学习之心5 小时前
扩散模型 + Transformer 回归预测:用生成式AI增强小样本回归
人工智能·transformer·扩散模型