Skip to content
ARieS719Public

About

企业级中文教育知识库 RAG 数据工程项目:入库质量门 + 混合检索 + 三层评测闭环|5,179 份语料实测:脏数据拦截 100%/误伤 0,Recall@5 81.1%,Faithfulness 100%

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

26 Commits

Folders and files

Repository files navigation

KnowPulse (EduGuard-RAG)

CI

一个围绕检索增强生成(RAG)数据质量问题的实验项目。实验以一份混合格式的中文教育语料(5,179 份文档,其中 677 份为人为注入的脏数据)为对象,实现并验证「入库质量门 → 双索引混合检索 → 三层评测」的完整流程。项目关心的两个具体问题是:非结构化文档进入索引之前如何进行质量拦截,以及检索与生成的效果如何被量化评测。

实验结果摘要

项目 结果 证据
质量门:677 份脏数据拦截率 677/677,干净数据零误伤 quality_gate_report.md
解析产出率(100 份分层抽检) 100%;完整内容解析率 100%(OCR 预解析接入后) parse_audit_report.md
检索 Recall@5(hybrid_rerank) 81.08% ablation_report.md
检索 Recall@10 85.14%(BM25 档 90.54%) 同上
相对向量基线提升 +25.67 个百分点 同上
生成忠实度(裁判模型判分) 68/68 判为忠实 generation_report.md
无证据拒答正确率 5/5 同上
引用硬校验 Precision 0.9367 同上
单元测试 8 项通过(CI 门禁) .github/workflows/ci.yml

索引规模:4,542 份文档、19,211 个切片(ChromaDB 向量 + SQLite FTS5 双索引)。全量评测的 LLM API 累计成本约 0.61 元。

1. 背景与目标

1.1 背景

RAG 知识库的检索效果很大程度上取决于进入索引的文档质量。实际收集到的文档往往混杂重复文件、低清扫描件、乱码块以及新旧版本冲突,这些问题若不在入库前拦截,会在检索与生成阶段造成难以定位的错误。实验希望回答两个问题:

  1. 能否用一套可配置的检测规则,在文档入库前拦截上述问题文档;
  2. 能否建立一套可复现的量化评测流程,衡量检索与生成效果,并让每次修改的影响可度量。

1.2 评测指标

指标 设定目标 实测
脏数据入库拦截率 100% 100%(677/677,误伤 0)
文档解析成功率 ≥ 95% 产出率 100%;完整内容解析率 100%(OCR 预解析接入后,见 §8 与 parse_audit_report.md)
检索 Recall@5 ≥ 82% 81.08%
Recall@5 分层 简单类 ≥ 92%;表格/扫描类 ≥ 72% 88.57% / 74.36%
Recall@10 ≥ 90% 85.14%(BM25 档 90.54%)
相对朴素基线提升 ≥ 18–25 个百分点 +25.67pp
生成忠实度 ≥ 0.85 68/68
引用硬校验 Precision ≥ 0.90 0.9367
单次问答成本 < 0.05 元 实测 0.005 元量级

2. 系统架构

┌─────────────────────────────────────────────────────────────┐
│ 接入层   FastAPI(/ingest /query /feedback /quality/summary)│
├─────────────────────────────────────────────────────────────┤
│ 采集层   本地目录导入 → 元数据抽取(标题/学科/版本/access_roles)│
├─────────────────────────────────────────────────────────────┤
│ 解析层   MinerU(预留)/ pypdfium2 / PaddleOCR(预留)        │
│          python-docx / openpyxl / JSON 题库 → 父子块          │
│          跨页表格拼接修复(table_stitcher)                    │
├─────────────────────────────────────────────────────────────┤
│ 数据质量层                                                    │
│  哈希去重 / 题目级近重复检测 / 版本一致性状态机 / 字段级乱码    │
│  检测 / 空白页与低分辨率检测 / PII 脱敏 / 质量门 + 核查报告     │
├─────────────────────────────────────────────────────────────┤
│ 切片层   标题树切分 + 父子块 + 表格/图片摘要索引               │
│          断头块语义完整度修复(表头断离/题目选项分离)         │
├─────────────────────────────────────────────────────────────┤
│ 索引层   bge-m3 → 1024 维向量 → ChromaDB                      │
│          BM25 全文 → SQLite FTS5(jieba 预分词)              │
│          SHA256 嵌入缓存(文本未变不重算)                     │
│          双索引由同一 chunk_id 关联,原子双写 + 故障回滚       │
├─────────────────────────────────────────────────────────────┤
│ 检索层   向量 Top100 + FTS5 Top100 → RRF 融合 → bge-reranker  │
│          重排 Top8 → ACL 前置过滤 → 语义缓存(热点 <20ms)     │
├─────────────────────────────────────────────────────────────┤
│ 生成层   硅基流动 API(主)/ Ollama 本地(兜底)               │
│          强制引用 prompt + 无证据拒答 + 引用双层校验           │
├─────────────────────────────────────────────────────────────┤
│ 评测层                                                        │
│  数据层/检索层/生成层三层评测 + 四档消融实验                   │
│  badcase 归因(解析/切片/检索/生成)→ 修复 → 回归对比          │
└─────────────────────────────────────────────────────────────┘

