# Rag.Playground **Repository Path**: ymjake/rag-playground ## Basic Information - **Project Name**: Rag.Playground - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-13 - **Last Updated**: 2026-06-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Rag.Extensions 基于 `Microsoft.Extensions.DataIngestion`、`VectorData`、`AI` 的 .NET RAG 基础设施实践。 ## 架构 ### 检索 ### Classic RAG ``` 用户 Query │ ▼ QueryExpansionProcessor │ 生成 query variants ▼ QdrantCollection.HybridSearchAsync │ 3 路 prefetch + RRF: ├─ dense prefetch → OpenAI /embed → Vectors["embedding"] ├─ sparse prefetch → Qdrant 原生 BM25 → Vectors["content-bm25"] └─ sparse prefetch → TEI /embed_sparse → Vectors["content-splade"] │ └─ RRF fusion → top-k │ ▼ ├─ 多 variants 去重 ├─ RerankingResultProcessor → TEI /rerank ├─ ParentContextResultProcessor (窗口扩展) └─ TakeTopResultsProcessor (topK 裁剪) │ ▼ RetrievalResults → (可选) IChatClient → Answer + Citations ``` ### Agentic RAG ``` 用户 Query │ ▼ LlmSubQuestionPlanner │ tools metadata + query ▼ AgenticRetrievalPlan │ sub-queries ▼ ParallelAgenticQueryExecutor │ ├─ DataRetrievalAgenticTool │ └─ IRetriever │ └─ RetrievalPipeline │ └─ Qdrant dense + BM25 + SPLADE + RRF │ ▼ ChatAgenticResultSynthesizer │ 基于 citations 生成最终回答 ▼ Answer + Steps + Citations + Metadata ``` ### GraphRAG Sample GraphRAG 当前作为独立 sample 验证,不接入主 `SampleWebApi`,也不接入 Agentic RAG 主链路。 ```text 文档上传 │ ▼ GraphIngestionBackgroundService │ 后台异步处理 ▼ Microsoft.Extensions.DataIngestion.IngestionPipeline │ ├─ DocumentReader ├─ DocumentProcessors ├─ HeaderChunker └─ GraphChunkWriter │ ▼ Neo4j Document / Section / Chunk 手动触发 entity extraction │ ▼ IChatClient 抽取 Entity / Relation │ ▼ Neo4j Entity / RELATED_TO / evidenceChunkId 查询 │ ├─ /api/graph/search → Neo4jGraphRetriever ├─ /api/graph/answer → 自定义 graph answer └─ /api/graph/maf/answer → Neo4j.AgentFramework.GraphRAG ContextProvider ``` ### 当前边界 当前项目阶段性收敛在三条已经跑通的链路: - **Classic RAG**:`dense + BM25 + SPLADE + RRF + rerank + parent-child + answer` - **Agentic RAG**:`LLM planner + knowledge tool + parallel execution + synthesizer` - **GraphRAG Sample**:独立 Neo4j sample,用来验证图检索和官方 Neo4j GraphRAG provider - `RAG`:一次检索,一次回答 - `Agentic RAG`:先做 query planning / sub-question decomposition,再调用 knowledge tool 检索并汇总回答 - `GraphRAG`:离线抽取实体关系,查询时通过图关系和证据 chunk 生成上下文 - `DeepSearch / DeepResearch`:在 Agentic RAG 之上继续增加多轮补查、反思、校验、报告生成,工程形态更接近工作流系统、多 Agent 编排或 workflow 本阶段明确不继续推进这些方向: - `DeepSearch / DeepResearch` - workflow graph - A2A / SubAgent / 多 Agent 编排 - 让 Agent 自己选择 BM25、SPLADE、RRF、rerank 等底层检索算法 - 把 GraphRAG 直接接入 Agentic RAG 主链路 原因: - 当前知识库与单文档 / 小型文档集场景下,`Hybrid Retrieval + Rerank + Parent-Child + Agentic decomposition` 已经足够形成有效闭环 - `DeepSearch` 会显著增加延迟、Token 成本、调试复杂度和评估难度 - 对通用 RAG 基础设施项目来说,先把单 Agent 的检索、工具抽象和回答链路做稳,比过早引入重工作流 / 多 Agent 架构更有复用价值 - GraphRAG 先保持独立 sample,只有跑出明确价值后再考虑包装成 Agentic tool DeepSearch / DeepResearch 相关调研先保留为背景知识,不进入当前实现主线。 ### 写入 #### Classic RAG 写入 ``` 文档 → DocumentReader → DocumentProcessors → HeaderChunker → ChunkMetadataStampingWriter → QdrantCollection.UpsertAsync │ ├─ dense embedding → OpenAI /embed → Vectors["embedding"] ├─ BM25 原文 → Document { Model = "qdrant/bm25" } → Vectors["content-bm25"] └─ SPLADE → TEI /embed_sparse → Vectors["content-splade"] ``` #### GraphRAG 写入 ``` 文档 → DocumentReader → DocumentProcessors → HeaderChunker → GraphChunkWriter → GraphIngestionService → Neo4j ``` 说明: - `Microsoft.Extensions.DataIngestion` 负责读取、清洗、切片和 writer 编排 - Classic RAG 的 writer 是 `VectorStoreWriter` - GraphRAG 的 writer 是 `GraphChunkWriter` - GraphRAG 的实体 / 关系抽取是后续离线步骤,不在上传请求中同步执行 ## 项目结构 | 项目 | 说明 | |------|------| | `Rag.Extensions` | 文档处理器(清洗、规范化、去脏) | | `Rag.Extensions.DataIngestion.PdfPig` | PDF 读取 | | `Rag.Extensions.DataIngestion.OpenXml` | DOCX 读取 | | `Rag.Extensions.DataIngestion.ClosedXML` | XLSX 读取 | | `Rag.Extensions.DataRetrieval.Abstractions` | 检索契约 | | `Rag.Extensions.DataRetrieval` | 检索 pipeline、结果处理器 | | `Rag.Extensions.DataRetrieval.Tei` | TEI reranker | | `Rag.Extensions.AgenticRetrieval.Abstractions` | Agentic RAG 抽象 | | `Rag.Extensions.AgenticRetrieval` | Agentic planner / executor / synthesizer | | `Rag.Extensions.AgenticRetrieval.Maf` | MAF 适配层 | | `Rag.Extensions.VectorData.Abstractions` | 稀疏嵌入抽象 | | `Rag.Extensions.VectorData.Qdrant` | Qdrant 提供者(dense + sparse + hybrid) | | `Rag.Extensions.VectorData.Tei` | TEI 稀疏向量生成器(SPLADE) | | `samples/Rag.Extensions.SampleWebApi` | 端到端示例 | | `samples/Rag.Extensions.GraphRag.SampleWebApi` | 独立 GraphRAG / Neo4j 验证示例 | ## 混合检索配置 `SparseVectors` 支持列表,可同时配置多路稀疏向量: ```csharp SparseVectors = [ new QdrantSparseVectorOptions { StorageName = "content-bm25", SourcePropertyName = nameof(MyChunk.Content), // Qdrant 原生 BM25,无需模型 }, new QdrantSparseVectorOptions { StorageName = "content-splade", SourcePropertyName = nameof(MyChunk.Content), // 指定文本字段 EmbeddingGenerator = sp.GetRequiredService>(), // TEI SPLADE }, ], ``` - BM25:存原文,Qdrant 服务端内置分词/打分,**不需要模型** - SPLADE:客户端调 TEI `/embed_sparse` 生成稀疏向量再存,**需要 TEI SPLADE 模型** ## 前置条件 - Qdrant server 1.18+ - TEI server(用于 rerank,可选用于 SPLADE) - OpenAI-compatible embedding endpoint - Neo4j(仅 GraphRAG sample 需要) - `HasNamedVectors = true`