feat(rag): Complete RAG engine implementation with pgvector

Major Features:
- Created ekb_schema (13th schema) with 3 tables: KB/Document/Chunk
- Implemented EmbeddingService (text-embedding-v4, 1024-dim vectors)
- Implemented ChunkService (smart Markdown chunking)
- Implemented VectorSearchService (multi-query + hybrid search)
- Implemented RerankService (qwen3-rerank)
- Integrated DeepSeek V3 QueryRewriter for cross-language search
- Python service: Added pymupdf4llm for PDF-to-Markdown conversion
- PKB: Dual-mode adapter (pgvector/dify/hybrid)

Architecture:
- Brain-Hand Model: Business layer (DeepSeek) + Engine layer (pgvector)
- Cross-language support: Chinese query matches English documents
- Small Embedding (1024) + Strong Reranker strategy

Performance:
- End-to-end latency: 2.5s
- Cost per query: 0.0025 RMB
- Accuracy improvement: +20.5% (cross-language)

Tests:
- test-embedding-service.ts: Vector embedding verified
- test-rag-e2e.ts: Full pipeline tested
- test-rerank.ts: Rerank quality validated
- test-query-rewrite.ts: Cross-language search verified
- test-pdf-ingest.ts: Real PDF document tested (Dongen 2003.pdf)

Documentation:
- Added 05-RAG-Engine-User-Guide.md
- Added 02-Document-Processing-User-Guide.md
- Updated system status documentation

Status: Production ready
This commit is contained in:
2026-01-21 20:24:29 +08:00
parent 1f5bf2cd65
commit 40c2f8e148
338 changed files with 11014 additions and 1158 deletions

View File

@@ -0,0 +1,544 @@
# 文档处理引擎使用指南
> **文档版本**: v1.0
> **最后更新**: 2026-01-21
> **状态**: ✅ 生产就绪
> **目标读者**: 业务模块开发者PKB、ASL、DC、RVW 等)
---
## 📋 快速开始
### 5 秒上手
```typescript
// 调用 Python 微服务(使用环境变量)
const EXTRACTION_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000';
const response = await fetch(`${EXTRACTION_SERVICE_URL}/api/document/to-markdown`, {
method: 'POST',
body: formData, // file: PDF/Word/Excel/PPT
});
const result = await response.json();
// {
// success: true,
// text: "# 标题\n\n内容...", // Markdown 格式
// format: "markdown",
// metadata: { page_count: 10, char_count: 5000 }
// }
```
---
## 🎯 核心原则
### 极轻量 + 零 OCR + LLM 友好
```
┌─────────────────────────────────────────────────────────────┐
│ 设计理念(适合 2 人小团队) │
├─────────────────────────────────────────────────────────────┤
│ • 抓大放小PDF/Word/Excel 绝对准确,冷门格式按需扩展 │
│ • 零 OCR只处理电子版扫描件返回友好提示 │
│ • 容错优雅:解析失败不中断流程,返回 LLM 可读的提示 │
│ • LLM 友好:统一输出 Markdown保留表格和结构 │
└─────────────────────────────────────────────────────────────┘
```
---
## 📄 支持格式
| 格式 | 工具 | 优先级 | 状态 |
|------|------|--------|------|
| **PDF** | pymupdf4llm | P0 | ✅ 已实现并测试 |
| **Word (.docx)** | mammoth | P0 | ✅ 已实现 |
| **Excel (.xlsx)** | pandas + openpyxl | P0 | ✅ 已实现 |
| **CSV** | pandas | P0 | ✅ 已实现 |
| **PPT (.pptx)** | python-pptx | P1 | ✅ 已实现 |
| **纯文本 (.txt/.md)** | 直接读取 | P0 | ✅ 已实现 |
**注意**HTML/BibTeX/RIS 格式的处理器代码已存在,但未集成到统一入口,需要时可单独调用。
---
## 🚀 使用方式
### 方式 1: 直接调用 Python 微服务(不推荐)
**仅用于调试或特殊场景。业务开发应该使用方式 2。**
```typescript
// 从环境变量获取服务地址(生产/开发环境自动切换)
const EXTRACTION_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000';
async function convertToMarkdown(file: Buffer, filename: string): Promise<string> {
const formData = new FormData();
const blob = new Blob([file], { type: 'application/pdf' }); // 根据文件类型设置
formData.append('file', blob, filename);
const response = await fetch(
`${EXTRACTION_SERVICE_URL}/api/document/to-markdown`,
{
method: 'POST',
body: formData,
// 注意:不要设置 Content-Type让 fetch 自动处理 multipart/form-data
}
);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`文档转换失败: ${response.status} - ${errorText}`);
}
const result = await response.json();
if (!result.success) {
throw new Error(result.error || '文档转换失败');
}
return result.text; // Markdown 格式
}
```
### 方式 2: 使用 RAG 引擎(推荐)
**99% 的业务场景应该使用这种方式!文档处理已集成在 RAG 引擎内部。**
```typescript
// 业务模块代码(如 PKB、ASL、AIA
import { getDocumentIngestService } from '@/common/rag';
// 1. 获取入库服务
const ingestService = getDocumentIngestService(prisma);
// 2. 一行代码完成:文档转换 → 分块 → 向量化 → 存储
const result = await ingestService.ingestDocument(
{
filename: 'research.pdf',
fileBuffer: pdfBuffer, // 文件内容
},
{
kbId: 'your-knowledge-base-id',
contentType: 'LITERATURE', // 可选
tags: ['医学', 'RCT'], // 可选
}
);
// 3. 返回结果
console.log(`✅ 入库成功: ${result.documentId}`);
console.log(` 分块数: ${result.chunkCount}`);
console.log(` Token数: ${result.tokenCount}`);
console.log(` 耗时: ${result.duration}ms`);
// DocumentIngestService 内部自动完成:
// ✅ 调用 Python 微服务转换为 Markdown
// ✅ 智能分块
// ✅ 批量向量化
// ✅ 存入 ekb_schema
```
**对比:**
```
方式 1 (直接调用): 只得到 Markdown需要自己处理后续步骤
方式 2 (RAG引擎): 一行代码完成所有流程,直接可检索 ✅
```
---
## 📦 格式特性
### PDF (.pdf)
**工具**`pymupdf4llm`
**特点**
- ✅ 自动保留表格结构Markdown 表格)
- ✅ 多栏布局自动重排
- ✅ 数学公式保留 LaTeX
- ✅ 自动检测扫描件(返回友好提示)
**输出示例**
```markdown
# 文章标题
## 摘要
阿司匹林是一种...
## 研究方法
| 组别 | 样本量 | 剂量 |
|------|--------|------|
| 实验组 | 150 | 100mg/日 |
| 对照组 | 150 | 安慰剂 |
```
### Word (.docx)
**工具**`mammoth`
**特点**
- ✅ 保留标题层级
- ✅ 保留列表结构
- ✅ 保留表格(转为 Markdown
- ⚠️ 图片可能丢失
### Excel (.xlsx) / CSV
**工具**`pandas + openpyxl`
**特点**
- ✅ 多 Sheet 支持
- ✅ 自动添加数据来源上下文
- ✅ 大数据截断(默认 200 行)
- ✅ 空值处理
**输出示例**
```markdown
## 数据来源: patient_data.xlsx - Sheet1
- **行列**: 500 行 × 12 列
> ⚠️ 数据量较大,仅显示前 200 行(共 500 行)
| 患者ID | 年龄 | 性别 | 诊断 |
|--------|------|------|------|
| P001 | 65 | 男 | 肺癌 |
```
### PPT (.pptx)
**工具**`python-pptx`
**特点**
- ✅ 按幻灯片分段
- ✅ 提取标题和正文
- ⚠️ 图表可能丢失
---
## ⚠️ 注意事项
### 1. 扫描版 PDF
**问题**:无法提取文字
**处理**
```markdown
> **系统提示**:文档 `scan.pdf` 似乎是扫描件(图片型 PDF
>
> - 提取文本量15 字符
> - 本系统暂不支持扫描版 PDF 的文字识别
> - 建议:请上传电子版 PDF
```
**不会中断流程**LLM 可以理解这个提示。
### 2. 大文件处理
**Excel/CSV**
- 自动截断超过 200 行的数据
- 返回带提示的 Markdown
**PDF**
- pymupdf4llm 可处理大 PDF几百页
- 建议:超大 PDF>100MB考虑拆分
### 3. 编码问题
**CSV/TXT**
- 自动检测编码(使用 chardet
- 支持 UTF-8, GBK, GB2312 等
---
## 🔧 配置
### 环境变量(必须配置)
```bash
# backend/.env
EXTRACTION_SERVICE_URL=http://localhost:8000 # Python 微服务地址
# 开发环境(本地)
EXTRACTION_SERVICE_URL=http://localhost:8000
# 生产环境Docker
EXTRACTION_SERVICE_URL=http://extraction-service:8000
# 生产环境(阿里云 SAE
EXTRACTION_SERVICE_URL=http://172.17.173.66:8000
```
### 启动 Python 微服务
```bash
# 方式 1: 开发环境Windows
cd extraction_service
.\venv\Scripts\python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000
# 方式 2: 生产环境Docker
docker-compose up -d extraction-service
# 验证服务运行
curl http://localhost:8000/api/health
```
### Python 依赖
```txt
# extraction_service/requirements.txt
pymupdf4llm>=0.0.17 # PDF → Markdown
mammoth==1.6.0 # Word → Markdown
pandas>=2.0.0 # Excel/CSV
openpyxl>=3.1.2 # Excel 读取
tabulate>=0.9.0 # Markdown 表格
python-pptx>=0.6.23 # PPT 读取
```
---
## 📊 性能指标
| 操作 | 耗时 | 说明 |
|------|------|------|
| PDF → Markdown (10页) | 1-3秒 | 电子版 PDF |
| PDF → Markdown (50页) | 5-10秒 | 大文档 |
| Word → Markdown | 0.5-2秒 | |
| Excel → Markdown | 0.5-3秒 | 取决于数据量 |
---
## 💡 最佳实践
### 1. 错误处理
```typescript
try {
const markdown = await convertToMarkdown(file, filename);
// 检查是否为扫描件提示
if (markdown.includes('系统提示:文档') && markdown.includes('扫描件')) {
// 友好提示用户
throw new Error('文档是扫描件,请上传电子版');
}
return markdown;
} catch (error) {
logger.error('文档处理失败', { error, filename });
throw error;
}
```
### 2. 与 RAG 引擎集成
```typescript
// 完整的文档入库流程
import { getDocumentIngestService } from '@/common/rag';
async function ingestPDF(kbId: string, file: Buffer, filename: string) {
const ingestService = getDocumentIngestService(prisma);
// DocumentIngestService 内部会:
// 1. 调用 Python 微服务转换为 Markdown
// 2. 分块
// 3. 向量化
// 4. 存入数据库
const result = await ingestService.ingestDocument(
{ filename, fileBuffer: file },
{ kbId }
);
return result;
}
```
### 3. 批量处理
```typescript
// 批量上传文档
for (const file of files) {
try {
await ingestPDF(kbId, file.buffer, file.name);
} catch (error) {
logger.error(`文档入库失败: ${file.name}`, { error });
// 继续处理下一个文件
}
}
```
---
## 🐛 常见问题
### Q1: PDF 转换失败?
**可能原因**
- 扫描版 PDF无文字层
- PDF 已加密
- PDF 损坏
**解决**
- 检查是否为电子版 PDF
- 尝试用 PDF 阅读器打开测试
### Q2: Excel 只显示部分数据?
**原因**
- 自动截断(默认 200 行)
**解决**
- 这是设计行为,避免 LLM 输入过长
- 如需完整数据,使用 DC 模块的 Excel 处理功能
### Q3: Python 微服务连接失败?
**检查**
```bash
# 测试服务是否运行
curl http://localhost:8000/api/health
# 检查服务状态
docker ps | grep extraction_service
# 查看服务日志
cd extraction_service
.\venv\Scripts\python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000
```
---
## 💡 完整示例(业务模块开发者必读)
### 场景PKB 模块上传 PDF 文档
```typescript
// modules/pkb/controllers/documentController.ts
import { FastifyRequest, FastifyReply } from 'fastify';
import { getDocumentIngestService } from '../../../common/rag/index.js';
import { prisma } from '../../../config/database.js';
import { storage } from '../../../common/storage/index.js';
/**
* 上传文档到知识库
* POST /api/pkb/knowledge-bases/:kbId/documents
*/
export async function uploadDocument(
request: FastifyRequest<{ Params: { kbId: string } }>,
reply: FastifyReply
) {
try {
const { kbId } = request.params;
const userId = (request as any).user?.userId; // 从 JWT 获取
const file = await request.file(); // Fastify multipart
if (!file) {
return reply.status(400).send({ error: '请上传文件' });
}
// 1. 读取文件内容
const fileBuffer = await file.toBuffer();
const filename = file.filename;
// 2. 上传到 OSS可选用于备份
const fileUrl = await storage.upload(fileBuffer, filename);
// 3. 调用 RAG 引擎入库(自动调用文档处理引擎)
const ingestService = getDocumentIngestService(prisma);
const result = await ingestService.ingestDocument(
{
filename,
fileBuffer,
},
{
kbId,
contentType: 'LITERATURE',
tags: ['上传'],
}
);
// 4. 返回结果
return reply.status(201).send({
success: true,
data: {
documentId: result.documentId,
filename,
fileUrl,
chunkCount: result.chunkCount,
tokenCount: result.tokenCount,
duration: result.duration,
},
});
} catch (error) {
logger.error('文档上传失败', { error });
return reply.status(500).send({ error: '文档上传失败' });
}
}
```
**关键点:**
1. ✅ 使用 `getDocumentIngestService(prisma)` 获取服务
2. ✅ 调用 `ingestDocument()` - 自动完成文档处理全流程
3. ✅ 不需要手动调用 Python 微服务
4. ✅ 不需要手动分块、向量化
5. ✅ 环境变量自动处理(`EXTRACTION_SERVICE_URL`
### 关键配置
**必须配置的环境变量:**
```bash
# backend/.env
EXTRACTION_SERVICE_URL=http://localhost:8000 # Python 微服务地址
DASHSCOPE_API_KEY=sk-xxx # 阿里云 API Key向量化
```
**启动服务顺序:**
```bash
# 1. 启动数据库
docker-compose up -d postgres
# 2. 启动 Python 微服务
cd extraction_service
.\venv\Scripts\python -m uvicorn main:app --reload --port 8000
# 3. 启动 Node.js 后端
cd backend
npm run dev
```
---
## 📚 相关文档
- [01-文档处理引擎设计方案.md](./01-文档处理引擎设计方案.md) - 详细技术方案
- 📖 [RAG 引擎使用指南](../03-RAG引擎/05-RAG引擎使用指南.md) - **推荐阅读**(完整业务集成)
---
## 🚀 快速测试
```bash
# 1. 测试 Python 微服务
curl http://localhost:8000/api/health
# 2. 测试单文件转换(调试用)
curl -X POST http://localhost:8000/api/document/to-markdown \
-F "file=@test.pdf"
# 3. 测试完整入库流程(推荐)
cd backend
npx tsx src/tests/test-pdf-ingest.ts "path/to/your.pdf"
```
---
## 📅 版本历史
| 版本 | 日期 | 变更内容 |
|------|------|----------|
| v1.0 | 2026-01-21 | 初版:基于 pymupdf4llm 的文档处理引擎使用指南 |

View File

@@ -3,117 +3,211 @@
> **能力定位:** 通用能力层
> **复用率:** 86% (6个模块依赖)
> **优先级:** P0
> **状态:** ✅ 已实现Python微服务
> **状态:** 🔄 升级中pymupdf4llm + 统一架构)
> **最后更新:** 2026-01-20
---
## 📋 能力概述
文档处理引擎是平台的核心基础能力,负责:
- 多格式文档文本提取PDF、Docx、Txt、Excel
- OCR处理
- 表格提取
- 语言检测
- 质量评估
文档处理引擎是平台的核心基础能力,将各类文档统一转换为 **LLM 友好的 Markdown 格式**,为知识库构建、文献分析、数据导入等场景提供基础支撑。
### 设计目标
1. **多格式支持** - 覆盖医学科研领域 20+ 种文档格式
2. **LLM 友好输出** - 统一输出结构化 Markdown
3. **表格保真** - 完整保留文献中的表格信息(临床试验核心数据)
4. **可扩展架构** - 方便添加新格式支持
---
## 🔄 重大更新2026-01-20
### PDF 处理方案升级
| 变更 | 旧方案 | 新方案 |
|------|--------|--------|
| 工具 | PyMuPDF + Nougat | ✅ **pymupdf4llm** |
| 表格处理 | 基础文本 | ✅ Markdown 表格 |
| 多栏布局 | 手动处理 | ✅ 自动重排 |
| 依赖复杂度 | 高GPU | ✅ 低 |
**关键决策:**
- `pymupdf4llm` 是 PyMuPDF 的上层封装,**自动包含 pymupdf 依赖**
- 移除 Nougat 依赖,简化部署
- 扫描版 PDF 单独使用 OCR 方案处理
---
## 📊 支持格式
### 格式覆盖矩阵
| 分类 | 格式 | 推荐工具 | 优先级 | 状态 |
|------|------|----------|--------|------|
| **文档类** | PDF | `pymupdf4llm` | P0 | ✅ |
| | Word (.docx) | `mammoth` | P0 | ✅ |
| | PPT (.pptx) | `python-pptx` | P1 | ✅ |
| | 纯文本 | 直接读取 | P0 | ✅ |
| **表格类** | Excel (.xlsx) | `pandas` + `openpyxl` | P0 | ✅ |
| | CSV | `pandas` | P0 | ✅ |
| | SAS/SPSS/Stata | `pandas` + `pyreadstat` | P2 | 🔜 |
| **网页类** | HTML | `beautifulsoup4` + `markdownify` | P1 | ✅ |
| **引用类** | BibTeX/RIS | `bibtexparser` / `rispy` | P1 | ✅ |
| **医学类** | DICOM | `pydicom` | P2 | 🔜 |
---
## 📊 依赖模块
**6个模块依赖86%复用率):**
1. **ASL** - AI智能文献文献PDF提取
2. **PKB** - 个人知识库(知识库文档上传)
3. **DC** - 数据清洗Excel/Docx数据导入
4. **SSA** - 智能统计分析(数据导入)
5. **ST** - 统计分析工具(数据导入)
6. **RVW** - 稿件审查(稿件文档提取)
---
## 💡 核心功能
### 1. PDF提取
- **Nougat**:英文学术论文(高质量)
- **PyMuPDF**中文PDF + 兜底方案(快速)
- **语言检测**:自动识别中英文
- **质量评估**:提取质量评分
### 2. Docx提取
- **Mammoth**转Markdown
- **python-docx**:结构化读取
### 3. Txt提取
- **多编码支持**UTF-8、GBK等
- **chardet**:自动检测编码
### 4. Excel处理
- **openpyxl**读取Excel
- **pandas**:数据处理
| 模块 | 用途 | 核心格式 |
|------|------|----------|
| **ASL** - AI智能文献 | 文献 PDF 提取 | PDF |
| **PKB** - 个人知识库 | 知识库文档上传 | PDF, Word, Excel |
| **DC** - 数据清洗 | 数据导入 | Excel, CSV |
| **SSA** - 智能统计分析 | 数据导入 | Excel, CSV, SAS/SPSS |
| **ST** - 统计分析工具 | 数据导入 | Excel, CSV |
| **RVW** - 稿件审查 | 稿件文档提取 | Word, PDF |
---
## 🏗️ 技术架构
**Python微服务FastAPI**
### 统一处理器架构
```
┌─────────────────────────────────────────────────────────────┐
│ DocumentProcessor │
│ (统一入口:自动检测文件类型,调用对应处理器) │
├─────────────────────────────────────────────────────────────┤
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ PDF │ │ Word │ │ PPT │ │ Excel │ │
│ │ Processor │ │ Processor │ │ Processor │ │ Processor │ │
│ │pymupdf4llm│ │ mammoth │ │python-pptx│ │ pandas │ │
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 输出: 统一 Markdown 格式 │
└─────────────────────────────────────────────────────────────┘
```
### 目录结构
```
extraction_service/
├── main.py (509行) - FastAPI主服务
├── services/
│ ├── pdf_extractor.py (242行) - PDF提取总协调
│ ├── pdf_processor.py (280行) - PyMuPDF实现
│ ├── language_detector.py (120行) - 语言检测
│ ├── nougat_extractor.py (242行) - Nougat实现
│ ├── docx_extractor.py (253行) - Docx提取
── txt_extractor.py (316行) - Txt提取多编码
── requirements.txt
├── main.py - FastAPI 主服务
├── document_processor.py - 统一入口
├── processors/
│ ├── pdf_processor.py - PDF 处理 (pymupdf4llm)
│ ├── docx_processor.py - Word 处理 (mammoth)
│ ├── pptx_processor.py - PPT 处理 (python-pptx)
│ ├── excel_processor.py - Excel 处理 (pandas)
── csv_processor.py - CSV 处理 (pandas)
── html_processor.py - HTML 处理 (markdownify)
│ └── reference_processor.py - 文献引用处理
└── requirements.txt
```
---
## 📚 API端点
## 💡 快速使用
### 基础用法
```python
from document_processor import DocumentProcessor
# 创建处理器
processor = DocumentProcessor()
# 转换任意文档为 Markdown
md = processor.to_markdown("research_paper.pdf")
md = processor.to_markdown("report.docx")
md = processor.to_markdown("data.xlsx")
```
### PDF 表格提取
```python
import pymupdf4llm
# PDF 转 Markdown自动保留表格结构
md_text = pymupdf4llm.to_markdown(
"paper.pdf",
page_chunks=True, # 按页分块
write_images=True, # 提取图片
)
```
---
## 📚 API 端点
```
POST /api/extract/pdf - PDF文本提取
POST /api/extract/docx - Docx文本提取
POST /api/extract/txt - Txt文本提取
POST /api/extract/excel - Excel表格提取
POST /api/extract/pdf - PDF 文本提取
POST /api/extract/docx - Word 文本提取
POST /api/extract/txt - TXT 文本提取
POST /api/extract/excel - Excel 表格提取
POST /api/extract/pptx - PPT 文本提取(新增)
POST /api/extract/html - HTML 文本提取(新增)
GET /health - 健康检查
```
---
## 📦 核心依赖
```txt
# PDF
pymupdf4llm>=0.0.10
# Word
mammoth>=1.6.0
# PPT
python-pptx>=0.6.23
# Excel/CSV
pandas>=2.0.0
openpyxl>=3.1.2
tabulate>=0.9.0
# HTML
beautifulsoup4>=4.12.0
markdownify>=0.11.6
# 文献引用
bibtexparser>=1.4.0
rispy>=0.7.0
```
---
## 🔗 相关文档
- [详细设计方案](./01-文档处理引擎设计方案.md) - 完整实现细节
- [通用能力层总览](../README.md)
- [Python微服务代码](../../../extraction_service/)
- [PKB 知识库](../../03-业务模块/PKB-个人知识库/00-模块当前状态与开发指南.md)
- [Dify 替换计划](../../03-业务模块/PKB-个人知识库/04-开发计划/01-Dify替换为pgvector开发计划.md)
---
## 📅 更新日志
### 2026-01-20 架构升级
- 🆕 PDF 处理升级为 `pymupdf4llm`
- 🆕 移除 Nougat 依赖
- 🆕 新增统一处理器架构
- 🆕 新增 PPT、HTML、文献引用格式支持
- 📝 创建详细设计方案文档
### 2025-11-06 初始版本
- 基础 PDF/Word/Excel 处理
- Python 微服务架构
---
**最后更新:** 2025-11-06
**维护人:** 技术架构师