3. 目录结构

knowpulse-rag/
├── .github/            CI 质量门禁(pytest 全量测试)
├── configs/            settings.yaml(全局配置)+ .env.example(密钥模板)
├── data/
│   ├── raw/            5,179 份语料(含 677 份注入脏数据;不入库,生成脚本另行托管)
│   ├── parsed/         解析缓存(运行时生成)
│   ├── quarantine/     质量门拦截清单与核查报告(报告入库)
│   ├── golden_set/     评测集(79 条,5 难度层)与消融/评测报告(入库)
│   ├── meta/           manifest.csv + 脏数据审计报告 + 来源声明(入库)
│   └── storage/        chroma_db/ + metadata.db(运行时生成,不入库)
├── src/
│   ├── config.py       全局配置加载器(settings.yaml + .env)
│   ├── llm/            siliconflow_client.py
│   ├── ingestion/      parser_router.py + table_stitcher.py
│   ├── quality/        state_machine.py + operators.py + quality_gate.py
│   ├── indexing/       chunker.py + embedder.py + fts5_store.py + dual_writer.py
│   ├── retrieval/      hybrid_search.py + reranker.py + semantic_cache.py
│   ├── generation/     rag_chain.py + citation_check.py
│   ├── evaluation/     metrics.py + build_golden.py + badcase_loop.py
│   └── api/            main.py
└── tests/              test_fault_injection.py + test_quality_and_fts.py

4. 快速开始

# 环境准备(一次性)
cd D:\knowpulse-rag
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt          # GPU 环境另见 §8

# 配置密钥
# 复制 configs/.env.example 为 configs/.env,填入 SILICONFLOW_API_KEY
# (硅基流动 https://cloud.siliconflow.cn 注册后创建 API 密钥)
# 注意:中国区账号密钥只能使用 https://api.siliconflow.cn/v1 端点(.com 国际站不互通)

# Step 1 质量门全量审计(5,179 份语料 → 拦截 677 份脏/冲突文档)
python -m src.quality.quality_gate

# Step 2-3 双索引构建(先小样本验证,再全量)
python -m src.indexing.dual_writer --limit 50
python -m src.indexing.dual_writer

# Step 4 四档消融实验(Recall@5 / MRR / nDCG / 延迟)
python -m src.evaluation.metrics --action run_ablation

# Step 5 三层评测
python -m src.evaluation.metrics --action data_layer
python -m src.evaluation.metrics --action generation

# Step 6 启动 API 服务
python -m uvicorn src.api.main:app --host 127.0.0.1 --port 8000
# 浏览器打开 http://127.0.0.1:8000/docs 直接试 /query

# 测试
python -m pytest tests

5. 评测方法与结果

5.1 评测集

评测集 golden_set_v1.jsonl 共 79 条,按难度分为五层:简单检索 35、跨文档聚合 14、表格数值 9、图片理解 16、应拒答 5。评测题与语料模板解耦,避免字面重合造成的评测泄漏。每条包含问题、标准答案、证据文档与难度标签。

命中判定采用三口径(任一成立即命中):证据文档本身被检索到;检索到与证据内容相同的模板副本(内容指纹级);检索内容能够支撑标准答案(答案包含性)。语料中存在大量同模板副本,仅按文档编号判定会系统性低估真实检索质量。

5.2 检索层:四档消融实验

对 74 条可检索评测题(排除 5 条应拒答),分别在四种检索配置下测量:

检索配置 Recall@5 Recall@10 MRR@10 nDCG@10 平均延迟
仅向量 44.59% 52.70% 0.3801 0.4151 70.4 ms
仅 BM25 82.43% 90.54% 0.7876 0.8147 20.3 ms
混合 + RRF 72.97% 78.38% 0.5650 0.6194 86.0 ms
混合 + RRF + 重排 81.08% 85.14% 0.7463 0.7717 ~1.4–2.2 s

重排档的延迟主要来自云端重排 API 往返(详见 §8)。完整报告见 ablation_report.md。

5.3 生成层:忠实度与引用校验

  • 忠实度:以裁判模型(DeepSeek-V3)判断"标准答案是否蕴含于检索证据",74 条可回答题目中 68 条参与判定、全部判为忠实;
  • 无证据拒答:5 条应拒答题全部正确拒答;
  • 引用硬校验:在线正则校验回答中的引用编号是否真实存在于本次召回,平均 Precision 0.9367。

完整报告见 generation_report.md。

5.4 数据层与质量门

质量门对 5,179 份语料全量审计:4,502 份干净文档全部放行;677 份脏/冲突文档全部拦截(重复 200、近重复 100、版本冲突 97、乱码 160、空白 70、低清 50,其中 6 份为低清+重复的复合注入,按优先级归入重复)。报告见 quality_gate_report.md,检测器阈值全部经过语料实测校准,校准过程记录在 dirty_audit_report.md。

