Skip to main content
Glama
zhtong-star

Modular RAG MCP Server

by zhtong-star

Modular RAG MCP Server

一个可插拔、可观测的模块化 RAG(检索增强生成)服务框架。通过 MCP(Model Context Protocol)标准协议对外暴露工具接口,让 Claude、Copilot 等 AI 助手直接调用私有知识库;配套 Streamlit 管理面板与自动化评估体系,实现从文档摄取到在线检索的完整闭环。


📖 目录


🏗️ 项目简介

本项目把 RAG 的核心环节——混合检索(Hybrid Search + RRF)多模态视觉处理(Image Captioning)RAG 评估(Ragas + Custom)——与当下热门的应用协议 MCP(Model Context Protocol) 串联为一个完整、可运行的工程系统。

设计定位

  1. 全链路可插拔:LLM / Embedding / Reranker / Splitter / VectorStore / Evaluator 每个能力维度都定义了抽象接口 + 工厂模式,通过 config/settings.yaml 一键切换后端,零代码修改即可适配不同 Provider 与部署环境。

  2. 白盒化可观测:Ingestion 与 Query 两条链路的每一个中间状态(耗时、输入输出、错误)都被 TraceContext 记录到 logs/traces.jsonl,并通过 6 页面 Streamlit Dashboard 可视化呈现,慢查询诊断不再靠猜。

  3. 标准协议接入:遵循 MCP 协议(stdio + JSON-RPC 2.0),可直接对接 Claude Desktop、GitHub Copilot、Cursor 等任意 MCP Client,一次开发、多处调用。

  4. 数据驱动的质量闭环:集成 Custom(Hit Rate / MRR)与 Ragas(Faithfulness 等)双评估体系,配合 Golden Test Set 回归基线,让检索质量的每次调优都有数据可依。

一段话讲清楚它做什么

丢进一篇 PDF → 系统将其解析、分块、LLM 精炼、生成图片描述、向量化编码、写入多路存储 → 一个可检索的知识库就绪。之后任何 MCP Client 都能用自然语言查询它,系统做 jieba 分词 + Dense/Sparse 并行混合检索 + RRF 融合排序 + 可选重排,最终返回带引用来源的 Markdown 结构化答案,必要时还能附带检索到的图片。


✨ 核心能力

模块

能力

说明

Ingestion Pipeline

PDF → Markdown → Chunk → Transform → Embedding → Upsert

6 阶段全链路数据摄取,SHA256 幂等去重,支持多模态图片描述

Hybrid Search

Dense(向量)+ Sparse(BM25)+ RRF 融合 + 可选 Rerank

两段式检索架构:粗排召回 + 精排重排

MCP Server

标准 MCP 协议暴露 Tools

query_knowledge_hub / list_collections / get_document_summary

Multimodal

Image-to-Text 策略

Vision LLM 自动为文档图片生成描述并缝合进 Chunk,"搜文字出图"

Observability

全链路白盒化追踪

双链路(摄取/查询)独立打点,JSON Lines 持久化

Dashboard

Streamlit 6 页面管理平台

总览 / 数据浏览 / 摄取管理 / 摄取追踪 / 查询追踪 / 评估面板

Evaluation

Custom + Ragas 双评估体系

Golden Test Set 回归测试,拒绝"凭感觉"调优

可插拔架构

6 大抽象接口 + 工厂模式

LLM ×4 / Embedding ×3 / Reranker ×2 / Splitter / VectorStore / Evaluator


🏛️ 系统架构

总体设计

系统由离线摄取在线查询两大链路构成,共享同一套存储层:

┌─────────────────────────────────────────────────────────────────────────┐
│                        Modular RAG MCP Server                           │
│                                                                          │
│  ┌──────────────────────────────┐    ┌──────────────────────────────┐   │
│  │  离线 Ingestion 链路(摄取)    │    │  在线 Query 链路(查询)       │   │
│  │                              │    │                              │   │
│  │  ① 文件完整性检查 (SHA256)     │    │  ① MCP 工具调用 (stdio)       │   │
│  │  ② PDF 解析 (MarkItDown)      │    │  ② 查询预处理 (jieba 分词)    │   │
│  │  ③ 递归分块 (chunk=1000)      │    │  ③ 并行混合检索 (Dense+Sparse)│   │
│  │  ④ 变换管线 (Refine+Enrich+   │    │  ④ RRF 融合排序 (k=60)        │   │
│  │     Caption)                  │    │  ⑤ 可选 Rerank               │   │
│  │  ⑤ 向量编码 (Dense+Sparse)    │    │  ⑥ 响应构建 (Markdown+引用+   │   │
│  │  ⑥ 多路存储 (3 个后端)         │    │     图片)                     │   │
│  └──────────────────────────────┘    └──────────────────────────────┘   │
│                                                                          │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │  存储层:ChromaDB(稠密向量)+ BM25 Index(稀疏索引)               │   │
│  │          + ImageStorage(图片索引)+ SQLite(摄取历史/幂等)         │   │
│  └──────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘

