MetaSearch

深度迭代检索增强系统

一个教学项目,带你从零开始,利用大语言模型构建一套融合多种先进技术的RAG系统,体验智能信息探索的魅力。

MetaSearch 是什么?

MetaSearch 是一个基于深度迭代检索原理构建的先进检索增强生成 (RAG) 系统。它通过逐步精炼搜索、融合多种检索技术,并利用大语言模型 (LLM) 来提供全面且上下文丰富的答案。

核心特性

模块化 RAG 框架

遵循社区标准,学习使用清晰、模块化的架构构建 LLM 项目的最佳实践。

深度迭代检索

实现前沿的 RAG 算法,通过多轮搜索迭代深入探索信息。

混合检索融合

结合向量搜索、关键词搜索 (TF-IDF) 和知识图谱检索,实现更广泛的覆盖。

智能查询扩展

利用 LLM 动态生成子查询,实现知识探索的广度和深度。

自适应搜索控制

基于新发现信息的比例决定是否继续搜索,优化效率。

多样性重排序

利用最大边际相关性 (MMR) 平衡相关性和多样性,提供更全面的结果。

系统架构

核心组件

文档处理

将原始文档分割成带有上下文和摘要的可管理文本块。

索引构建

构建向量、TF-IDF 和知识图谱索引以实现高效检索。

检索模块

结合多种检索方法(向量、关键词、图谱)查找相关文档。

查询扩展

使用 LLM 基于检索到的信息生成新的子查询。

深度 RAG 编排器

协调迭代检索过程并综合生成最终答案。

工作流程

用户查询输入
初始检索 (混合)
生成子查询 (LLM)
迭代检索与扩展
重排序与综合
生成最终答案 (LLM)

项目目录结构

MetaSearch/
├── config/           # 配置文件 (YAML)
├── data/             # 数据目录 (原始, 处理后, 索引)
│   ├── raw/          # 原始数据
│   ├── processed/    # 处理后的数据
│   └── indexes/      # 索引文件
├── deepsearch/       # 核心库代码
│   ├── indexing/     # 索引逻辑 (向量, tfidf, 图谱)
│   ├── llm/          # LLM 接口封装
│   ├── preprocessing/# 文档解析与分块
│   ├── rag/          # RAG 流水线实现 (标准, 深度)
│   ├── retrieval/    # 检索策略与重排序
│   └── utils/        # 工具函数
├── scripts/          # 辅助脚本 (下载, 处理)
├── app.py            # 主应用入口点
├── requirements.txt  # 项目依赖
└── README.md         # 项目文档

快速开始指南

技术深潜

文档处理与分块

原始文档被解析并分割成重叠的块。每个块存储:

  • content: 块的主要文本。
  • chunk_id: 唯一标识符。
  • parent_content: 可选的更大上下文块。
  • abstract: LLM 生成的摘要 (可选)。
  • 元数据: 源文档、页码等。
# 示例配置 (config/config.yaml)
processing:
  chunk_size: 512      # 每个块的目标大小
  overlap_size: 64     # 连续块之间的重叠大小
  generate_abstract: true # 是否生成摘要

混合索引

多个索引捕获数据的不同方面:

  1. 向量索引 (FAISS): 使用嵌入 (例如 BCE-Embedding) 进行语义相似性搜索。
  2. TF-IDF 索引: 经典的基于关键词的检索,适用于特定术语。
  3. 知识图谱 (可选): 提取实体和关系以进行结构化查询。

检索模块融合来自已启用索引的结果。

查询扩展机制

迭代地扩展搜索范围:

  1. LLM 从检索到的结果中提取关键搜索词/子问题。
  2. 计算潜在子查询与原始查询的相关性分数。
  3. 汇集所有迭代中的候选子查询。
  4. 根据相关性和发现新信息的潜力选择得分最高的 k 个子查询。
  5. 这些成为下一次检索迭代的输入。

深度迭代检索循环