5.5 迭代记录

实验过程中四次较大的修改及其影响:

  1. 讲义解析器将 Heading 2 样式的正文段误判为标题,导致讲义正文丢失;修复后 FTS 索引块 14,710 → 19,211,简单类 Recall 提升约 20 个百分点;
  2. RRF 合并池截断导致只在单路出现的候选被挤出重排池;保留两路全部唯一候选后,Recall@5 提升 13.5 个百分点;
  3. 评测命中口径从文档级升级为三口径判定,修正模板副本语料下的系统性低估;
  4. 接入 OCR 预解析(独立环境 .venv-ocr + ocr_preparse.py):解析完整率 80% → 100%;期间发现文档编号从可检索文本中消失导致"按编号提问"的题目召回骤降,将 doc_id 写入扫描件/图片块前缀修复后,BM25 档 Recall@10 升至 90.54%。

6. 语料说明

  • 构成(5,179 份):题库 2,002(562 组真实高考真题 GAOKAO-Bench,Apache-2.0 + 1,440 组合成题)/ 讲义 1,000 / 表格 500 / 模拟扫描件 700 / 题目图片 300 / 注入脏数据 677。
  • 脏数据按故障类型反向设计:每一类对应一种真实故障模式与一个可指定检测器(重复、近重复、版本冲突、乱码、空白页、低清)。
  • 版权:所有数据仅用于学习与技术演示,来源与许可详见 SOURCES.md。
  • 语料生成脚本与评测集构建脚本位于仓库之外(体积与版权考虑),需要复现语料时可另行提供。

7. 运行模式(settings.yaml run_mode)

模式 嵌入/重排 LLM 适用
MODE_A(默认) 本地嵌入 + 云端重排 硅基流动 API 本机算力 + API 组合
MODE_B 本地 Ollama 本地 离线演示
MODE_CLOUD 硅基流动 API 硅基流动 API 未装本地模型时最快跑通

8. 运行环境与硬件适配

  • 实验机器:RTX 3050 Laptop 4GB / 16GB RAM / Windows 11。
  • bge-m3 本地嵌入实测约 31 chunks/s、峰值显存 1.1GB;Ollama 3B Q4(约 2.2GB)不应与嵌入/重排模型同时常驻。
  • 重排默认走云端(rerank.mode: siliconflow):本机 4GB 显存与桌面 GUI 共享,本地 CrossEncoder(FP32 约 2.2GB)实测触发 WDDM 显存分页抖动(CPU 空闲、GPU 100%、速度极慢);云端使用同款 bge-reranker-v2-m3,单次约 0.3s。关闭大应用后可切回 local 验证本地路径。
  • CUDA 版 torch(当前 venv 若是 CPU 版,需重装):
    pip uninstall -y torch
    pip install torch==2.12.1 --index-url https://download.pytorch.org/whl/cu126
  • 无 GPU 也可运行:嵌入/重排自动降级 CPU(settings.yaml 中 embed.batch_size 建议调至 8–16),或切换 MODE_CLOUD。
  • 模型下载镜像:settings.yaml embed.hf_endpoint 默认 https://hf-mirror.com。
  • OCR 预解析(扫描件/图片,可选):paddlepaddle 2.6 要求 protobuf ≤3.20.2,与主环境 chromadb 链路(protobuf ≥6.33.5)不兼容,因此 OCR 在独立环境 .venv-ocr 中运行,识别结果落盘为解析缓存、由主流水线消费:
    D:\Python3.11\python.exe -m venv .venv-ocr
    .\.venv-ocr\Scripts\pip.exe install paddlepaddle==2.6.2 paddleocr==2.7.3 "numpy>=1.23,<2"
    .\.venv-ocr\Scripts\python.exe -m src.ingestion.ocr_preparse --categories scanned images
    python -m src.indexing.dual_writer    # 主环境重索引(消费解析缓存)

9. 局限性与后续方向

  • 语料与评测集的规模较小(79 条评测题),后续可用 build_golden.py 的候选生成 + 人工复核流程扩充;
  • OCR 识别精度受扫描件倾斜/噪声/水印影响,低置信度文档按时间盒止损规则保持标题级兜底(ocr_preparse.py 中 MIN_CONFIDENCE=0.75);
  • 未做模型预训练/微调、多租户权限(仅文档级 ACL 预留)、移动端;文档规模按万级设计;
  • 检索延迟在云端重排配置下约 1.4–2.2s(API 往返);本地 GPU 重排可达 150–280ms,受 4GB 共享显存限制。

参考资料

About

企业级中文教育知识库 RAG 数据工程项目:入库质量门 + 混合检索 + 三层评测闭环|5,179 份语料实测:脏数据拦截 100%/误伤 0,Recall@5 81.1%,Faithfulness 100%

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages