Skip to main content
Glama
FireWizard-V9

self_rag_mcp

Self-RAG 检索引擎

自反思检索增强生成 系统,基于 LangGraph 和 Qdrant 构建,并通过 SSE 传输以 MCP(模型上下文协议)服务器形式对外提供。

与盲目检索并生成的标准 RAG 流水线不同,Self-RAG 让 LLM 成为自身质量控制的积极参与者——决定是否检索、对检索结果进行评分、验证生成内容,并在答案不够好时进行重试。


目录


Related MCP server: mcp-rag-agent

什么是 Self-RAG?

标准 RAG 存在一个根本性问题:它总是执行检索(即使没有必要),从不检查检索到的文档是否相关,也从不验证生成的答案是否真正基于这些文档。

Self-RAG(首次提出于论文 Self-RAG: Learning to Retrieve, Generate, and Critique Through Self-Reflection)通过在每个阶段插入反思步骤来解决这一问题:

阶段

标准 RAG

Self-RAG

检索决策

总是检索

LLM 决定是否需要检索

文档过滤

使用所有检索到的文档

LLM 对每个文档的相关性进行评分

生成

只生成一次

生成,然后验证是否基于上下文

答案质量

不检查

LLM 对有用性进行评分,必要时重试

本实现使用 LangGraph 将 Self-RAG 流程建模为带条件边的有状态有向图,支持动态路由、重试循环和完整的状态可追溯性。


架构概览

┌─────────────────────────────────────────────────────────────────┐
│                        MCP Client (SSE)                         │
│                    rich interactive terminal                     │
└──────────────────────────┬──────────────────────────────────────┘
                           │ SSE  http://127.0.0.1:8000/sse
┌──────────────────────────▼──────────────────────────────────────┐
│                      MCP Server (SSE)                           │
│              MCPServer  ·  3 tools exposed                      │
│         rag_answer  ·  retrieve  ·  server_health               │
└──────────┬──────────────────────────────┬───────────────────────┘
           │                              │
┌──────────▼──────────┐       ┌───────────▼──────────────────────┐
│   Self-RAG Graph    │       │       Hybrid Retriever           │
│   (LangGraph)       │       │                                  │
│                     │       │  1. Qdrant Hybrid Search         │
│  retrieval_decision │       │     Dense (OpenAI embeddings)    │
│  retrieve           │       │     Sparse (BM25 / FastEmbed)    │
│  relevance_grader   │       │     Fusion: RRF                  │
│  context_builder    │       │                                  │
│  generator          │       │  2. MMR Diversity Reranking      │
│  support_grader     │       │                                  │
│  usefulness_grader  │       │  3. FlashRank Cross-Encoder      │
│                     │       │     (ms-marco-MiniLM-L-12-v2)    │
└──────────┬──────────┘       │                                  │
           │                  │  4. Parent Document Expansion    │
           │                  └───────────────┬──────────────────┘
           │                                  │
┌──────────▼──────────────────▼──────────────────────────────────┐
│                         Qdrant                                  │
│                                                                 │
│   self_rag_documents  (child chunks  · dense + sparse)         │
│   self_rag_parents    (parent chunks · dense only)             │
└─────────────────────────────────────────────────────────────────┘

Self-RAG 图流程

flowchart TD
    START([START]) --> RD[retrieval_decision]

    RD -->|should_retrieve = true| RET[retrieve]
    RD -->|should_retrieve = false| GEN[generator]

    RET --> REL[relevance_grader]
    REL --> CTX[context_builder]
    CTX --> GEN

    GEN --> SUP[support_grader]

    SUP -->|fully_supported\npartially_supported| USE[usefulness_grader]
    SUP -->|not_supported\n& retry_count < max_retries| INC1[increment_retry]
    SUP -->|not_supported\n& retry_count >= max_retries| USE

    INC1 --> GEN

    USE -->|useful| END([END])
    USE -->|not_useful\n& retry_count >= max_retries| END
    USE -->|not_useful\n& retry_count < max_retries| INC2[increment_retry_for_retrieval]

    INC2 --> RET

    style START fill:#2d6a4f,color:#fff
    style END fill:#2d6a4f,color:#fff
    style RD fill:#1d3557,color:#fff
    style RET fill:#457b9d,color:#fff
    style REL fill:#457b9d,color:#fff
    style CTX fill:#457b9d,color:#fff
    style GEN fill:#e63946,color:#fff
    style SUP fill:#f4a261,color:#000
    style USE fill:#f4a261,color:#000
    style INC1 fill:#6d6875,color:#fff
    style INC2 fill:#6d6875,color:#fff

节点参考

retrieval_decision

图的入口点。LLM 分析用户的问题,并决定是否确实需要外部知识检索。

  • 对话式查询("Hello""What is 2+2")→ 跳过检索,直接进入 generator

  • 事实性 / 领域性查询 → 进入 retrieve

使用结构化输出:RetrievalDecision { thought: str, answer: "YES" | "NO" }


retrieve

针对 Qdrant 运行完整的混合检索流水线

  1. 混合搜索 — 结合稠密(OpenAI text-embedding-3-small)和稀疏(通过 FastEmbed 实现的 BM25)向量,在服务端使用倒数排名融合(RRF)进行融合

  2. MMR — 最大边际相关性重排序,以增加多样性(避免返回近乎重复的块)

  3. FlashRank — 轻量级 ONNX 交叉编码器重排序器(ms-marco-MiniLM-L-12-v2),用于最终相关性评分

  4. 父块扩展 — 子块用于精确检索,但将完整父块返回给 LLM 以提供更丰富的上下文


relevance_grader

过滤检索到的文档。LLM 针对问题对每个文档逐一评分。

  • 评分为 YES 的文档 → 保留为 relevant_documents

  • 评分为 NO 的文档 → 丢弃

使用结构化输出:RelevanceGrade { thought: str, answer: "YES" | "NO" }


context_builder

将相关文档格式化为结构化的 XML 上下文块,针对 LLM 注意力进行优化:

<context>
  <document index="1">
    <metadata>Source: hr.pdf | Relevance Score: 0.9821</metadata>
    <content>
      Human Resource Management (HRM) refers to...
    </content>
  </document>
</context>

generator

LLM 仅使用上下文块中的事实生成答案。提示词明确指示模型不要使用外部知识,并引用文档索引([Doc 1])。


support_grader

验证生成的答案是否基于上下文。逐条声明进行审计。

返回以下之一:

  • fully_supported — 每条声明都有上下文支撑

  • partially_supported — 部分声明有依据,部分没有

  • not_supported — 答案包含幻觉或与上下文矛盾

使用结构化输出:SupportGrade { thought: str, label: "fully_supported" | "partially_supported" | "not_supported" }


usefulness_grader

评估答案是否真正解决了用户的问题——即使答案有依据,也可能回避问题或不完整。

返回以下之一:

  • useful — 答案直接满足查询

  • not_useful — 答案偏离主题、不完整或回避问题

使用结构化输出:UsefulnessGrade { thought: str, label: "useful" | "not_useful" }


increment_retry / increment_retry_for_retrieval

簿记节点,在循环回 generatorretrieve 之前递增图状态中的 retry_count


路由逻辑

路由器

条件

下一节点

route_after_retrieval_decision

should_retrieve = True

retrieve

should_retrieve = False

generator

route_after_support

fully_supportedpartially_supported

usefulness_grader

not_supportedretry_count < max_retries

increment_retrygenerator

not_supportedretry_count >= max_retries

usefulness_grader

route_after_usefulness

useful

END

not_usefulretry_count < max_retries

increment_retry_for_retrievalretrieve

not_usefulretry_count >= max_retries

END


检索流水线

Query
  │
  ▼
Qdrant Hybrid Search (Dense + BM25 + RRF)   k=20 candidates
  │
  ▼
MMR Diversity Reranking                      k=15 diverse docs
  │
  ▼
FlashRank Cross-Encoder                      top_k=4 final docs
  │
  ▼
Parent Document Expansion                    fetch full parent chunks
  │
  ▼
List[Document] → relevance_grader

为什么采用这种多阶段漏斗?

  • 混合搜索(稠密 + 稀疏)比单独使用任何一种都能获得更好的召回率——稠密向量捕捉语义匹配,BM25 捕捉精确关键词匹配

  • MMR 防止 LLM 看到 4 个近乎相同的块——强制多样性

  • FlashRank(ONNX int8 量化)以约 0.1 秒的时间提供交叉编码器质量,而完整的 PyTorch CrossEncoder 需要约 19 秒

  • 父块扩展意味着检索精度来自小子块,但 LLM 获得的是完整的周边上下文


摄取流水线

文档被分割为父子块层级结构

PDF Document
  │
  ├── Parent Chunk 1  (1200 chars, overlap=0)  → stored in self_rag_parents
  │     ├── Child Chunk 1a  (600 chars, overlap=150)  → stored in self_rag_documents
  │     ├── Child Chunk 1b
  │     └── Child Chunk 1c
  │
  ├── Parent Chunk 2
  │     ├── Child Chunk 2a
  │     └── Child Chunk 2b
  ...
  • 子块同时使用稠密 + 稀疏向量进行索引,以实现混合搜索精度

  • 父块仅存储稠密向量,用于检索后的上下文扩展

  • UUID 是确定性的(UUID5),因此重新摄取是幂等的


MCP 服务器与客户端

该系统以 MCP 服务器形式通过 SSE 传输对外提供,兼容任何 MCP 客户端(Claude Desktop、自定义客户端等)。

工具

工具

描述

rag_answer

运行完整的 Self-RAG 图——检索决策 → 检索 → 评分 → 生成 → 验证 → 重试

retrieve

仅进行原始混合检索,不进行生成或评分

server_health

返回检索器和重排序器组件的运行状态

交互式客户端

包含一个功能丰富的终端客户端,提供菜单驱动界面:

╭─────────────────────────────────╮
│ Self-RAG MCP Interactive Client │
│ Connected via SSE Transport     │
╰─────────────────────────────────╯

[1] 💬 Ask Question     (rag_answer)
[2] 🔍 Raw Search       (retrieve)
[3] 🏥 System Health    (server_health)
[4] 📋 List Tools
[0] 🚪 Exit

项目结构

self_rag_retrieval/
├── src/self_rag/
│   ├── clients/
│   │   ├── llm.py              # LiteLLM chat model + OpenAI embeddings (cached)
│   │   └── qdrant.py           # Qdrant client singleton
│   ├── core/
│   │   └── config.py           # Pydantic settings from .env
│   ├── graph/
│   │   ├── engine.py           # Compiled graph singleton (lru_cache)
│   │   ├── routes.py           # Conditional edge routing functions
│   │   └── workflow.py         # LangGraph StateGraph definition
│   ├── ingestion/
│   │   ├── chunker.py          # Parent-child chunk splitting
│   │   ├── indexer.py          # Qdrant collection management
│   │   ├── loaders.py          # PDF loader
│   │   └── pipeline.py         # Ingestion orchestration
│   ├── mcp/
│   │   ├── server.py           # MCPServer with 3 tools + startup warmup
│   │   ├── mcp_client.py       # Rich interactive terminal client
│   │   └── tools.py            # Tool implementations (answer, retrieve, health)
│   ├── models/
│   │   ├── graph_state.py      # LangGraph TypedDict state
│   │   └── schemas.py          # Pydantic structured output schemas
│   ├── nodes/
│   │   ├── context_builder.py  # XML context formatter
│   │   ├── generator.py        # LLM answer generation
│   │   ├── relevance_grader.py # Per-document relevance grading
│   │   ├── retrieval_decision.py # Retrieval necessity classifier
│   │   ├── retrieve.py         # Retrieval node
│   │   ├── support_grader.py   # Hallucination / grounding checker
│   │   └── usefulness_grader.py # Answer quality checker
│   ├── prompts/
│   │   ├── generation.py
│   │   ├── relevance.py
│   │   ├── retrieval.py
│   │   ├── support.py
│   │   └── usefulness.py
│   ├── retrieval/
│   │   ├── mmr.py              # Maximal Marginal Relevance
│   │   ├── reranker.py         # FlashRank ONNX cross-encoder
│   │   ├── retriever.py        # HybridRetriever orchestrator (cached)
│   │   └── vector_store.py     # Qdrant vector store (dense + sparse, cached)
│   └── services/
│       └── rag_service.py      # Business layer wrapping the graph
├── scripts/
│   └── ingest.py               # CLI ingestion script
├── tests/
│   ├── test_mcp_server.py
│   ├── test_mcp_tools.py
│   └── test_routes.py
├── docker-compose.yaml
├── pyproject.toml
└── .env

安装与配置

前置条件

  • Python 3.12+

  • uv 包管理器

  • Docker(用于 Qdrant)

  • OpenRouter API 密钥

1. 克隆仓库并安装依赖

git clone <repo-url>
cd self_rag_retrieval
uv sync

2. 配置环境

cp .env.example .env

编辑 .env

OPENROUTER_API_KEY=sk-or-v1-...

CHAT_MODEL=openrouter/openai/gpt-4.1-mini
EMBEDDING_MODEL=openai/text-embedding-3-small

QDRANT_URL=http://localhost:6333
QDRANT_COLLECTION=self_rag_documents
QDRANT_PARENT_COLLECTION=self_rag_parents

DATA_DIR=src/self_rag/data

3. 启动 Qdrant

docker compose up -d

4. 添加文档

将 PDF 文件放入 src/self_rag/data/

5. 摄取文档

# First time
uv run python scripts/ingest.py

# Full rebuild (wipes existing collections)
uv run python scripts/ingest.py --reset

配置

所有设置都在 .env 中,并由 Pydantic 验证。关键参数:

变量

默认值

描述

CHAT_MODEL

openrouter/openai/gpt-4.1-mini

用于所有评分和生成节点的 LLM

EMBEDDING_MODEL

openai/text-embedding-3-small

稠密嵌入模型

CHUNK_SIZE

600

子块大小(字符)

CHUNK_OVERLAP

150

子块重叠

PARENT_CHUNK_SIZE

1200

父块大小(字符)

RETRIEVAL_K_INITIAL

20

混合搜索候选池

RETRIEVAL_K_MMR

15

MMR 多样性过滤后的文档

RETRIEVAL_K_RERANK

4

FlashRank 后的最终文档

MAX_RETRIES

3

最大 Self-RAG 重试循环

LLM_TEMPERATURE

0.0

LLM 温度(0 = 确定性)


运行系统

终端 1 — 启动 MCP 服务器

uv run python src/self_rag/mcp/server.py

服务器在接受连接之前会预热所有模型:

INFO  Warming up retriever...
INFO  Warming up reranker...
INFO  Warming up graph...
INFO  Warmup complete — server ready.
INFO  Uvicorn running on http://127.0.0.1:8000

终端 2 — 启动交互式客户端

uv run python src/self_rag/mcp/mcp_client.py

示例问题(HR 领域)

What is Human Resource Management and what are its main objectives?
What are the nine broad areas of HRM activities identified by ASTD?
What is the difference between training and organizational development?
How does compensation and benefits management work in HRM?
What is the role of HRM in the new millennium?
What is the significance of HR planning in an organization?
Explain the scope of HRM and what it covers in an employee's working life.

运行测试

uv run pytest tests/ -v
tests/test_routes.py::test_retrieval_decision_retrieve          PASSED
tests/test_routes.py::test_retrieval_decision_skip              PASSED
tests/test_routes.py::test_support_fully_supported_...          PASSED
tests/test_routes.py::test_support_not_supported_retries...     PASSED
tests/test_routes.py::test_usefulness_useful_ends               PASSED
...
24 passed

测试覆盖:

  • test_routes.py — 所有路由分支(检索决策、支持评分、有用性评分)

  • test_mcp_tools.py — 使用模拟的 Qdrant/LLM 测试工具函数(空输入、截断、异常、健康检查)

  • test_mcp_server.py — 服务器类型、工具注册、工具描述


技术栈

组件

技术

图编排

LangGraph

LLM 路由

LiteLLM 通过 OpenRouter

LLM

OpenAI GPT-4.1-mini(通过 OpenRouter)

嵌入

OpenAI text-embedding-3-small(通过 OpenRouter)

向量数据库

Qdrant

稀疏嵌入

FastEmbed BM25

重排序器

FlashRank ms-marco-MiniLM-L-12-v2(ONNX int8)

MCP 框架

MCP Python SDK v2

设置

Pydantic Settings

终端 UI

Rich

包管理器

uv

运行时

Python 3.12

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Adaptive Retrieval-Augmented Self-Refinement MCP Server — a closed-loop system that lets LLMs iteratively verify and correct their own claims using uncertainty-guided retrieval.
    11
    1
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Exposes a Retrieval-Augmented Generation pipeline as MCP tools, allowing users to index documents and query them through any MCP-compatible client like Claude or IDEs.

View all related MCP servers

Related MCP Connectors

  • AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.

  • MCP server exposing the Backtest360 engine API as tools for AI agents.

  • MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/FireWizard-V9/self_rag_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server