五层分层架构

代码按依赖方向分为五层,层间通过抽象基类解耦,上层依赖下层接口而非具体实现:

   ┌──────────────────────────────────────────────────────────┐
   │   AI 助手(Claude / Copilot / Cursor 等 MCP Client)        │
   └──────────────────────────┬───────────────────────────────┘
                              │ MCP Protocol (stdio JSON-RPC 2.0)
   ┌──────────────────────────▼───────────────────────────────┐
   │  src/mcp_server/    【协议服务层】                          │
   │  server.py → protocol_handler.py → tools/(3 个 Tool)     │
   └──────────────────────────┬───────────────────────────────┘
                              │ 调用
   ┌────────────┬─────────────▼─────────────┬─────────────────┐
   │            │                           │                 │
   │ src/       │ src/core/query_engine/    │ src/            │
   │ ingestion/ │ 【检索引擎层】             │ observability/  │
   │ 【业务管道】│ HybridSearch → RRF →      │ 【可观测性层】   │
   │ Pipeline   │ Rerank → Response         │ Dashboard +     │
   │ 6 阶段     │                           │ Evaluation      │
   └────────────┴─────────────┬─────────────┴─────────────────┘
                              │ 依赖抽象
   ┌──────────────────────────▼───────────────────────────────┐
   │  src/libs/   【可插拔库层】                                 │
   │  LLM | Embedding | Loader | Splitter | VectorStore        │
   │  | Reranker | Evaluator(Base 类 + Factory 模式)           │
   └──────────────────────────┬───────────────────────────────┘
                              │ 读写
   ┌──────────────────────────▼───────────────────────────────┐
   │  src/core/    【基础设施层】                                │
   │  settings.py | types.py | trace/(配置 + 数据类型 + 追踪)  │
   └──────────────────────────────────────────────────────────┘

层级依赖规则:上层可调用下层,下层绝不引用上层;src/libs/ 是纯抽象层,不依赖任何业务层;src/core/ 只含纯数据与配置,零业务逻辑。

链路一:离线摄取(Ingestion Pipeline)

IngestionPipeline::run() 将一篇 PDF 逐步转换为可检索的向量与索引,共 6 个阶段:

阶段

组件

作用

① 完整性检查

SQLiteIntegrityChecker

计算 SHA256 哈希,查询历史记录,已处理文件自动跳过(幂等)

② 文档加载

PdfLoader

MarkItDown 转 Markdown + PyMuPDF 提取图片,插入 [IMAGE: id] 占位符

③ 文档分块

DocumentChunker + RecursiveSplitter

chunk_size=1000 / overlap=200,生成确定性 Chunk ID,继承源数据

④ 变换管线

ChunkRefiner + MetadataEnricher + ImageCaptioner

LLM 精炼去噪、生成 title/summary/tags、为图片生成描述;LLM 失败自动降级为规则模式

⑤ 向量编码

BatchProcessorDenseEncoder + SparseEncoder

Dense:Embedding API(2560 维);Sparse:jieba 分词 + BM25 词频统计(本地零成本)

⑥ 多路存储

VectorUpserter + BM25Indexer + ImageStorage

分别写入 ChromaDB、JSON 倒排索引、SQLite 图片索引;三路并行独立,一路失败不影响其他

幂等性设计:SHA256 文件级去重 + Chunk ID 确定性生成({doc_id}_{index:04d}_{content_hash[:8]}),同一文件重复提交自动跳过,--force 可强制重处理。

链路二:在线查询(Query Pipeline)

MCP Client 发出 JSON-RPC 请求,经 ProtocolHandler 分发到对应 Tool,核心链路如下:

