内容
# 混合PDF + OCR检索流程(Hybrid PDF + OCR Retrieval Pipeline)
一个为复杂企业文档构建的模块化、生产级别的增强检索生成(RAG)系统。它协调了布局感知的PDF解析、混合分层分块、密集/稀疏检索以及基于Gemini的答案生成,使用模型上下文协议(MCP)。
---
## 当前状态
* 第一阶段:PDF解析MCP ✅ (已完成)
* 第二阶段:分块流程 ✅ (已完成)
* 第三阶段:嵌入流程 ✅ (已完成)
* 第四阶段:Qdrant集成 ✅ (已完成)
* 第五阶段:文档摄入MCP ✅ (已完成)
* 第六阶段:检索MCP ✅ (已完成)
* 第第七阶段:Gemini RAG ✅ (已完成)
* 第八阶段:文档过滤 ✅ (已完成)
* 第九阶段:重复保护 ✅ (已完成)
* 第十阶段:混合检索(密集+BM25) ✅ (已完成)
* 第十一阶段:重新排序 🚧 (计划中)
* 第十二阶段:OCR MCP 🚧 (计划中)
* 第十三阶段:表格提取MCP 🚧 (计划中)
* 第十四阶段:布局分析MCP 🚧 (计划中)
当前发布版本:**RAG V1.0(启用混合检索)**
---
## 问题陈述
传统的RAG流程在处理现实世界中的企业文档时经常遇到困难,通常由于以下原因而失败:
* **多列布局**导致文本提取顺序错误。
* **表格和图表**丢失其空间表示。
* **扫描/低质量PDF**需要OCR集成。
* **结构噪声**(页眉、页脚、页码)污染语义嵌入。
* **关键词与语义不匹配**,其中确切的术语/首字母缩写被密集模型忽略,或者概念主题被基于关键词的匹配器忽略。
该流程保留布局结构,过滤掉结构噪声,支持基于元数据的过滤,并实现混合检索,使用互惠排名融合(RRF)检索最相关的上下文块。
---
## 系统架构
### 查询和检索流程
检索服务器通过并行执行语义搜索和BM25搜索,然后使用互惠排名融合(RRF)融合结果。
```mermaid
flowchart TB
U[用户查询] --> RM[检索MCP]
subgraph 并行检索
RM --> DR[密集语义搜索\nBAAI/bge-base-en-v1.5]
RM --> BR[稀疏关键词搜索\nrank-bm25 / Qdrant滚动载荷]
end
DR --> RRF[RRF融合\nk = 60]
BR --> RRF
RRF --> RC[最相关的块\n带有章节元数据]
RC --> GR[Gemini RAG\ngemini-2.5-flash]
GR --> GA[生成的答案\n带有引用]
```
### 文档摄入流程
文档经过布局提取、逐页混合分块、嵌入和确定性更新。
```mermaid
flowchart TB
DU[PDF上传] --> DIM[文档摄入MCP]
DIM --> VAL[验证和重复检查]
VAL --> PP[PDF解析器\nPyMuPDF]
PP --> HC[混合分层分块\n递归 + 滑动上下文窗口]
HC --> FLT[噪声过滤器\n块过滤器]
FLT --> EG[嵌入生成\n混合嵌入器]
EG --> QV[Qdrant向量存储\n确定性MD5点ID]
```
---
## 关键功能和能力
### 1. 高级摄入和布局感知解析
* **布局解析**:提取元数据、总页数和文本层次结构。
* **混合分层分块**:
* 使用结构化标题检测(`r"(\d+(?:\.\d+)?\s+.+)"`)按章节分块文本。
* 生成**基本块**(递归字符文本分割器)以及**上下文块**(滑动窗口合并相邻块以保留上下文)。
* **噪声过滤**:自动丢弃页眉、页脚、“目录”和短块(< 50字符)。
### 2. 双引擎检索和融合
* **密集语义检索**:采用`BAAI/bge-base-en-v1.5`嵌入(768维,余弦距离)以捕捉概念相似性。
* **稀疏关键词检索**:采用`BM25Okapi`对从Qdrant载荷中滚动的本地文本文档进行精确的首字母缩写和关键词匹配。
* **互惠排名融合(RRF)**:使用互惠评分($Score = \sum \frac{1}{k + Rank}$)合并密集和稀疏排名,以确保最佳排名。
### 3. 可靠性和重复数据删除
* **基于内容的点ID**:点ID使用`document_name + page + chunk_text`的MD5哈希生成。这保证了重复块不会创建冗余数据库条目。
* **摄入保护**:如果文档已编入索引,则跳过处理。
---
## 检索MCP工具
**检索MCP**为客户端编排提供了以下端点:
| 工具名称 | 参数 | 描述 |
|-----------|------------|-------------|
| `semantic_search` | `query: str`, `top_k: int`, `document_name: str` | 在Qdrant向量存储中执行语义(密集)搜索。 |
| `bm25_search` | `query: str`, `top_k: int` | 对索引文档执行BM25关键词(稀疏)搜索。 |
| `hybrid_search` | `query: str`, `top_k: int`, `document_name: str` | 使用RRF融合执行混合(密集+BM25)搜索。 |
| `ask_documents` | `query: str`, `top_k: int`, `document_name: str` | 使用Gemini基于融合的检索上下文回答查询。 |
| `ingest_document` | `file_path: str` | 验证并将本地PDF/TXT/MD文档摄入Qdrant数据库。 |
| `list_documents` | 无 | 检索当前在向量存储中索引的所有文档名称。 |
| `get_collection_stats`| 无 | 获取Qdrant集合的统计信息(点数、向量大小、距离度量)。 |
---
## 入门指南
### 先决条件
* Python >= 3.11
* [uv](https://github.com/astral-sh/uv) (快速的Python包安装程序和运行程序)
* Qdrant(在`localhost:6333`或Docker上运行)
* Google Gemini API密钥
### 配置
1. 克隆此存储库。
2. 在根目录中创建`.env`文件:
```env
GEMINI_API_KEY="your_gemini_api_key_here"
```
### 快速设置
1. **安装依赖项**:
```bash
uv sync
```
2. **启动Qdrant**:
确保Qdrant正在运行。如果使用Docker:
```bash
docker run -p 6333:6333 -p 6334:6334 -v qdrant_storage:/qdrant/storage qdrant/qdrant
```
3. **初始化集合**:
使用正确的向量维度(768)创建Qdrant `documents`集合:
```bash
uv run python tests/test_create_collection.py
```
4. **摄入示例文档**:
摄入测试PDF文件以填充索引:
```bash
uv run python tests/test_pipeline.py
```
---
## 运行MCP服务器
您可以使用`uv`在本地启动MCP服务器:
### PDF解析器MCP服务器
```bash
uv run python -m mcp_servers.pdf_parser.server
```
### 检索MCP服务器
```bash
uv run python -m mcp_servers.retrieval.server
```
*(您可以将这些服务器注册到cursor/VS Code设置或MCP主机配置中,使用`uv`的绝对路径和脚本模块参数。)*
---
## 验证和测试套件
我们提供了一个全面的测试列表,在`tests/`目录下,以验证RAG流程的每个组件:
```bash
# 验证基本连接和设置
uv run python tests/test_qdrant_connection.py # 检查与Qdrant的连接
uv run python tests/test_gemini.py # 检查Gemini连接和凭证
# 验证嵌入和分块机制
uv run python tests/test_chunking.py # 测试递归 + 滑动上下文分块
uv run python tests/test_embeddings.py # 测试BGE嵌入生成
# 验证摄入和统计
uv run python tests/test_pipeline.py # 通过布局解析器、分割器和嵌入器摄入PDF
uv run python tests/test_document_counts.py # 按文档分组和计数点
uv run python tests/test_scroll_points.py # 滚动和预览摄入的载荷
# 验证搜索算法
uv run python tests/test_retrieval.py # 测试密集语义搜索
uv run python tests/test_bm25.py # 测试稀疏关键词BM25搜索
uv run python tests/test_hybrid_retrieval.py # 比较密集、BM25和混合结果
uv run python tests/test_document_filter.py # 带有元数据过滤的语义搜索
# 验证端到端QA
uv run python tests/test_rag.py # 测试基于Gemini的答案生成
```
---
## 项目结构
```text
hybrid-rag-mcp/
├── agent/ # 未来的代理逻辑(基于图的路由)
│ └── graph.py
├── app/ # 配置设置
│ ├── config.py
│ └── settings.py
├── data/ # 保存本地文件(例如 data/samples/sample.pdf)
├── docs/ # 升级日志和设计文档
│ └── HYBRID_RAG_UPGRADE.md
├── embeddings/ # 文本嵌入实用程序(句子转换器)
│ └── embedder.py
├── ingestion/ # PDF提取、分块、过滤和流程协调
│ ├── chunker.py
│ ├── filters.py
│ ├── ingestion_service.py
│ └── pipeline.py
├── llm/ # Gemini API接口客户端
│ └── gemini_client.py
├── mcp_servers/ # 模型上下文协议服务器
│ ├── pdf_parser/ # 基于PyMuPDF的文本解析器和元数据提取器
│ │ ├── pdf_utils.py
│ │ ├── schemas.py
│ │ ├── tools.py
│ │ └── server.py
│ ├── retrieval/ # 检索服务器(语义、bm25、混合、RAG、摄入)
│ │ ├── bm25_qdrant_retriever.py
│ │ ├── bm25_retriever.py
│ │ ├── hybrid_retriever.py
│ │ ├── rag_engine.py
│ │ ├── retrieval_engine.py
│ │ ├── schemas.py
│ │ ├── tools.py
│ │ └── server.py
│ ├── ocr/ # 扫描页面的OCR占位符(计划中)
│ ├── table_extractor/ # 表格结构提取器的占位符(计划中)
│ ├── layout_analyzer/ # 布局提取服务器的占位符(计划中)
│ └── vector_store/ # 独立向量存储控件的占位符(计划中)
├── vector_store/ # Qdrant客户端连接、摄入和模式创建
│ ├── collections.py
│ ├── ingest.py
│ └── qdrant_client.py
├── tests/ # 集成和验证测试脚本
├── pyproject.toml # PEP 621配置文件和依赖项列表
└── uv.lock # 用于精确依赖项解析的锁定文件
```
---
## 技术栈
* **语言**:Python >= 3.11
* **编排**:模型上下文协议(FastMCP)
* **向量数据库**:Qdrant(使用余弦距离、滚动、载荷)
* **嵌入模型**:`BAAI/bge-base-en-v1.5`通过句子转换器
* **稀疏索引**:`BM25Okapi`通过`rank-bm25`
* **RAG LLM**:Google Gemini SDK(`gemini-2.5-flash`)
* **解析**:PyMuPDF(`fitz`)
* **环境**:`uv`包管理器,`python-dotenv`