跳到主要内容

知识库与 RAG

这章讲什么: 你把资料丢进知识库后,DeepTutor 怎么检索它。重点是「一个知识库绑一种检索引擎」的可插拔设计,而不是某一种 RAG 算法的细节。

1. 它要解决的小问题

不同资料适合不同检索法:平铺文档适合向量检索;有大量交叉引用的知识适合图检索(GraphRAG);长 PDF 适合按页/层级索引(PageIndex)。一个辅导系统不该只押一种 RAG——得让每个知识库挑自己合适的引擎,但对上层(聊天循环里的 rag 工具)暴露同一个接口。

2. 思路 / 直觉:引擎按知识库绑定,工厂路由

RAGService(deeptutor/services/rag/service.py,RAGService)是统一入口。它的核心一句话(docstring):provider 按知识库解析——建库时显式传的 provider 优先,否则从 DeepTutor 权威 KB 配置里读,metadata 作为旧版兜底。

四套引擎在工厂里登记(deeptutor/services/rag/factory.py):

provider适合常量
llamaindex默认,向量 + BM25;大库可用 FAISS ANNDEFAULT_PROVIDER(factory.py:27)
pageindex长文档按页/层级索引PAGEINDEX_PROVIDER(factory.py:28)
graphrag图结构知识GRAPHRAG_PROVIDER(factory.py:29)
lightrag轻量图 RAG(还有 lightrag_server 服务端引擎)LIGHTRAG_PROVIDER(factory.py:30)

get_pipeline 按名字拿到 pipeline,list_pipelines(factory.py:169)列出可用引擎给 UI 选。pipeline 实现分目录摆在 deeptutor/services/rag/pipelines/{llamaindex,graphrag,pageindex,lightrag,lightrag_server}/,共用 pipelines/base.py 的基类。

3. 图示:一次检索的路由

怎么读: 从上到下,聊天里的 rag 工具最终落到「这个 KB 绑的那套引擎」。

聊天循环里模型调 rag 工具(query, kb_name)


RAGService:看 kb_name 绑了哪个 provider
│ (建库时显式 > KB 配置 > metadata 兜底)

factory.get_pipeline(provider)

┌────┼─────────┬──────────┬────────────┐
▼ ▼ ▼ ▼ ▼
llamaindex graphrag pageindex lightrag lightrag_server
(向量+BM25) (图) (页/层级) (轻量图) (服务端)


命中段落 + sources → 回到工具结果 → 塞回对话

4. 几个值得看的细节

4.1 按文件类型路由解析

FileTypeRouter(deeptutor/services/rag/file_routing.py,FileTypeRouter/DocumentType/FileClassification)按文件类型把文档分流到合适的解析路径(PDF、office 文档等各走各的提取器)。解析引擎本身在 deeptutor/services/parsing/engines/(含 MinerU、PyMuPDF4LLM 等)。

4.2 多查询聚合:SmartRetriever

SmartRetriever(deeptutor/services/rag/smart_retriever.py,SmartRetriever)是建在 RAGService 之上的高层 helper:它先生成若干查询变体(或用传入的 hints),并行检索(asyncio.gather),把命中的段落聚合后再让 LLM 合成一个答案(smart_retriever.py:18-46,retrieve)。失败的查询用 return_exceptions=True 跳过,不拖垮整体。

# 示意,非源码:一个问题 → 多个查询变体 → 并行检索 → 聚合
queries = hints or await generate_queries(context, n=3) # 没给 hints 就让 LLM 造
results = await gather(*(search(query=q, kb_name=kb) for q in queries),
return_exceptions=True) # 失败的跳过
passages = [r["content"] for r in results if ok(r)]
answer = await aggregate(context, passages) # LLM 合成

4.3 索引版本化与预检

RAG 服务带了一组工程化设施:index_versioning.py(带版本的 KB 索引 + 重建流程)、index_probe.pypreflight.py(检索前的健康检查)、embedding_signature.py(embedding 配置签名,变了就提示重建)、linked_kb.py(链接外部 KB,如 Obsidian)。这些是「让大库检索稳」的配套,README 的 v1.3.x/v1.4.x 多个版本在打磨它们(如 FAISS 向量后端、re-index 韧性)。

5. 边界与局限

  • 具体每套引擎的检索算法细节没在本章展开(它们各自封在 pipelines/<name>/ 里,接口统一在 base.py)——本章只讲「可插拔路由」这个架构决定。
  • 默认 llamaindex 的 FAISS 是懒导入,缺了就回退到 SimpleVectorStore 的暴力扫描(pyproject.toml:83-87 注释,issue #552),所以小库不装 faiss 也能跑,只是大库慢。

6. 代码地图

主题文件符号
统一检索入口deeptutor/services/rag/service.pyRAGService
引擎工厂 / 路由deeptutor/services/rag/factory.pyget_pipelinelist_pipelinesDEFAULT_PROVIDER
pipeline 基类deeptutor/services/rag/pipelines/base.py(基类)
文件类型路由deeptutor/services/rag/file_routing.pyFileTypeRouterDocumentType
多查询聚合deeptutor/services/rag/smart_retriever.pySmartRetriever.retrieve
索引版本化deeptutor/services/rag/index_versioning.py(版本化逻辑)
rag 工具(LLM 入口)deeptutor/tools/rag_tool.py(rag 工具)