MCP Client (stdio)
  └─ tools/call: query_knowledge_hub
      └─ QueryProcessor      → jieba 分词 + 停用词过滤 + 过滤语法解析
      └─ HybridSearch        → DenseRetriever + SparseRetriever 并行(ThreadPool)
      └─ RRFFusion (k=60)    → Σ 1/(k + rank_i),排名级融合,无需分数归一化
      └─ Reranker(可选)     → Cross-Encoder / LLM 精排,失败保持原序
      └─ ResponseBuilder     → Markdown 内容 + [1][2] 引用标记 + 多模态图片
      └─ TraceCollector      → 写入 logs/traces.jsonl
      └─ MCP Response        → TextContent + 可选 ImageContent

并行与降级:Dense 与 Sparse 通过 ThreadPoolExecutor 并行执行,总耗时取二者最大值;任一路失败,另一路结果直接作为最终结果,两路皆失败才报错——单点故障不阻断整体查询。

可观测性与评估

  • TraceContext:每个阶段独立计时,记录 {name, elapsed_ms, details},最终持久化为 logs/traces.jsonl(每行一条合法 JSON,可按类型/时间/集合过滤)。

  • Streamlit Dashboard(6 页面):系统总览 / 数据浏览 / 摄取管理 / 摄取追踪(阶段瀑布图)/ 查询追踪(Dense vs Sparse 对比)/ 评估面板。

  • 评估体系CustomEvaluator(Hit Rate、MRR 等确定性指标)+ RagasEvaluator(Faithfulness、Answer Relevancy、Context Precision 等 LLM-as-Judge 语义指标),由 CompositeEvaluator 并行组合、EvalRunner 基于 Golden Test Set 批量运行。


💡 技术亮点

🔌 全链路可插拔架构:LLM / Embedding / Reranker / Splitter / VectorStore / Evaluator 均定义抽象基类 + 工厂模式,通过 settings.yaml 一键切换 Provider(LLM ×4、Embedding ×3、Reranker ×2),替换组件不修改任何上游代码。

🔍 混合检索 + RRF 融合:BM25 稀疏检索解决专有名词精确匹配,Dense Embedding 解决同义词语义匹配,两者互补;RRF 基于排名而非原始分数融合(RRF_score = Σ 1/(k+rank)),免去跨路分数归一化,输出完全确定性。

🖼️ 多模态图像处理:采用 Image-to-Text 策略,Vision LLM(Qwen3-VL)自动为文档图片生成描述并缝合进 Chunk,复用纯文本 RAG 链路即可实现"搜文字出图";图片以 base64 编码随 MCP 响应返回。

📡 MCP 生态集成:遵循 MCP 标准协议(stdio + JSON-RPC 2.0),stdout 专用于协议消息、所有日志重定向 stderr;阻塞 I/O 用 asyncio.to_thread() 放入线程池;主线程预加载 chromadb/onnxruntime 规避 import 死锁。可直接对接任意 MCP Client,零前端开发。

🧪 三层测试体系:Unit(无外部依赖,Mock-First)/ Integration(跨模块协作,LLM 相关用 marker 可选运行)/ E2E(全链路端到端),覆盖独立模块逻辑、模块间交互与完整链路。

⛓️ 幂等与优雅降级:SHA256 文件级去重 + 确定性 Chunk ID 保证重复摄取不产生脏数据;LLM 失败回退规则、Dense/Sparse 互备、Rerank 失败保序,任何单点故障都不中断主链路。

📊 数据驱动迭代:Golden Test Set 回归基线 + 双评估体系,让检索调优(如调整 RRF k、chunk_size)有量化指标可循。


🛠️ MCP 工具

工具名

描述

输入参数

query_knowledge_hub

知识库混合检索(核心工具)

query(必填)、top_k(默认 5)、collection(可选)

list_collections

列出所有集合及统计信息

include_stats(默认 true)

get_document_summary

按文档 ID 获取标题/摘要/标签

doc_id(必填)、collection(可选)


🧰 技术栈