核心引擎在一个循环中运行:

  1. 从初始用户查询开始。
  2. 执行标准 RAG (检索、重排序、生成响应片段)。
  3. 计算信息增长率 (IGR): `len(new_chunk_ids) / len(existing_chunk_ids)`。
  4. 如果 IGR < 阈值或达到最大迭代次数,则停止。
  5. 否则,使用查询扩展为下一个循环生成新的子查询。
  6. 最后,将所有收集到的知识综合成一个最终的、全面的答案。
# 示例配置 (config/config.yaml)
deepsearch:
  max_iterations: 3          # 最大检索循环次数
  growth_rate_threshold: 0.1 # 如果发现的新信息少于 10%,则停止
  extend_query_num: 3        # 每次迭代的子查询数量

工作流程示例: "明朝内阁制度"

迭代 1

  1. 输入查询: "明朝内阁制度"
    • 初始知识库: 空
    • 现有块 ID: 空集合
  2. 标准 RAG 执行:
    • 检索相关块 (例如 ID: {101, 102, 103, 104, 105})。
    • 生成初始响应片段: "明朝内阁起源于永乐年间..."
    • 将片段添加到知识库。
    • 更新现有 ID: {101, 102, 103, 104, 105}
  3. 计算 IGR: 5 (新) / 1 (总计,概念上) = 5.0。由于 5.0 > 0.1 (阈值),继续。
  4. 扩展查询:
    • LLM 分析片段,建议子查询: ["大学士", "内阁权力", "张居正改革", ...]。
    • 为下次迭代选择前 3 个相关子查询: 例如 ["明朝大学士", "明朝内阁的演变", "内阁与皇权"]。

迭代 2

  1. 输入查询: ["明朝大学士", "明朝内阁的演变", "内阁与皇权"]
  2. 标准 RAG 执行 (针对每个子查询):
    • 为每个查询检索块 (例如发现的新 ID: {201, 202, 203, 204})。
    • 为每个子查询生成响应片段。
    • 将片段添加到知识库。
    • 更新现有 ID: {101, 102, ..., 105, 201, ..., 204} (总共: 9)
  3. 计算 IGR: 4 (新) / 5 (现有) = 0.8。由于 0.8 > 0.1,可能继续 (取决于最大迭代次数)。
  4. 扩展查询 (如果继续): 生成并选择下一组子查询。

最终答案综合

  1. 聚合和格式化知识:
    • 收集所有迭代中生成的所有响应片段。
    • 使用重排序模型,根据与 *原始* 查询的相关性对所有收集到的块/片段进行重新排序。
  2. 生成综合答案:
    • 构建最终提示,包括原始查询和经过排序、聚合的知识。
    • 使用 LLM 生成一个连贯、结构化的最终答案,整合收集到的多样化信息。

建议学习路径

初学者路径

  1. 运行系统 (app.py --interactive) 查看实际效果。
  2. 阅读 app.py: 理解初始化和主要的 RAG 调用流程。
  3. 探索 deepsearch/preprocessing/: 文档是如何加载和分块的?
  4. 学习 deepsearch/indexing/vector_index.py: 基本的向量索引创建和搜索。
  5. 查看 deepsearch/llm/: 代码如何与 LLM (本地或 API) 交互?
  6. 检查 deepsearch/rag/standard_rag.py: 基础的“检索-生成”流水线。

进阶路径

  1. 深入 deepsearch/rag/deep_rag.py: 理解迭代循环、IGR 和查询扩展逻辑。
  2. 学习 deepsearch/retrieval/: 探索混合检索和 MMR 重排序。
  3. 比较 deepsearch/indexing/ 中不同的索引实现。
  4. 分析 deepsearch/rag/query_expansion.py 中的查询扩展实现。
  5. 尝试调整 config/config.yaml 中的参数 (迭代次数、阈值、模型) 并观察变化。
  6. 尝试添加新的文档类型解析器或自定义检索策略。

常见问题解答 (FAQ)

加入社区

MetaSearch 是一个开源教育项目。欢迎各种形式的贡献!

发现 Bug?

报告您遇到的问题,帮助改进项目。

报告 Issue

有新想法?

通过贡献代码分享您的创新和改进。

提交 PR

喜欢这个项目?

点亮星星表示支持,并帮助他人发现它!

GitHub Star

欢迎您的 Forks 和 PR!✨