# [S1-T3] MemoryBear RAG 源码盘点与模块依赖关系图谱 — 交付物 ## 一、模块清单 > 统计口径:`api/app/core/rag/` 全部子目录 + `api/app/core/workflow/nodes/knowledge` + `api/app/core/rag_utils/` 共 **~24,900+ LOC** Python 代码。 | 子模块路径 | 主要职责 | 入口文件 / 关键类 / 关键函数 | 对外接口(被谁调用 / 调用谁) | 第三方依赖 | 文件数 / 行数 | |---|---|---|---|---|---| | `rag/app` | 文档解析与分块 orchestrator;按 doc_type 路由到不同解析策略(naive / book / paper / qa / audio / picture / manual / laws / mail / one) | `naive.py:508 chunk()`、`naive.py:257 naive.__call__()`、`naive.py:27 by_deepdoc()`、`naive.py:45 by_mineru()`、`naive.py:65 by_textln()` | 被 `tasks.py` 调用(Celery ingestion);调用 `deepdoc/parser` + `deepdoc/vision` + `rag/nlp` + `rag/llm/cv_model` + `rag/llm/sequence2txt_model` | `python-docx`, `openpyxl`, `pdfplumber`, `markdown`, `Pillow` | 12 / 2,923 | | `rag/common` | RAG 共享常量、异常、装饰器、工具函数(文件/浮点/日志/字符串/Token 计数) | `constants.py`(常量定义)、`token_utils.py`(encoder)、`settings.py:13 init_settings()`(单例初始化) | 被 `rag/utils/es_conn.py`、`rag/graphrag/utils.py`、`rag/nlp/search.py` 等广泛 import | `tiktoken`(tokenizer) | 12 / 602 | | `rag/crawler` | Web 页面抓取与内容提取 | `web_crawler.py`、`content_extractor.py`、`http_fetcher.py` | 被 `tasks.py` 调用;由 knowledge sync 触发 | `requests` | 9 / 1,237 | | `rag/deepdoc/parser` | 11 种格式文档解析(PDF/Word/Excel/HTML/MD/JSON/TXT/PPT) | `pdf_parser.py:34 RAGPdfParser.__call__:1124`、`docx_parser.py:9 RAGDocxParser`、mineru_parser.py:41 MinerUParser` | 被 `rag/app/naive.py` import 并调用 | `pdfplumber`, `pypdf`, `python-docx`, `openpyxl`, `beautifulsoup4`, `markdown`, `pandas` | 12 / 3,228 | | `rag/deepdoc/vision` | 文档视觉分析:布局识别 + OCR + 表格结构识别 | `ocr.py:522 OCR.__call__:694`、`layout_recognizer.py:17 LayoutRecognizer`、`table_structure_recognizer.py:15 TableStructureRecognizer` | 被 `pdf_parser.py` 调用进行版面/表格/图像识别 | `onnxruntime`, `huggingface_hub`, `Pillow`, `opencv-python`, `numpy` | 10 / 3,657 | | `rag/graphrag`(顶层) | GraphRAG 共享工具、实体消歧、查询分析提示、知识图谱搜索 | `search.py:19 KGSearch(Dealer)`、`entity_resolution.py:31 EntityResolution`、`utils.py`(graph merge/persist/LLM cache) | 被 `tasks.py`、workflow knowledge node、prompts/generator.py 调用 | `networkx`, `pandas`, `trio`, `redis`, `xxhash`, `json_repair` | 6 / 1,452 | | `rag/graphrag/general` | 通用/完整版 GraphRAG 流水线:子图抽取 → 合并 → 实体消歧 → Leiden 社区 → 社区报告 | `index.py:36 run_graphrag()`、`index.py:122 run_graphrag_for_kb()`、`graph_extractor.py:34 GraphExtractor`、`community_reports_extractor.py:37` | 被 `tasks.py` 的 Celery task 调用;调用 `ElasticSearchVector` 写图数据 | `networkx`, `graspologic`, `tiktoken`, `trio` | 11 / 1,857 | | `rag/graphrag/light` | 轻量版 GraphRAG(LightRAG 风格):简化实体/关系抽取,无社区报告 | `light/graph_extractor.py:31 GraphExtractor` | 被 `general/index.py` 根据 `parser_config.graphrag.method` 条件切换调用 | `networkx`, `trio` | 3 / 462 | | `rag/integrations/feishu` | 飞书文档同步客户端 | `client.py: FeishuAPIClient` | 被 `knowledge_controller.py` + `tasks.py` 调用 | `requests` | 6 / 737 | | `rag/integrations/yuque` | 语雀文档同步客户端 | `client.py: YuqueAPIClient` | 被 `knowledge_controller.py` + `tasks.py` 调用 | `requests` | 6 / 844 | | `rag/llm` | LLM 多模型统一 facade(Chat / Embedding / CV / Seq2txt) | `chat_model.py:52 Base`、`embedding_model.py:14 Base`、`cv_model.py:19 Base`、`sequence2txt_model.py:15 Base` | 被 `rag/app`、`rag/nlp/search`、`rag/graphrag`、`rag/vdb`、`workflow/nodes/knowledge` 等调用 | `openai`, `dashscope`, `azure-openai`, `ollama`, `zhipuai`, `requests` | 5 / 1,676 | | `rag/models` | Chunk 数据模型 | `chunk.py:17 DocumentChunk`、`chunk.py:5 ChildDocumentChunk` | 被 `rag/vdb`、`rag/app`、`workflow/nodes/knowledge`、`tasks.py` 引用 | `pydantic` | 2 / 72 | | `rag/nlp` | NLP 工具箱:中文分词、BM25/hybrid 搜索调度、同义词扩展、术语权重、Query 重写 | `search.py:349 Dealer`(含 `retrieval:674`、`search:387`、`rerank:606`)、`rag_tokenizer.py:15 RagTokenizer`、`query.py:10 FulltextQueryer` | 被 `rag/app/naive.py`、`rag/graphrag`、`rag/prompts/generator.py`、`rag/common/settings.py` 调用 | `datrie`, `hanziconv`, `nltk`, `pandas`, `numpy` | 7 / 2,962 | | `rag/prompts` | Prompt 模板加载与 LLM prompt 工厂 | `template.py:9 load_prompt()`、`generator.py`(citation/keyword/question/toc/reflect 等 20+ 函数) | 被 `tasks.py`、`rag/nlp/search.py`、`rag/graphrag` 调用;依赖 `.md` prompt 文件 | `jinja2`, `json_repair` | 3 / 769 + 31 md 文件 | | `rag/utils` | ES 连接、Redis 连接、LibreOffice 转换、文件工具 | `es_conn.py: ESConnection`、`redis_conn.py`、`libre_office.py`、`file_utils.py`、`doc_store_conn.py` | 被 `rag/vdb`、`rag/common/settings.py`、`rag/app/naive.py`、`rag/nlp/search.py` 调用 | `elasticsearch`, `redis` | 6 / 1,578 | | `rag/vdb` | 向量数据库抽象 + Elasticsearch 实现 | `elasticsearch/elasticsearch_vector.py:29 ElasticSearchVector`、`elasticsearch/elasticsearch_vector.py:666 ElasticSearchVectorFactory`、`vector_base.py:9 BaseVector` | 被 `tasks.py`、`knowledge_controller.py`、`chunk_controller.py`、`workflow/nodes/knowledge` 调用 | `elasticsearch`, `langchain-core` | 3 / 83 + 2 / 753 | | `rag/res` | 静态资源:NER 词表、同义词表、映射表 | `ner.json`、`synonym.json`、`mapping.json` | 被 `rag/nlp/term_weight.py`、`rag/nlp/synonym.py` 加载 | — | 3 JSON | | `workflow/nodes/knowledge` | Workflow 知识检索节点:多知识库检索 + 重排序 + GraphRAG 增强 | `node.py:29 KnowledgeRetrievalNode`、`node.py:303 execute()`、`node.py:195 knowledge_retrieval()` | 被 `workflow/nodes/node_factory.py`、`workflow/nodes/__init__.py` 注册;调用 `rag/vdb`、`rag/llm`、`rag/models` | `langchain-core` | 3 / 455 | | `rag_utils`(⚠️ 与 `rag/utils` 不同) | Chunk 内容 LLM 分析:摘要生成、标签提取、洞察分析、人物画像 | `chunk_summary.py:68 generate_chunk_summary()`、`chunk_tags.py:56 extract_chunk_tags()`、`chunk_insight.py:137 generate_chunk_insight()` | 被 `services/memory_dashboard_service.py` 调用;依赖 `app.core.memory.*` LLM 工厂 | `pydantic` | 4 / 588 | --- ## 二、依赖关系图谱(Mermaid) ```mermaid graph TB subgraph "上层调用者" A1[tasks.py
Celery Workers] A2[controllers/
REST API] A3[workflow/nodes/
知识检索节点] A4[services/memory_
dashboard_service.py] end subgraph "RAG Core" B1[rag/app
解析与分块] B2[rag/deepdoc/parser
格式解析] B3[rag/deepdoc/vision
版面/OCR] B4[rag/crawler
网页抓取] B5[rag/integrations
飞书/语雀] B6[rag/nlp
分词/搜索调度] B7[rag/llm
多模型Facade] B8[rag/vdb
ES向量存储] B9[rag/graphrag
知识图谱] B10[rag/prompts
Prompt工厂] B11[rag/models
Chunk模型] B12[rag/common
常量/工具] B13[rag/utils
ES/Redis连接] end subgraph "旁路模块" C1[rag_utils
Chunk LLM分析] end A1 --> B1 A1 --> B4 A1 --> B5 A1 --> B8 A1 --> B9 A1 --> B10 A2 --> B1 A2 --> B5 A2 --> B8 A2 --> B9 A3 --> B8 A3 --> B7 A3 --> B11 A4 --> C1 B1 --> B2 B1 --> B3 B1 --> B6 B1 --> B7 B2 --> B3 B2 --> B6 B3 --> B12 B4 --> B13 B5 --> B13 B6 --> B7 B6 --> B13 B6 --> B10 B8 --> B7 B8 --> B11 B8 --> B13 B9 --> B6 B9 --> B7 B9 --> B10 B9 --> B13 B10 --> B7 B10 --> B9 C1 --> B7 B12 --> B13 B13 --> B8 ``` --- ## 三、入口链路梳理 ### 3.1 文档入库链路(Indexing Pipeline) ``` REST POST /document 或 /knowledge/{id}/sync ↓ 触发 Celery task @tasks.py:212 parse_document(file_path, document_id) ↓ 调用 rag/app/naive.py:508 chunk(filename, binary, ...) ↓ 路由 by file extension ├─ PDF → by_deepdoc() → deepdoc/parser/pdf_parser.py:34 RAGPdfParser.__call__:1124 ├─ PDF alt → by_mineru() → deepdoc/parser/mineru_parser.py:41 MinerUParser.parse_pdf() ├─ DOCX → RAGDocxParser.__call__() @ docx_parser.py:9 ├─ XLSX → RAGExcelParser.__call__() @ excel_parser.py:16 ├─ HTML → RAGHtmlParser.__call__() @ html_parser.py:22 ├─ MD → RAGMarkdownParser.__call__() @ markdown_parser.py:6 ├─ JSON → RAGJsonParser.__call__() @ json_parser.py:7 └─ TXT → RAGTxtParser.__call__() @ txt_parser.py:7 ↓ rag/app/naive.py:257 naive.__call__() — 提取 sections + tables ↓ rag/nlp/__init__.py — tokenize / naive_merge / hierarchical_merge ↓ rag/vdb/elasticsearch/elasticsearch_vector.py:55 add_chunks() ↓ 调用 rag/vdb/elasticsearch/elasticsearch_vector.py:65 create() ↓ 调用 embedding_model.py: encode() → LLM API → ES bulk index ``` ### 3.2 在线检索链路(Query Pipeline) ``` REST POST /retrieval 或 Workflow Node: workflow/nodes/knowledge/node.py:303 execute() ↓ workflow/nodes/knowledge/node.py:195 knowledge_retrieval() ↓ 根据 retrieve_type 分支 ├─ PARTICIPLE → ElasticSearchVector.search_by_full_text() @ elasticsearch_vector.py:468 ├─ SEMANTIC → ElasticSearchVector.search_by_vector() @ elasticsearch_vector.py:374 ├─ HYBRID → 并行 vector + full_text → dedupe → rerank @ node.py:236-271 └─ Graph → HYBRID 结果 + kg_retriever.retrieval() ↓ 调用 rag/common/settings.py:10 kg_retriever (单例) ↓ 调用 rag/graphrag/search.py:19 KGSearch.retrieval() ``` ### 3.3 GraphRAG 构建链路 ``` REST POST /knowledge/{knowledge_id}/knowledge_graph 或 Celery task @tasks.py:472 build_graphrag_for_kb(kb_id) ↓ Celery task @tasks.py:557 build_graphrag_for_document(document_id, knowledge_id) ↓ rag/graphrag/general/index.py:36 run_graphrag(row, language, with_resolution, with_community, ...) ↓ rag/graphrag/general/index.py:122 run_graphrag_for_kb(kb_id, ...) ↓ 流水线 1. init_graphrag() → 创建 ES 索引 2. GraphExtractor.extract() → 逐 chunk 抽取实体/关系 ├─ general/graph_extractor.py:34 GraphExtractor (Microsoft GraphRAG 风格) └─ light/graph_extractor.py:31 GraphExtractor (LightRAG 风格,条件切换) 3. graph_merge() → 合并子图 4. EntityResolution.resolve() → 实体消歧 5. leiden.run() → 社区发现 6. CommunityReportsExtractor.extract() → 社区摘要 7. set_graph() → 写回 ES ``` ### 3.4 Workflow Knowledge 节点链路 ``` workflow/nodes/knowledge/node.py:29 KnowledgeRetrievalNode ↓ node.py:54 _extract_input() — 渲染 query 模板,读取 knowledge_bases 配置 ↓ node.py:303 execute() ↓ node.py:335 get_knowledge_by_id() — 校验知识库存在性 ↓ node.py:195 knowledge_retrieval() ↓ 分支处理 ├─ FOLDER 类型 → 递归遍历子知识库 ├─ PARTICIPLE → vector_service.search_by_full_text() ├─ SEMANTIC → vector_service.search_by_vector() ├─ HYBRID → vector + full_text 并行 → dedupe → rerank └─ Graph → HYBRID + kg_retriever.retrieval() 增强 ↓ node.py:108 rerank() — 调用 RedBearRerank 模型 ↓ node.py:362 返回 {"chunks": [...], "citations": [...]} ``` --- ## 四、Gap 报告(代码 vs S1-T2 架构预期) ### 4.1 "架构里列了但代码里没有 / 命名/范围不一致" | # | 差异项 | S1-T2 架构预期 | 代码实际 | 影响与建议 | |---|---|---|---|---| | 1 | **缺少 Milvus/Weaviate/Qdrant 支持** | VDB 环节预期讨论"向量数据库选型",暗示可能多库 | 仅 `rag/vdb/elasticsearch/` 有实现,`BaseVector` 无其他子类 | 架构文档中 VDB 章节需要明确限定为 Elasticsearch 8.x,或规划扩展接口 | | 2 | **`rag_utils` vs `rag/utils` 命名冲突** | 预期目录:`api/app/core/rag/{deepdoc,crawler,integrations,llm,vdb,graphrag,prompts,app}` | 实际存在 `rag/utils`(文件工具/ES 连接)**和** `rag_utils/`(Chunk LLM 分析)两个独立目录,仅下划线差异 | 极易混淆,建议将 `rag_utils/` 重命名为 `rag/chunk_analytics/` 或合并到 `rag/app/` 下游 | | 3 | **`nlp/search.py` 中的 `Dealer` 是遗留/旁路模块** | 架构中 `rag/nlp` 预期为"分词/NLP 工具" | `rag/nlp/search.py:349 Dealer` 实际是一个完整的 BM25/hybrid 搜索调度器,与 `rag/vdb` 的 ES 向量搜索并行存在两套检索体系 | 两套检索代码并存(`nlp/search.py` 主要被 GraphRAG 使用,`vdb/elasticsearch` 被 Workflow 使用)。架构文档应明确标注 `nlp/search` 是 GraphRAG 专用旧通道 | | 4 | **缺少独立的 Reranking 模块** | S1-T2 预期有独立的 Reranking 环节 | 重排序逻辑散布在多处:`workflow/nodes/knowledge/node.py:108 rerank()`、`rag/vdb/elasticsearch/elasticsearch_vector.py:560 rerank()`、以及 `rag/nlp/search.py:606 rerank()` | 建议 Sprint-2 文档将 Reranking 单独成章,汇总这三处实现并标注差异(Workflow 节点用 RedBearRerank,VDB 层也有独立 rerank,NLP 层有 model-based rerank) | | 5 | **Prompt 目录含大量 .md 模板但无统一版本管理** | Prompt 工程是独立环节 | `rag/prompts/` 有 31 个 `.md` 模板文件 + `template.py`(加载器)+ `generator.py`(工厂函数),但模板修改无版本控制/审计机制 | 建议文档中标注 prompt 管理现状:文件驱动、运行时加载、无 A/B 或版本回滚机制 | | 6 | **Deepdoc vision 模型加载路径硬编码** | 架构预期模型管理可配置 | `deepdoc/vision/` 各 recognizer 硬编码从 `huggingface_hub.snapshot_download(repo_id="InfiniFlow/deepdoc")` 下载到 `res/deepdoc/`,仅 `HF_ENDPOINT` 环境变量可配 | 建议文档中明确标注模型路径约束,为后续模型热更新/私有化部署做铺垫 | | 7 | **GraphRAG light 是条件分支而非独立模块** | S1-T2 预期 GraphRAG 有 light 和 general 两个独立目录 | `light/` 仅含 `graph_extractor.py` + `graph_prompt.py`(2 个逻辑文件),其余全部复用 `general/` 的 `Extractor` 基类、`utils.py`、`index.py` | Sprint-2 文档应将 light 标记为"general 的条件子模式",避免读者误以为两套完整流水线 | ### 4.2 "代码里有但架构没列" | # | 差异项 | 代码位置 | 说明 | |---|---|---|---| | 1 | **rag/app 按 doc_type 路由的 11 种解析策略** | `rag/app/{naive,book,paper,qa,audio,picture,manual,laws,mail,one,textin_parser}.py` | S1-T2 架构只提到 "Loader / Parser",未提及 MemoryBear 特有的 doc_type 路由体系(book/paper/qa/audio 等) | | 2 | **MinerU 第三方解析器集成** | `rag/deepdoc/parser/mineru_parser.py` | 架构中 Parser 环节未提及 MinerU(第三方 PDF 解析服务)作为 PDF 解析的替代方案 | | 3 | **TextIn 第三方解析器集成** | `rag/app/textin_parser.py` | 同上,未提及 TextIn API 作为另一 PDF 解析备选 | | 4 | **rag_utils(Chunk LLM 分析)** | `api/app/core/rag_utils/` | 架构中无此模块定位,它实际做 chunk 摘要/标签/洞察,与 Memory 系统耦合 | | 5 | **Toc(目录)智能提取链路** | `rag/prompts/generator.py:408-717` | 大量 LLM-driven TOC 检测/提取/索引/关联代码,架构大纲中未单列 "TOC 处理" 环节 | | 6 | **Crawler(网页抓取)** | `rag/crawler/` | 架构中 Loader 环节可能包含爬虫,但代码量 1,200+ LOC 值得单独标注 | | 7 | **res/ 静态资源(NER、同义词表)** | `rag/res/{ner.json,synonym.json,mapping.json}` | 架构中未提及术语权重/同义词扩展的资源文件体系 | --- ## 五、关键数据速查 | 指标 | 数值 | |---|---| | `api/app/core/rag/` 总 Python LOC | ~24,895 | | `api/app/core/rag/` 子模块数 | 15(不含 res/) | | `.md` Prompt 模板数 | 31 | | Parser 实现数 | 11 种(含 PDF 3 种策略:deepdoc/mineru/textin) | | LLM Provider 实现数 | Chat 9 种 + Embed 10 种 + CV 7 种 + Seq2txt 6 种 = **32 个 provider 类** | | Workflow Knowledge 检索类型 | PARTICIPLE / SEMANTIC / HYBRID / Graph(4 种) | | GraphRAG 模式 | general(Microsoft GraphRAG)/ light(LightRAG 风格) | | VDB 实现 | Elasticsearch 8.x(唯一) | --- 以上交付物已同步写入本地文件 `WS-14-deliverable.md`,可作为 Sprint-2 文档化的底图直接复用。