┌───────────────────────────────────────────────────────────────┐
│  交互层:Streamlit(Dashboard)· MCP Protocol(JSON-RPC over  │
│          stdio)· Python 3.10+ · asyncio                       │
├───────────────────────────────────────────────────────────────┤
│  RAG 核心:                                                   │
│    检索     Dense: Qwen3-Embedding-4B(2560 维)              │
│             Sparse: 自实现 BM25(jieba 分词)                  │
│    融合     RRF(k=60,排名级融合)                             │
│    重排     Cross-Encoder / LLM Rerank(可插拔)               │
│    生成/变换 DeepSeek-V3.2 等(OpenAI 兼容)                    │
├───────────────────────────────────────────────────────────────┤
│  存储层:ChromaDB(向量)· BM25 JSON Index(稀疏)·            │
│          SQLite(图片索引 / 摄取历史)· 文件系统                │
├───────────────────────────────────────────────────────────────┤
│  可观测性:TraceContext · JSON Lines · Ragas · CustomEvaluator│
│             · pytest(三层测试)· Golden Test Set              │
└───────────────────────────────────────────────────────────────┘

关键依赖mcp(官方 SDK)、chromadblangchain-text-splittersmarkitdown[pdf] + PyMuPDFjiebaopenai(兼容 SiliconFlow / Azure / DeepSeek)、ollamaragasstreamlitsentence-transformers(可选重排)。

支持的 Provider:LLM ×4(OpenAI 兼容 / Azure / DeepSeek / Ollama)、Embedding ×3、Rerank ×2(LLM / Cross-Encoder)、Vision LLM(Qwen3-VL 等)。


📂 项目结构

MODULAR-RAG-MCP-SERVER/
├── config/
│   ├── settings.yaml              # 全局配置中心(LLM/Embedding/检索/摄取…)
│   └── prompts/                   # 各阶段 Prompt 模板(精炼/元数据/图片描述/重排)
├── documents/                     # 待摄取原始文档
├── data/db/                       # 运行时数据(chroma/ bm25/ 图片索引/ 摄取历史)
├── logs/traces.jsonl              # 全链路追踪 JSON Lines
├── scripts/                       # CLI 入口(ingest/query/evaluate/start_dashboard/探测脚本)
├── src/
│   ├── core/                      # 【基础设施层】settings、types、query_engine、response、trace
│   ├── ingestion/                 # 【业务管道层】pipeline、chunking、embedding、storage、transform
│   ├── libs/                      # 【可插拔库层】llm、embedding、loader、splitter、vector_store、reranker、evaluator
│   ├── mcp_server/                # 【协议服务层】server、protocol_handler、tools/
│   └── observability/             # 【可观测性层】logger、dashboard(6 页)、evaluation
├── tests/                         # unit / integration / e2e / fixtures(Golden Test Set)
├── DEV_SPEC.md                    # 开发规格文档
├── main.py                        # 项目主入口(注册为 mcp-server CLI)
└── pyproject.toml                 # 项目元数据与依赖

🛠️ 我是怎么做的:Harness 工程方法

这个项目的构建遵循 Harness 工程思路——不是"让一个模型一次写完所有代码",而是 Initializer + Coding Loop 的最小闭环:

先拆解 → 再循环执行 → 靠外部状态保持连续性 → 靠确定性验证保证质量

核心哲学是五个字:拆、循环、记、验、守

1. 拆:Initializer 把需求拆成可验证的 Feature

不直接写代码,先把需求整理成后续 Agent 可反复执行的任务蓝图(AppSpec.md),再由 Initializer 把大任务拆成一组细粒度、可执行、可验证的 Feature,产出 feature_list.json 状态文件。

本项目被拆成 24 个独立 Feature(F-001 → F-024),每个 Feature 明确四件事:

{
  "id": "F-005",
  "name": "VectorStore 抽象层",
  "description": "BaseVectorStore 抽象类 + VectorStoreFactory + ChromaStore 实现",
  "files": ["src/libs/vector_store/*.py"],
  "depends_on": ["F-001", "F-002"],
  "verification": "python -m pytest tests/unit/test_vector_store.py -v",
  "acceptance": "ChromaStore 可 upsert/query/delete/get_by_ids,cosine 排序正确"
}

F-001(核心数据类型)到 F-024(端到端集成测试),依赖关系清晰、按拓扑序执行:先打通 F-001 types / F-002 settings / F-007 integrity 等无依赖地基,再到 F-013 pipeline 编排、F-017 hybrid search、F-020 MCP Server,最后是 F-021~F-024 工具与端到端验收。

2. 循环:Coding Loop 每轮只做一件事

每轮启动一个全新的 Coding Agent,只完成一个明确的小任务,靠外部状态接力:

┌──────────────────────────────────────────────────────────┐
│                   Coding Loop 单轮协议                     │
│                                                          │
│  ① 启动全新 Agent(无历史上下文)                           │
│  ② Agent 读取 3 个外部文件:                              │
│     - feature_list.json → 知道当前该做哪个 Feature        │
│     - progress.md      → 知道前面完成了什么、踩了什么坑     │
│     - 目标代码文件      → 了解当前代码状态                  │
│  ③ Agent 完成一个 Feature                                 │
│  ④ 确定性验证 Gate(不是 Agent 自评):                    │
│     - pytest 必须 PASS                                    │
│     - mypy/pyright 类型检查必须 PASS                       │
│     - ruff lint 必须 PASS                                 │
│  ⑤ 验证通过后,由系统(非 Agent)更新状态:                 │
│     - feature_list.json: status → completed               │
│     - progress.md: 追加交接记录                            │
│     - git commit: 提交代码 + 验证结果                      │
│  ⑥ Agent 立即退出,下一轮由新 Agent 接力                   │
└──────────────────────────────────────────────────────────┘

3. 记:外部状态是系统的核心记忆

不把连续性寄托在模型上下文里,每个 Agent 启动时从三份持久化信息快速接手:

外部状态

作用

feature_list.json

所有 Feature 的定义、依赖、状态、验证命令;状态由验证结果决定,不由 Agent 自评,永远反映真实进度

progress.md

每轮完成后的交接记录(做了什么、结果如何、踩了什么坑),是新 Agent 的 onboarding 材料

Git Log

每个 Feature 一个 commit,feat(F-xxx): description 命名,git log --oneline 就是天然的任务完成清单

4. 验:确定性验证 Gate

每个 Feature 都有明确的验证命令和预期输出,pytest pass ≠ 代码完成,pytest pass = 代码至少通过了预定义的确定性检查。通过才更新状态、提交、进入下一轮;失败则记录失败原因,由下一轮新 Agent 接手修复——质量不由"AI 说做好了就是做好了"决定。

5. 守:Human-in-the-Loop 关键节点

高度自动化但并非无人值守,在以下节点设计人工确认断点

断点时机

触发条件

本项目实例

高风险依赖选择

Feature 涉及关键依赖引入

PDF Loader 选择 MarkItDown vs pdfminer

架构决策点

跨多个 Feature 的接口设计

LLM / Embedding 抽象基类签名

失败重试 > 2 次

同一 Feature 连续失败

Pipeline 编排器集成反复失败时人工介入

关键界面变更

修改已有公共 API

VectorStore 接口变更影响所有 consumer

集成验证前

最后几个 Feature 完成

端到端验收通过后再正式发布

为什么这么做

传统方式让一个 Agent 一次做完所有事,产出的代码无法验证、无法复现、无法交接。而 Initializer + Coding Loop 最小闭环让每个 Feature 都有明确的输入文件、输出文件、验证命令和依赖关系,把"靠 AI 记忆"变成"靠外部状态 + 确定性验证",把一个复杂项目稳扎稳打地交付出来。


🚀 快速开始

# 1. 克隆并进入项目
git clone <repo-url>
cd MODULAR-RAG-MCP-SERVER

# 2. 安装依赖(Python 3.10+)
pip install -e ".[dev]"

# 3. 配置 API Key:从模板复制(config/settings.yaml 已被 git 忽略,请勿提交真实密钥)
cp config/settings.yaml.example config/settings.yaml
#   然后编辑 config/settings.yaml,填写 LLM / Embedding 的 API Key 与 base_url

# 4. 摄取文档:将 PDF 放入 documents/,执行
python scripts/ingest.py --path documents/ --collection knowledge_hub

# 5. 查询验证
python scripts/query.py --query "你的问题" --collection knowledge_hub

# 6. 启动 Dashboard
python scripts/start_dashboard.py

# 7. 启动 MCP Server(供 Claude / Copilot 等 Client 调用)
mcp-server

配置 Provider 切换、新文档格式扩展等,只需修改 settings.yaml 或基于 src/libs/ 的抽象接口新增实现——可插拔架构让这些改动不影响任何上游代码。


📚 配套文档

文档

内容

DEV_SPEC.md

开发规格文档:项目概述、核心特点、技术选型、测试方案、系统架构、排期与可扩展性