docs(rag): add MemoryBear RAG implementation docs v1.0
Some checks failed
Sync to Gitee / sync (push) Has been cancelled
Some checks failed
Sync to Gitee / sync (push) Has been cancelled
Submit the formed RAG documentation set produced across Sprint-1/2/3 (WS-12 through WS-26) under docs/rag/. Includes: - README.md / INDEX.md: landing + total index (responsibility matrix, review verdicts, dual-link to source issues) - overview/: full-pipeline architecture (4 .mmd diagrams), 11-stage boundary contracts, doc map, source-code inventory - pipeline/: 5 deep-dives (Loader/Parser/Chunking, Embedding, VDB & retrieval, GraphRAG, Rerank/Prompt/LLM) - graphrag/, end-to-end/: v1.0 formal versions with full source retained as reference - evolution/: 11 architecture-refactor proposals, 6-direction roadmap, capability map - review/: S3-T1 / S3-T2 final reviews, S2-T7 final summary - _indexes/: glossary (81 terms), source->doc reverse index, chart index - _release/: v1.0-RC1 release manifest, versioning convention, ops & freshness plan - _meta/README.md: placeholder noting WS-12 governance assets gap Aggregate review score 92.6/100 (8/8 PASS, 31/31 source-code spot checks hit). The legacy docs/ ignore in .gitignore is narrowed to docs/* with an explicit allowlist for docs/rag/. Refs: WS-26 Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
132
docs/rag/overview/01-architecture.mmd
Normal file
132
docs/rag/overview/01-architecture.mmd
Normal file
@@ -0,0 +1,132 @@
|
||||
%% MemoryBear RAG 全链路架构图(Mermaid Flowchart)
|
||||
%% 约定:浅蓝色 = 数据来源层;浅绿色 = 解析与分块;浅黄色 = 向量化与存储;浅紫色 = 检索;浅橙色 = 生成;浅灰色 = 支撑组件
|
||||
|
||||
flowchart TB
|
||||
subgraph DATA_SOURCES["数据来源层 (Loader)"]
|
||||
CRAWLER["Web Crawler\ncrawler/web_crawler.py\n-> 输出: CrawledDocument"]
|
||||
FEISHU["飞书 API\nintegrations/feishu/client.py\n-> 输出: 本地文件 (.docx/.pdf)"]
|
||||
YUQUE["语雀 API\nintegrations/yuque/client.py\n-> 输出: 本地文件 (.md/.html/.xlsx)"]
|
||||
UPLOAD["用户上传\ncontrollers/document_controller.py:275\n-> 输出: 文件路径"]
|
||||
end
|
||||
|
||||
subgraph PARSER["文档解析与分块 (Parser + Chunking)"]
|
||||
NAIVE["app/naive.py:chunk()\n统一分块入口\nDispatch by filename extension"]
|
||||
PDFP["deepdoc/parser/pdf_parser.py\nOCR + Layout + Table"]
|
||||
DOCXP["deepdoc/parser/docx_parser.py"]
|
||||
HTMLP["deepdoc/parser/html_parser.py"]
|
||||
MDPP["deepdoc/parser/markdown_parser.py"]
|
||||
EXCELP["deepdoc/parser/excel_parser.py"]
|
||||
TXTPIP["deepdoc/parser/txt_parser.py"]
|
||||
VISION["deepdoc/vision/\nocr.py + layout_recognizer.py\n+ table_structure_recognizer.py"]
|
||||
NLP["nlp/__init__.py\ntokenize / naive_merge / hierarchical_merge"]
|
||||
end
|
||||
|
||||
subgraph CHUNK_TYPES["文档类型适配 (Task Types)"]
|
||||
BOOK["app/book.py\n长文档分级分块"]
|
||||
PAPER["app/paper.py\n论文结构保持"]
|
||||
MANUAL["app/manual.py\n手册按节分块"]
|
||||
LAWS["app/laws.py\n法规层级树分块"]
|
||||
QA["app/qa.py\n问答对独立分块"]
|
||||
ONE["app/one.py\n整文件单块"]
|
||||
PIC["app/picture.py\nOCR + VLM描述"]
|
||||
AUD["app/audio.py\n语音转文本"]
|
||||
end
|
||||
|
||||
subgraph EMBED["向量化 (Embedding)"]
|
||||
EMB_BASE["llm/embedding_model.py\nBase.encode(texts: list)\n→ (np.array, token_count)"]
|
||||
EMB_PROV["Provider 工厂\nOpenAI / LocalAI / Azure / Tongyi /\nHuggingFace / Xinference / VolcEngine /\nGPUStack / NVIDIA / BaiChuan"]
|
||||
end
|
||||
|
||||
subgraph VDB["向量数据库 (VDB)"]
|
||||
ES_VECT["vdb/elasticsearch/elasticsearch_vector.py\nDense + Sparse 混合索引\ncosineSimilarity + BM25"]
|
||||
ES_CONN["utils/es_conn.py\nES 连接管理"]
|
||||
ES_SCHEMA["vdb/field.py\npage_content / metadata / vector / text\n+ doc_id / knowledge_id / sort_id"]
|
||||
end
|
||||
|
||||
subgraph GRAPHRAG["知识图谱 (GraphRAG)"]
|
||||
G_LIGHT["graphrag/light/\ngraph_extractor.py\n实体+关系抽取\n→ nx.Graph"]
|
||||
G_GEN["graphrag/general/\ngraph_extractor.py\n→ community_reports_extractor.py\n+ mind_map_extractor.py"]
|
||||
G_LEIDEN["general/leiden.py\n层次聚类"]
|
||||
G_RESOLVE["entity_resolution.py\n实体消歧 LLM 匹配"]
|
||||
G_SEARCH["graphrag/search.py\nKGSearch.retrieval()\nQuery分析→实体检索→N-hop→社区报告"]
|
||||
end
|
||||
|
||||
subgraph RETRIEVAL["检索 (Retrieval)"]
|
||||
DEALER["nlp/search.py\nDealer.search()\nHybrid: BM25 0.05 + Vector 0.95"]
|
||||
QRYR["nlp/query.py\nQuery理解 / 关键词扩展"]
|
||||
KNOWLEDGE["nlp/search.py:36\nknowledge_retrieval()\n→ 多知识库合并"]
|
||||
end
|
||||
|
||||
subgraph RERANK["重排序 (Reranking)"]
|
||||
RERANK_M["models/rerank.py\nRedBearRerank\ncompress_documents() / rerank()"]
|
||||
RERANK_P["Provider: JinaRerank /\nDashScopeRerank /\nXINFERENCE / GPUSTACK"]
|
||||
end
|
||||
|
||||
subgraph PROMPT["Prompt 组装"]
|
||||
PGEN["prompts/generator.py\ncitation_prompt / keyword_extraction /\nfull_question / content_tagging /\ntoc_relevance / structured_output"]
|
||||
PTEMPLATE["prompts/template.py\n加载 .md 模板文件"]
|
||||
end
|
||||
|
||||
subgraph LLM["LLM 生成"]
|
||||
CHAT["llm/chat_model.py\nBase.chat() / chat_streamly()\n→ (str, tokens)"]
|
||||
CHAT_PROV["Provider 工厂\nOpenAI / Azure / LocalAI /\nXinference / Tongyi /\nHuggingFace / GPUStack / VolcEngine"]
|
||||
end
|
||||
|
||||
subgraph ORCH["编排层 (Orchestration)"]
|
||||
CELERY["tasks.py\nparse_document() /\nbuild_graphrag_for_kb() /\nbuild_graphrag_for_document()"]
|
||||
WORKFLOW["workflow/nodes/knowledge/node.py\nKnowledgeRetrievalNode.execute()\n→ 检索→去重→重排→返回 chunks"]
|
||||
end
|
||||
|
||||
subgraph POST["后处理"]
|
||||
CITE["插入引用标注\nDealer.insert_citations()\npagerank*sim 评分"]
|
||||
CACHE["缓存层\nutils/redis_conn.py\nLLM 结果缓存"]
|
||||
end
|
||||
|
||||
%% === 数据流 ===
|
||||
DATA_SOURCES --> NAIVE
|
||||
NAIVE --> |PDF| PDFP
|
||||
NAIVE --> |DOCX| DOCXP
|
||||
NAIVE --> |HTML| HTMLP
|
||||
NAIVE --> |MD| MDPP
|
||||
NAIVE --> |XLSX| EXCELP
|
||||
NAIVE --> |TXT| TXTPIP
|
||||
|
||||
PDFP --> VISION
|
||||
VISION --> NLP
|
||||
DOCXP --> NLP
|
||||
HTMLP --> NLP
|
||||
MDPP --> NLP
|
||||
EXCELP --> NLP
|
||||
TXTPIP --> NLP
|
||||
|
||||
NAIVE --> |按文档类型| CHUNK_TYPES
|
||||
CHUNK_TYPES --> NLP
|
||||
|
||||
NLP --> EMB_BASE
|
||||
EMB_BASE --> EMB_PROV
|
||||
EMB_PROV --> ES_VECT
|
||||
ES_SCHEMA --> ES_VECT
|
||||
ES_CONN --> ES_VECT
|
||||
|
||||
NLP -.-> |"并行 (async)"| GRAPHRAG
|
||||
G_LIGHT --> G_SEARCH
|
||||
G_GEN --> G_LEIDEN
|
||||
G_GEN --> G_RESOLVE
|
||||
G_LEIDEN --> G_SEARCH
|
||||
G_RESOLVE --> G_SEARCH
|
||||
|
||||
CELERY --> NAIVE
|
||||
CELERY -.-> |"触发"| GRAPHRAG
|
||||
|
||||
WORKFLOW --> QRYR
|
||||
QRYR --> DEALER
|
||||
DEALER --> KNOWLEDGE
|
||||
KNOWLEDGE --> RERANK_M
|
||||
G_SEARCH --> |"GRAPH模式"| KNOWLEDGE
|
||||
RERANK_M --> RERANK_P
|
||||
RERANK_P --> PGEN
|
||||
PGEN --> PTEMPLATE
|
||||
PTEMPLATE --> CHAT
|
||||
CHAT --> CHAT_PROV
|
||||
CHAT --> CITE
|
||||
CITE --> CACHE
|
||||
87
docs/rag/overview/02-indexing-pipeline.mmd
Normal file
87
docs/rag/overview/02-indexing-pipeline.mmd
Normal file
@@ -0,0 +1,87 @@
|
||||
%% MemoryBear 文档入库时序图(Indexing Pipeline)
|
||||
%% 起点:用户上传 / API 调用;终点:向量入库 + GraphRAG 索引完成
|
||||
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant User as 用户/API
|
||||
participant API as document_controller.py:275<br/>parse_documents()
|
||||
participant Celery as Celery Worker<br/>tasks.py
|
||||
participant DB as PostgreSQL<br/>(Document / Knowledge)
|
||||
participant Chunker as app/naive.py:508<br/>chunk()
|
||||
participant Parser as deepdoc/parser/<br/>(PDF/DOCX/HTML/...)
|
||||
tokenizer as nlp/__init__.py<br/>tokenize / naive_merge
|
||||
participant Embed as llm/embedding_model.py<br/>Base.encode()
|
||||
participant VDB as ESVectorFactory<br/>elasticsearch_vector.py
|
||||
participant Graph as graphrag/general/index.py<br/>run_graphrag_for_kb()
|
||||
|
||||
Note over User,VDB: === 阶段 1:文件上传与触发 ===
|
||||
User->>API: POST /documents (file / URL)
|
||||
API->>DB: INSERT Document (status=pending)
|
||||
API->>Celery: delay parse_document(file_path, document_id)
|
||||
|
||||
Note over Celery,VDB: === 阶段 2:文档解析与分块 ===
|
||||
Celery->>DB: SELECT Document, Knowledge
|
||||
Celery->>Celery: _build_vision_model()
|
||||
Celery->>Chunker: chunk(filename, binary, vision_model)
|
||||
|
||||
alt PDF 格式
|
||||
Chunker->>Parser: RAGPdfParser.__call__()
|
||||
Parser->>Parser: __images__() → OCR → _layouts_rec()
|
||||
Parser->>Parser: _table_transformer_job()
|
||||
Parser->>Parser: _text_merge() + _concat_downward()
|
||||
Parser-->>Chunker: sections: List[(text, tag)]<br/>tables: List[(image, html)]
|
||||
else DOCX 格式
|
||||
Chunker->>Parser: RAGDocxParser.parse()
|
||||
Parser-->>Chunker: sections, tables
|
||||
else HTML/MD/TXT/Excel
|
||||
Chunker->>Parser: 对应 Parser
|
||||
Parser-->>Chunker: sections
|
||||
end
|
||||
|
||||
alt 按文档类型路由
|
||||
Chunker->>Chunker: book.py / paper.py / laws.py / ...
|
||||
Chunker->>tokenizer: hierarchical_merge() / tree_merge()
|
||||
else 默认 naive
|
||||
Chunker->>tokenizer: naive_merge(sections, chunk_token_num)
|
||||
end
|
||||
|
||||
tokenizer->>tokenizer: tokenize(d) → content_ltks / content_sm_ltks
|
||||
tokenizer->>tokenizer: tokenize_chunks() → 附 page_num / position / image
|
||||
tokenizer-->>Celery: res: List[Dict] (chunk dicts)
|
||||
|
||||
Note over Celery,VDB: === 阶段 3:向量化与存储 ===
|
||||
Celery->>DB: progress=0.8
|
||||
Celery->>VDB: delete_by_metadata_field(document_id)
|
||||
|
||||
alt auto_questions 开启
|
||||
Celery->>Celery: ThreadPool 并发生成问题
|
||||
Celery->>Embed: question_proposal(chat_mdl, content)
|
||||
end
|
||||
|
||||
Celery->>Embed: encode(chunk_texts) → np.array
|
||||
Embed-->>Celery: vectors + token_count
|
||||
|
||||
loop 每 batch
|
||||
Celery->>Celery: 组装 DocumentChunk(page_content, vector, metadata)
|
||||
Celery->>VDB: insert_documents(chunks)
|
||||
VDB->>VDB: cosineSimilarity 索引 + BM25
|
||||
VDB-->>Celery: ack
|
||||
end
|
||||
|
||||
Celery->>DB: UPDATE Document (progress=1.0, chunk_num=N)
|
||||
|
||||
Note over Celery,Graph: === 阶段 4:GraphRAG 异步构建 ===
|
||||
Celery->>Celery: build_graphrag_for_document.delay()
|
||||
Celery->>Graph: run_graphrag_for_kb(document_ids)
|
||||
Graph->>Graph: generate_subgraph() per chunk
|
||||
Graph->>Graph: LLM 抽取 entities + relations
|
||||
Graph->>Graph: merge_subgraph() → nx.pagerank
|
||||
opt entity_resolution
|
||||
Graph->>Graph: resolve_entities() (LLM 匹配)
|
||||
end
|
||||
opt community_reports (general only)
|
||||
Graph->>Graph: leiden.run() 层次聚类
|
||||
Graph->>Graph: CommunityReportsExtractor → LLM 报告
|
||||
end
|
||||
Graph->>VDB: store graph entities / relations / reports
|
||||
Graph-->>Celery: done
|
||||
102
docs/rag/overview/03-query-pipeline.mmd
Normal file
102
docs/rag/overview/03-query-pipeline.mmd
Normal file
@@ -0,0 +1,102 @@
|
||||
%% MemoryBear 在线检索时序图(Query Pipeline)
|
||||
%% 起点:用户 Query;终点:LLM 生成的回答
|
||||
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant User as 用户/API
|
||||
participant WF as Workflow Engine<br/>(workflow/nodes/knowledge/node.py)
|
||||
participant Config as config.py<br/>KnowledgeRetrievalNodeConfig
|
||||
participant Retriever as nlp/search.py<br/>knowledge_retrieval()
|
||||
participant Dealer as nlp/search.py:349<br/>Dealer.search()
|
||||
participant Qryr as nlp/query.py<br/>Query理解
|
||||
participant ESVec as ESVector<br/>elasticsearch_vector.py
|
||||
participant Graph as graphrag/search.py<br/>KGSearch.retrieval()
|
||||
participant Rerank as models/rerank.py<br/>RedBearRerank
|
||||
participant Prompt as prompts/generator.py
|
||||
participant LLM as llm/chat_model.py<br/>Base.chat()
|
||||
participant Cache as utils/redis_conn.py
|
||||
|
||||
Note over User,Cache: === 阶段 1:Query 准备 ===
|
||||
User->>WF: 用户输入 Query
|
||||
WF->>WF: _render_template(query, variable_pool)
|
||||
WF->>Config: 读取 knowledge_bases[]<br/>reranker_id / retrieve_type
|
||||
|
||||
Note over Retriever,ESVec: === 阶段 2:多知识库检索 ===
|
||||
loop 每个 Knowledge Base
|
||||
WF->>Retriever: knowledge_retrieval(query, config)
|
||||
Retriever->>DB: 验证 KB 状态 (chunk_num>0, status=1)
|
||||
|
||||
alt RetrieveType == PARTICIPLE
|
||||
Retriever->>ESVec: search_by_full_text(query, top_k)
|
||||
ESVec->>ESVec: match on page_content (ik_max_word)
|
||||
ESVec-->>Retriever: List[DocumentChunk]
|
||||
|
||||
else RetrieveType == SEMANTIC
|
||||
Retriever->>ESVec: search_by_vector(query, top_k)
|
||||
ESVec->>ESVec: script_score cosineSimilarity
|
||||
ESVec-->>Retriever: List[DocumentChunk]
|
||||
|
||||
else RetrieveType == HYBRID
|
||||
par
|
||||
Retriever->>ESVec: search_by_vector()
|
||||
ESVec-->>Retriever: rs1
|
||||
and
|
||||
Retriever->>ESVec: search_by_full_text()
|
||||
ESVec-->>Retriever: rs2
|
||||
end
|
||||
Retriever->>Retriever: _deduplicate_docs(rs1, rs2)
|
||||
Retriever->>Rerank: rerank(query, docs, top_k)
|
||||
Rerank->>Rerank: similarity() 交叉编码评分
|
||||
Rerank-->>Retriever: sorted docs
|
||||
|
||||
else RetrieveType == GRAPH
|
||||
par
|
||||
Retriever->>ESVec: search_by_vector()
|
||||
ESVec-->>Retriever: rs1
|
||||
and
|
||||
Retriever->>ESVec: search_by_full_text()
|
||||
ESVec-->>Retriever: rs2
|
||||
end
|
||||
Retriever->>Retriever: dedup + rerank
|
||||
|
||||
Retriever->>Graph: kg_retriever.retrieval(question)
|
||||
Graph->>Graph: query_rewrite() → keywords + entities
|
||||
Graph->>ESVec: get_relevant_ents_by_keywords()
|
||||
Graph->>ESVec: get_relevant_relations_by_txt()
|
||||
Graph->>Graph: n_hop_with_weight 路径扩展
|
||||
Graph->>Graph: Score = pagerank * sim
|
||||
Graph->>Graph: _community_retrieval_()
|
||||
Graph-->>Retriever: Entity+Relation+CommunityReport chunk
|
||||
Retriever->>Retriever: insert(0, graph_result)
|
||||
end
|
||||
|
||||
Retriever-->>WF: List[DocumentChunk]
|
||||
end
|
||||
|
||||
WF->>WF: _deduplicate_docs(all_results)
|
||||
|
||||
alt reranker_id 配置
|
||||
WF->>Rerank: rerank(query, all_results, reranker_top_k)
|
||||
Rerank-->>WF: reranked chunks
|
||||
end
|
||||
|
||||
Note over Prompt,Cache: === 阶段 3:Prompt 组装 + LLM 生成 ===
|
||||
WF->>WF: 返回 {"chunks": [...], "citations": [...]}
|
||||
WF->>Prompt: citation_prompt(chunks)
|
||||
Prompt->>Prompt: 组装 System Prompt + 检索上下文
|
||||
|
||||
Prompt->>Cache: get_llm_cache(model, prompt)
|
||||
alt cache miss
|
||||
Prompt->>LLM: chat(system, history, gen_conf)
|
||||
LLM-->>Prompt: answer, tokens
|
||||
Prompt->>Cache: set_llm_cache(model, prompt, answer)
|
||||
else cache hit
|
||||
Cache-->>Prompt: cached answer
|
||||
end
|
||||
|
||||
Note over User,Cache: === 阶段 4:后处理 ===
|
||||
Prompt->>Dealer: insert_citations(answer, chunks, chunk_v)
|
||||
Dealer->>Dealer: pagerank*sim 定位引用位置
|
||||
Dealer-->>Prompt: answer_with_citations, cited_ids
|
||||
|
||||
Prompt-->>User: 最终回答(含引用标注)
|
||||
78
docs/rag/overview/04-graphrag-indexing.mmd
Normal file
78
docs/rag/overview/04-graphrag-indexing.mmd
Normal file
@@ -0,0 +1,78 @@
|
||||
%% MemoryBear GraphRAG 索引构建时序图
|
||||
%% 覆盖 Light 与 General 两条分支的差异
|
||||
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant Celery as Celery<br/>tasks.py:473
|
||||
participant Index as graphrag/general/index.py<br/>run_graphrag_for_kb()
|
||||
participant KGExt as GraphExtractor<br/>light/graph_extractor.py:31<br/>general/graph_extractor.py:34
|
||||
participant LLM as llm/chat_model.py
|
||||
participant ES as ESVector<br/>elasticsearch_vector.py
|
||||
participant Merge as merge_subgraph()
|
||||
participant Resolve as entity_resolution.py<br/>EntityResolution
|
||||
participant Leiden as general/leiden.py<br/>run()
|
||||
participant Community as general/<br/>community_reports_extractor.py:37
|
||||
|
||||
Note over Celery,Community: === 触发条件 ===
|
||||
Celery->>Celery: build_graphrag_for_kb(kb_id)
|
||||
Celery->>Celery: 检查 parser_config.graphrag.use_graphrag
|
||||
Celery->>Index: run_graphrag_for_kb(row, document_ids, ...)
|
||||
|
||||
Note over Index,LLM: === 阶段 1:子图生成 (按 chunk) ===
|
||||
Index->>Index: init_graphrag(task, vector_size)
|
||||
Index->>Index: generate_subgraph() per chunk
|
||||
|
||||
loop 每个 chunk
|
||||
Index->>KGExt: _process_single_content(chunk_key_dp, chunk_text)
|
||||
|
||||
alt Light 分支
|
||||
KGExt->>KGExt: LightRAG-style prompt<br/>+ content_keywords 提取
|
||||
KGExt->>KGExt: GLEANING loop (max 2)
|
||||
else General 分支
|
||||
KGExt->>KGExt: MS GraphRAG-style prompt<br/>perform_variable_replacements
|
||||
KGExt->>KGExt: tiktoken logit-bias Y/N loop
|
||||
end
|
||||
|
||||
KGExt->>LLM: LLM 调用 → entities + relations JSON
|
||||
LLM-->>KGExt: extracted data
|
||||
KGExt->>KGExt: _merge_nodes() + _merge_edges()
|
||||
KGExt-->>Index: (entities_data, relationships_data)
|
||||
end
|
||||
|
||||
Index->>ES: store subgraph (entities + relations chunks)
|
||||
|
||||
Note over Merge,ES: === 阶段 2:子图合并 ===
|
||||
Index->>Merge: merge_subgraph()
|
||||
Merge->>ES: get_graph() 加载全局图
|
||||
Merge->>Merge: graph_merge(old_graph, subgraph, change)
|
||||
Merge->>Merge: nx.pagerank(new_graph)
|
||||
Merge->>ES: set_graph() 写回全局图 + entities + relations
|
||||
|
||||
Note over Resolve,ES: === 阶段 3:实体消歧 (可选) ===
|
||||
opt with_resolution == True
|
||||
Index->>Resolve: resolve_entities(graph, subgraph_nodes)
|
||||
Resolve->>LLM: 两两实体相似度 LLM 匹配
|
||||
LLM-->>Resolve: 合并建议
|
||||
Resolve->>Resolve: nx.pagerank(graph)
|
||||
Resolve->>ES: set_graph()
|
||||
end
|
||||
|
||||
Note over Leiden,Community: === 阶段 4:社区报告 (General only) ===
|
||||
opt with_community == True (General)
|
||||
Index->>Leiden: leiden.run(graph)
|
||||
Leiden->>Leiden: graspologic.partition.<br/>hierarchical_leiden<br/>max_cluster_size=12
|
||||
Leiden-->>Index: {level: {community_id: {nodes: [...]}}}
|
||||
|
||||
loop 每个 community (nodes >= 2)
|
||||
Index->>Community: __call__(graph, callback)
|
||||
Community->>Community: 构建 entity_df + relation_df
|
||||
Community->>LLM: COMMUNITY_REPORT_PROMPT
|
||||
LLM-->>Community: {title, summary, findings, rating}
|
||||
Community->>Community: add_community_info2graph()
|
||||
end
|
||||
|
||||
Community->>ES: index community_report chunks
|
||||
end
|
||||
|
||||
Note over Index,ES: === Mind Map (独立功能,非主链路) ===
|
||||
Note right of Index: mind_map_extractor.py<br/>由外部调用,非索引管道<br/>sections → 层级 markdown mind map
|
||||
194
docs/rag/overview/DocMap.md
Normal file
194
docs/rag/overview/DocMap.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# DocMap — MemoryBear RAG 文档目录大纲
|
||||
|
||||
> **定位**:Sprint-2 深度文档化的任务拆解输入。每行 = 一篇待写文档,标题格式与 [S1-T1] 统一模板兼容。
|
||||
> **责任人草拟**:基于当前 Sprint-1 分工建议,实际分配由项目经理确认。
|
||||
> **目录结构**:`docs/rag/<stage>/<topic>.md`
|
||||
|
||||
---
|
||||
|
||||
## 文档目录总览
|
||||
|
||||
```
|
||||
docs/rag/
|
||||
├── _meta/ # [S1-T1] 模板与评分卡(由 @知识运营与治理专家 维护)
|
||||
├── 01-loader/
|
||||
│ ├── 01-web-crawler.md # Web 爬虫:URL 发现、内容提取、速率控制
|
||||
│ ├── 02-feishu-integration.md # 飞书集成:API 调用、鉴权、文档导出
|
||||
│ ├── 03-yuque-integration.md # 语雀集成:知识库同步、文档下载
|
||||
│ └── 04-file-upload.md # 文件上传与预处理(本地文件系统、NFS 兼容)
|
||||
├── 02-parser/
|
||||
│ ├── 01-pdf-parser.md # PDF 解析:OCR + Layout + Table 流水线
|
||||
│ ├── 02-docx-parser.md # DOCX 解析:段落提取、图片嵌入
|
||||
│ ├── 03-html-md-parser.md # HTML / Markdown / TXT 解析
|
||||
│ ├── 04-excel-parser.md # Excel 解析:行列转表格结构
|
||||
│ └── 05-vision-pipeline.md # 视觉模块:OCR、布局识别、表格结构识别
|
||||
├── 03-chunking/
|
||||
│ ├── 01-chunking-strategies.md # 分块策略全景:naive_merge、层级分块、树分块
|
||||
│ ├── 02-task-type-adapters.md # 文档类型适配器:book / paper / laws / qa / one
|
||||
│ ├── 03-tokenizer.md # RagTokenizer:中文分词、英文处理、fine_grained
|
||||
│ └── 04-multimodal-chunking.md # 多模态分块:图片 VLM 描述、音频转文本
|
||||
├── 04-embedding/
|
||||
│ ├── 01-embedding-model-arch.md # Embedding 模型架构:Base 接口 + 10+ Provider
|
||||
│ ├── 02-provider-guide.md # Provider 接入指南:OpenAI / HuggingFace / 国产模型
|
||||
│ └── 03-auto-questions.md # 自动问题生成:并发策略、LLM 缓存
|
||||
├── 05-vdb/
|
||||
│ ├── 01-elasticsearch-schema.md # ES 索引 Schema:字段定义、mapping、analyzer
|
||||
│ ├── 02-hybrid-search.md # 混合检索:BM25 + Vector 加权融合
|
||||
│ └── 03-storage-connections.md # 存储连接层:ES、Redis、DocStore
|
||||
├── 06-graphrag/
|
||||
│ ├── 01-graphrag-overview.md # GraphRAG 总览:Light vs General 对比
|
||||
│ ├── 02-entity-relation-extraction.md # 实体关系抽取:Extractor 流程、Prompt 工程
|
||||
│ ├── 03-graph-merge-and-rank.md # 图合并与 PageRank:子图合并、实体消歧
|
||||
│ ├── 04-community-reports.md # 社区报告:Leiden 聚类、LLM 报告生成(General only)
|
||||
│ └── 05-knowledge-graph-search.md # KG 检索:Query 分析、实体匹配、N-hop 扩展
|
||||
├── 07-retrieval/
|
||||
│ ├── 01-retrieval-api.md # 检索 API:knowledge_retrieval()、Dealer.search()
|
||||
│ ├── 02-query-understanding.md # Query 理解:关键词提取、同义词扩展
|
||||
│ └── 03-multi-kb-retrieval.md # 多知识库检索:结果合并、去重策略
|
||||
├── 08-reranking/
|
||||
│ ├── 01-rerank-architecture.md # 重排序架构:内置评分 vs 外部 Rerank 模型
|
||||
│ └── 02-rerank-providers.md # Rerank Provider:Jina / DashScope / Xinference
|
||||
├── 09-prompt/
|
||||
│ ├── 01-prompt-system.md # Prompt 模板系统:template.py + generator.py
|
||||
│ ├── 02-citation-prompts.md # 引用标注 Prompt:citation_prompt / citation_plus
|
||||
│ └── 03-toc-prompts.md # 目录相关 Prompt:TOC 检测、提取、相关性
|
||||
├── 10-llm/
|
||||
│ ├── 01-llm-chat-model.md # Chat 模型架构:Base.chat() / chat_streamly()
|
||||
│ ├── 02-llm-providers.md # Chat Provider 全景:OpenAI / Azure / 国产模型
|
||||
│ └── 03-vision-model.md # 视觉模型:VLM 描述、图片理解
|
||||
├── 11-e2e/
|
||||
│ ├── 01-indexing-pipeline.md # 端到端入库流程:Celery 任务链、错误处理、进度追踪
|
||||
│ ├── 02-query-pipeline.md # 端到端检索流程:Workflow Node → 检索 → 生成
|
||||
│ └── 03-answer-postprocess.md # 回答后处理:引用插入、缓存、流式输出
|
||||
└── 12-architecture-evolution/
|
||||
├── 01-modularization-roadmap.md # 模块化拆分建议
|
||||
├── 02-performance-optimization.md # 性能优化方向
|
||||
└── 03-future-extensions.md # 未来扩展:多模态检索、混合搜索、对话记忆
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文档详细定义
|
||||
|
||||
### 01-loader
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 01-01 | Web 爬虫 | **写**:URL 规范化、robots.txt 检查、速率限制、HTTP 抓取、内容提取、去重策略。**不写**:搜索引擎索引、分布式爬虫、JS 渲染。 | `crawler/web_crawler.py`, `crawler/http_fetcher.py`, `crawler/content_extractor.py`, `crawler/rate_limiter.py`, `crawler/robots_parser.py` | Python 工程师 | 需覆盖 CrawledDocument 数据结构 |
|
||||
| 01-02 | 飞书集成 | **写**:App 鉴权、文件夹遍历、文档导出(PDF/DOCX/Sheet)、异步轮询下载。**不写**:飞书审批流、机器人消息推送。 | `integrations/feishu/client.py`, `integrations/feishu/retry.py`, `integrations/feishu/models.py` | Python 工程师 | 需说明 `_export_file` vs `_download_file` 区别 |
|
||||
| 01-03 | 语雀集成 | **写**:个人 Token 鉴权、知识库遍历、文档详情获取、多种格式下载(MD/HTML/Excel)。**不写**:语雀协作编辑、版本管理。 | `integrations/yuque/client.py`, `integrations/yuque/retry.py`, `integrations/yuque/models.py` | Python 工程师 | lakesheet 解压逻辑需重点说明 |
|
||||
| 01-04 | 文件上传 | **写**:文件上传接口、NFS 同步等待、binary 读取策略、进度追踪。**不写**:CDN 分发、大文件分片上传。 | `controllers/document_controller.py`, `utils/file_utils.py`, `tasks.py:213` | Python 工程师 | 30s NFS 等待逻辑是 MemoryBear 特有 |
|
||||
|
||||
### 02-parser
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 02-01 | PDF 解析 | **写**:PDF 渲染、OCR 文本检测、布局分类、表格结构识别、文本合并策略。**不写**:PDF 生成/编辑、数字签名验证。 | `deepdoc/parser/pdf_parser.py`, `deepdoc/vision/ocr.py`, `deepdoc/vision/layout_recognizer.py`, `deepdoc/vision/table_structure_recognizer.py` | Python 工程师 | 核心中的核心,需重点投入 |
|
||||
| 02-02 | DOCX 解析 | **写**:段落提取、图片提取、超链接提取、OLE 嵌入文件。**不写**:DOCX 生成、样式渲染。 | `deepdoc/parser/docx_parser.py`, `utils/file_utils.py:extract_embed_file` | Python 工程师 | 需与 `app/naive.py` 的 vision_figure_parser 联动说明 |
|
||||
| 02-03 | HTML/MD/TXT 解析 | **写**:HTML 标签清洗、Markdown 结构化解析、纯文本处理。**不写**:CSS 样式解析、JS 执行。 | `deepdoc/parser/html_parser.py`, `deepdoc/parser/markdown_parser.py`, `deepdoc/parser/txt_parser.py` | Python 工程师 | 合并为一篇即可 |
|
||||
| 02-04 | Excel 解析 | **写**:行列读取、Sheet 遍历、表头检测、Markdown 表格转换。**不写**:公式计算、图表提取。 | `deepdoc/parser/excel_parser.py` | Python 工程师 | 轻量 |
|
||||
| 02-05 | 视觉流水线 | **写**:OCR 模型(ONNXRuntime)、布局识别模型、表格结构模型、图像预处理。**不写**:模型训练、模型量化。 | `deepdoc/vision/*.py` | Python 工程师 | 含模型加载、推理、后处理 |
|
||||
|
||||
### 03-chunking
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 03-01 | 分块策略全景 | **写**:naive_merge、naive_merge_with_images、hierarchical_merge、tree_merge 的实现与选择策略。**不写**:通用 NLP 分词算法原理。 | `nlp/__init__.py:562+`, `nlp/rag_tokenizer.py` | Python 工程师 | 需附决策树:何时用哪种策略 |
|
||||
| 03-02 | 文档类型适配器 | **写**:book/paper/manual/laws/qa/one/picture/audio 各自的分块逻辑、数据结构差异。**不写**:业务场景适配(如医疗/法律专有分块)。 | `app/naive.py:508`, `app/book.py`, `app/paper.py`, `app/manual.py`, `app/laws.py`, `app/qa.py`, `app/one.py`, `app/picture.py`, `app/audio.py` | Python 工程师 | 核心章节,需逐一说明 |
|
||||
| 03-03 | RagTokenizer | **写**:中文分词(Huqie/datrie)、英文处理(nltk/Porter/WordNet)、fine_grained_tokenize、分词对检索的影响。**不写**:分词算法数学推导。 | `nlp/rag_tokenizer.py` | Python 工程师 | 与 ES ik_max_word 的对比 |
|
||||
| 03-04 | 多模态分块 | **写**:图片 VLM 描述调用链、音频 sequence2txt 转录、视频处理(如有)。**不写**:VLM/ASR 模型内部原理。 | `app/picture.py`, `app/audio.py`, `llm/cv_model.py`, `llm/sequence2txt_model.py`, `deepdoc/parser/figure_parser.py` | Python 工程师 | 需说明 vision_model 注入机制 |
|
||||
|
||||
### 04-embedding
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 04-01 | Embedding 模型架构 | **写**:Base.encode() 接口、批次处理、Token 截断(8000/2048)、返回格式。**不写**:Embedding 模型原理(Word2Vec/BERT 等)。 | `llm/embedding_model.py` | Python 工程师 | 重点讲接口契约 |
|
||||
| 04-02 | Provider 接入指南 | **写**:10+ Provider 的配置方式、API Key 管理、Base URL 设置、批次大小差异。**不写**:各厂商 API 的通用文档。 | `llm/embedding_model.py` 各子类 | Python 工程师 | 表格形式列出即可 |
|
||||
| 04-03 | 自动问题生成 | **写**:并发生成策略(ThreadPoolExecutor)、LLM 缓存机制(redis)、问题注入到 chunk metadata。**不写**:问题生成质量评估。 | `tasks.py:323+`, `prompts/generator.py:question_proposal()` | Python 工程师 | 与检索效果的关系 |
|
||||
|
||||
### 05-vdb
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 05-01 | ES 索引 Schema | **写**:字段定义、mapping 类型、ik_max_word analyzer、dense_vector cosine 配置、动态维度。**不写**:ES 集群运维、分片策略。 | `vdb/field.py`, `vdb/elasticsearch/elasticsearch_vector.py:653+` | Python 工程师 | 需附完整 mapping 示例 |
|
||||
| 05-02 | 混合检索 | **写**:BM25 + Vector 加权融合(0.05:0.95)、FusionExpr、score 归一化、降级策略。**不写**:BM25 算法数学推导、近似最近邻算法。 | `nlp/search.py:439`, `vdb/elasticsearch/elasticsearch_vector.py:374`, `utils/doc_store_conn.py:FusionExpr` | Python 工程师 | 核心章节,需讲清楚为什么权重是 0.05:0.95 |
|
||||
| 05-03 | 存储连接层 | **写**:ES 连接、Redis 缓存、DocStore 抽象。**不写**:连接池调优、网络安全配置。 | `utils/es_conn.py`, `utils/redis_conn.py`, `utils/doc_store_conn.py` | Python 工程师 | 轻量 |
|
||||
|
||||
### 06-graphrag
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 06-01 | GraphRAG 总览 | **写**:Light vs General 架构对比、适用场景、配置开关(use_graphrag/resolution/community)。**不写**:图数据库选型对比(已选 ES)。 | `graphrag/light/`, `graphrag/general/`, `graphrag/search.py` | Python 工程师 | 必须包含对比表格 |
|
||||
| 06-02 | 实体关系抽取 | **写**:Extractor 基类、_process_single_content 流程、Gleaning Loop、Prompt 工程、LLM 输出解析。**不写**:信息抽取的通用 NLP 方法。 | `graphrag/light/graph_extractor.py`, `graphrag/general/graph_extractor.py`, `graphrag/general/extractor.py` | Python 工程师 | 核心章节 |
|
||||
| 06-03 | 图合并与 PageRank | **写**:merge_subgraph 流程、nx.Graph 操作、PageRank 计算、实体消歧(EntityResolution)。**不写**:PageRank 数学推导。 | `graphrag/general/index.py`, `graphrag/entity_resolution.py` | Python 工程师 | 需附图数据结构示例 |
|
||||
| 06-04 | 社区报告 | **写**:Leiden 层次聚类、社区报告 Prompt、报告数据结构、存储方式。**不写**:社区发现算法数学原理。 | `graphrag/general/leiden.py`, `graphrag/general/community_reports_extractor.py`, `graphrag/general/community_report_prompt.py` | Python 工程师 | General only |
|
||||
| 06-05 | KG 检索 | **写**:KGSearch.retrieval() 流程、Query Rewrite、实体匹配、N-hop 扩展、社区报告检索。**不写**:图遍历算法通用理论。 | `graphrag/search.py:130` | Python 工程师 | 与标准检索的交互关系 |
|
||||
|
||||
### 07-retrieval
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 07-01 | 检索 API | **写**:knowledge_retrieval() 接口、Dealer.search() 内部实现、MatchDenseExpr / MatchTextExpr / FusionExpr。**不写**:信息检索通用理论。 | `nlp/search.py:36`, `nlp/search.py:349`, `utils/doc_store_conn.py` | Python 工程师 | 核心章节 |
|
||||
| 07-02 | Query 理解 | **写**:关键词提取、同义词扩展、查询改写、min_match 阈值调整。**不写**:NLP 句法分析。 | `nlp/query.py`, `nlp/synonym.py`, `nlp/term_weight.py` | Python 工程师 | 轻量 |
|
||||
| 07-03 | 多知识库检索 | **写**:Folder 类型递归检索、跨 KB 结果去重、权限过滤。**不写**:权限系统的 RBAC 设计。 | `workflow/nodes/knowledge/node.py:195`, `knowledge_repository.py` | Python 工程师 | 需说明 Folder 类型的特殊处理 |
|
||||
|
||||
### 08-reranking
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 08-01 | 重排序架构 | **写**:内置重排(token+vector 相似度融合)vs 外部 Rerank 模型、调用时机、容错降级。**不写**:Learning-to-Rank 通用理论。 | `nlp/search.py:606`, `models/rerank.py` | Python 工程师 | 需对比两种方式的适用场景 |
|
||||
| 08-02 | Rerank Provider | **写**:JinaRerank、DashScopeRerank 的 API 调用、参数映射。**不写**:各厂商 API 通用文档。 | `models/rerank.py:57+` | Python 工程师 | 轻量 |
|
||||
|
||||
### 09-prompt
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 09-01 | Prompt 模板系统 | **写**:template.py 的 .md 文件加载机制、generator.py 的函数式 Prompt 组装、参数替换。**不写**:Prompt Engineering 通用方法论。 | `prompts/template.py`, `prompts/generator.py` | Python 工程师 | 需列出全部模板清单 |
|
||||
| 09-02 | 引用标注 Prompt | **写**:citation_prompt / citation_plus 的输入输出、引用格式、上下文窗口管理。**不写**:学术论文引用规范。 | `prompts/generator.py:citation_prompt()` | Python 工程师 | 与 insert_citations 联动 |
|
||||
| 09-03 | 目录相关 Prompt | **写**:TOC 检测、提取、层级分配、基于 TOC 的 chunk 相关性筛选。**不写**:目录生成算法。 | `prompts/generator.py` TOC 系列函数 | Python 工程师 | 轻量 |
|
||||
|
||||
### 10-llm
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 10-01 | Chat 模型架构 | **写**:Base.chat() / chat_streamly() / chat_with_tools() 接口、返回格式、流式输出。**不写**:Transformer 模型原理。 | `llm/chat_model.py` | Python 工程师 | 重点讲接口契约 |
|
||||
| 10-02 | Chat Provider 全景 | **写**:各 Provider 配置、温度/TopP/MaxTokens 参数透传、错误处理。**不写**:各厂商 API 通用文档。 | `llm/chat_model.py` 各子类 | Python 工程师 | 表格形式 |
|
||||
| 10-03 | 视觉模型 | **写**:CV 模型接口、VLM 描述调用、图片理解。**不写**:CNN/ViT 原理。 | `llm/cv_model.py` | Python 工程师 | 轻量 |
|
||||
|
||||
### 11-e2e
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 11-01 | 端到端入库流程 | **写**:Celery 任务链、parse_document 完整流程、进度追踪、错误处理、GraphRAG 异步触发。**不写**:Celery 分布式队列原理。 | `tasks.py` | Python 工程师 | 核心章节,需附时序图 |
|
||||
| 11-02 | 端到端检索流程 | **写**:Workflow Knowledge Node 完整流程、检索模式选择、结果组装。**不写**:Workflow Engine 通用设计。 | `workflow/nodes/knowledge/node.py` | Python 工程师 | 核心章节 |
|
||||
| 11-03 | 回答后处理 | **写**:引用插入、缓存策略、流式输出处理。**不写**:WebSocket 通用原理。 | `nlp/search.py:489`, `utils/redis_conn.py` | Python 工程师 | 轻量 |
|
||||
|
||||
### 12-architecture-evolution
|
||||
|
||||
| 序号 | 标题 | 范围边界 | 关联源码模块 | 责任人草拟 | 备注 |
|
||||
|------|------|----------|-------------|-----------|------|
|
||||
| 12-01 | 模块化拆分建议 | **写**:当前耦合点识别、建议的接口抽象(如 ParserInterface、ChunkerInterface)、拆分优先级。**不写**:微服务拆分方案。 | 全局代码分析 | AI 知识库专家 | 架构建议,无代码 |
|
||||
| 12-02 | 性能优化方向 | **写**:Embedding 批处理优化、ES 查询优化、GraphRAG 并发优化、缓存命中率提升。**不写**:通用性能优化方法论。 | 全局代码分析 | AI 知识库专家 | 需量化当前瓶颈假设 |
|
||||
| 12-03 | 未来扩展 | **写**:多模态检索、混合搜索增强、对话记忆优化、知识图谱演进方向。**不写**:产品需求文档。 | 全局代码分析 | AI 知识库专家 | 架构建议,无代码 |
|
||||
|
||||
---
|
||||
|
||||
## 工作量估算
|
||||
|
||||
| 阶段 | 文档数 | 预估 Sprint-2 人天(每篇 0.5~1d) |
|
||||
|------|--------|----------------------------------|
|
||||
| 01-loader | 4 | 2d |
|
||||
| 02-parser | 5 | 3d |
|
||||
| 03-chunking | 4 | 2.5d |
|
||||
| 04-embedding | 3 | 1.5d |
|
||||
| 05-vdb | 3 | 2d |
|
||||
| 06-graphrag | 5 | 3d |
|
||||
| 07-retrieval | 3 | 2d |
|
||||
| 08-reranking | 2 | 1d |
|
||||
| 09-prompt | 3 | 1.5d |
|
||||
| 10-llm | 3 | 1.5d |
|
||||
| 11-e2e | 3 | 2d |
|
||||
| 12-architecture-evolution | 3 | 1.5d |
|
||||
| **合计** | **41** | **~23.5d** |
|
||||
|
||||
> 注:Python 工程师承担约 30 篇(技术实现细节),AI 知识库专家承担约 8 篇(架构/优化/扩展方向)。具体分配由项目经理确认。
|
||||
193
docs/rag/overview/boundaries.md
Normal file
193
docs/rag/overview/boundaries.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# RAG 环节边界定义
|
||||
|
||||
> 目标:明确每个 RAG 阶段的输入 / 输出 / 上下游接口(数据结构层面),避免 Sprint-2 各文档之间留白或重叠。
|
||||
|
||||
---
|
||||
|
||||
## 总览图
|
||||
|
||||
```
|
||||
[Data Sources] ──→ [Loader] ──→ [Parser] ──→ [Chunking] ──→ [Embedding] ──→ [VDB]
|
||||
↑
|
||||
│ (async)
|
||||
[GraphRAG]
|
||||
|
||||
[User Query] ──→ [Query Understanding] ──→ [Retrieval] ──→ [Reranking] ──→ [Prompt] ──→ [LLM] ──→ [Post-Process] ──→ [Answer]
|
||||
↑
|
||||
│ (GRAPH mode)
|
||||
[KG Search]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Loader(数据加载层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | 外部系统:飞书 API、语雀 API、Web URL、用户上传接口 |
|
||||
| **输入** | 飞书:folder_token, app_id, app_secret;语雀:user_id, token;Web:entry_url, max_pages;上传:multipart/form-data |
|
||||
| **输出** | **原始文件内容**:`CrawledDocument` (dataclass) 或 **本地文件路径** (.docx/.pdf/.md/.html/.xlsx) |
|
||||
| **输出数据结构** | `CrawledDocument(url, title, content, content_length, crawl_timestamp, metadata)`;本地文件:`str` (path) |
|
||||
| **下游** | Parser:接收文件路径或 bytes,调用对应 format-specific parser |
|
||||
| **边界约定** | Loader 不做任何格式解析(不提取正文、不做 OCR)。仅负责:鉴权 → 获取/下载 → 存盘。格式识别由 Parser 层的 `naive.chunk()` 根据文件扩展名决定。 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Parser(文档解析层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | Loader:接收文件路径 `str` 或二进制 `bytes` |
|
||||
| **输入** | `(filename: str, binary: bytes \| None, from_page, to_page, callback, vision_model)` |
|
||||
| **输出** | `sections: List[Tuple[str, str]]` — (text_content, layout_tag);`tables: List[Tuple[Tuple[Optional[Image.Image], Union[str, List[str]]], List[Tuple]]]` |
|
||||
| **输出数据结构** | 元组列表,其中 tag 表示布局类型("Title"/"Text"/"Table"/...),text 可能含位置标签 `@@page\tx0\tx1\ttop\tbottom##` |
|
||||
| **下游** | Chunking:接收 `sections` + `tables`,执行合并与分块 |
|
||||
| **边界约定** | Parser 负责格式-specific 的**纯提取**,不负责语义分块。PDF Parser 特殊:需输出 OCR 结果 + 布局信息 + 表格 HTML。Parser 之间互不调用——由 `naive.chunk()` 统一 dispatch。 |
|
||||
|
||||
---
|
||||
|
||||
## 3. Chunking(文本分块层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | Parser:`sections` + `tables` |
|
||||
| **输入** | `sections: List[Tuple[str, str]]`, `tables`, `chunk_token_num: int`, `delimiter: str`, `parser_config: dict` |
|
||||
| **输出** | `res: List[Dict]` — 分块后的文档字典列表 |
|
||||
| **输出数据结构(关键字段)** | `content_with_weight: str`(原始文本), `content_ltks: str`(粗粒度分词), `content_sm_ltks: str`(细粒度分词), `image: PIL.Image`(可选), `page_num_int: int`, `position_int: List[int]`, `top_int: int`, `doc_type_kwd: str` |
|
||||
| **下游** | Embedding:接收 `res`,提取 `content_with_weight` 进行向量化;GraphRAG:接收 `res` 中的文本进行实体关系抽取 |
|
||||
| **边界约定** | Chunking 不调用 Embedding,也不直接写入 VDB。它只负责将长文本切分成符合 token 预算的 chunks,并填充分词/位置元数据。多模态(图片/音频)的分块结果也统一为此数据结构。 |
|
||||
|
||||
---
|
||||
|
||||
## 4. Embedding(向量化层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | Chunking:接收 chunk dicts 的 `content_with_weight` |
|
||||
| **输入** | `texts: List[str]`(batch,默认 ≤16 条) |
|
||||
| **输出** | `(np.array, total_tokens)` — `np.array` shape `(batch_size, vector_dimension)` |
|
||||
| **输出数据结构** | NumPy ndarray,float32;向量维度由模型决定(如 OpenAI text-embedding-3: 1536d) |
|
||||
| **下游** | VDB:接收 `(chunk_text, vector, metadata)` 组装成 `DocumentChunk` 后入库 |
|
||||
| **边界约定** | Embedding 层无状态,不管理模型生命周期。Provider 通过工厂模式实例化(`Base._FACTORY_NAME` 匹配)。输入文本超长时自动截断(OpenAI 截到 8000 tokens,QWen 截到 2048)。支持 `encode_queries()` 单条 query 编码。 |
|
||||
|
||||
---
|
||||
|
||||
## 5. VDB(向量数据库层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | Embedding:接收 `(text, vector, metadata)`;Chunking:接收 chunk dicts 中的 metadata |
|
||||
| **输入** | `DocumentChunk(page_content: str, vector: List[float], metadata: dict)`;或检索时:`query: str, top_k: int, indices: str, score_threshold: float` |
|
||||
| **输出(入库)** | ack / error;**输出(检索)**:`List[DocumentChunk]` |
|
||||
| **存储 Schema** | `page_content: text(ik_max_word)`, `metadata: object(doc_id, document_id, knowledge_id, sort_id, status)`, `vector: dense_vector(cosine, dynamic_dims)` |
|
||||
| **下游** | Retrieval:通过 `search_by_vector` / `search_by_full_text` / `search` (hybrid) 获取结果 |
|
||||
| **边界约定** | VDB 同时承担**文档存储**(全文索引)和**向量存储**(密集向量索引)双重职责。ES 是唯一的后端(无 Milvus/Pinecone 等)。GraphRAG 的实体/关系/社区报告也以相同 chunk 格式存储于此。 |
|
||||
|
||||
---
|
||||
|
||||
## 6. GraphRAG(知识图谱层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | Chunking:接收 chunk dicts 的 `content_with_weight`;Celery:异步触发 `build_graphrag_for_document` |
|
||||
| **输入(索引)** | `(document_id, chunk_text)` tuples;`chat_model: Base`, `embedding_model: OpenAIEmbed`, `vector_service: ElasticSearchVector` |
|
||||
| **输入(检索)** | `question: str, workspace_ids: List[str], kb_ids: List[str], emb_mdl, llm` |
|
||||
| **输出(索引)** | `nx.Graph`(全局图)存储到 ES;`entity` chunks + `relation` chunks + `community_report` chunks(General only) |
|
||||
| **输出(检索)** | `Dict` with `page_content` = "Entities CSV + Relations CSV + Community Reports",`metadata` 含引用信息 |
|
||||
| **下游** | VDB:索引/存储实体、关系、社区报告 chunks;Retrieval:`KGSearch.retrieval()` 返回的 chunk 被 `insert(0, ...)` 插入标准检索结果 |
|
||||
| **边界约定** | GraphRAG 是**独立异步流程**,不与标准 RAG 索引同步。Light 和 General 共享相同的存储格式但 General 多出 community_report。GraphRAG 不替代 VDB,而是**在 VDB 之上增加图语义层**。检索时 KG 结果优先级最高(insert at position 0)。 |
|
||||
|
||||
---
|
||||
|
||||
## 7. Retrieval(检索层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | VDB:通过 `search_by_vector` / `search_by_full_text` 获取候选;GraphRAG:`KGSearch.retrieval()` 获取图语义结果;Workflow Node:`KnowledgeRetrievalNode.execute()` 发起调用 |
|
||||
| **输入** | `query: str, config: Dict(knowledge_bases[], merge_strategy, reranker_id, reranker_top_k, use_graph)` |
|
||||
| **输出** | `List[DocumentChunk]` — 按相关性降序排列的文档块 |
|
||||
| **输出数据结构** | `DocumentChunk(page_content: str, metadata: dict)`,其中 metadata 含 `score`, `doc_id`, `document_id`, `knowledge_id`, `highlight` |
|
||||
| **下游** | Reranking:接收候选列表,可选执行重排序;Prompt:接收 chunks 组装上下文 |
|
||||
| **边界约定** | Retrieval 层支持 4 种模式:PARTICIPLE(全文)、SEMANTIC(向量)、HYBRID(混合)、GRAPH(图增强)。多 KB 时逐 KB 检索后合并。HYBRID 的默认权重为 BM25 0.05 + Vector 0.95。检索失败(空结果)时自动降级(min_match 0.1 + similarity 0.17 重试)。 |
|
||||
|
||||
---
|
||||
|
||||
## 8. Reranking(重排序层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | Retrieval:接收候选 `List[DocumentChunk]` |
|
||||
| **输入** | `query: str, docs: List[DocumentChunk], top_k: int`;或 `reranker_id: UUID` |
|
||||
| **输出** | `List[DocumentChunk]` — 重排序后的文档块(长度 ≤ top_k) |
|
||||
| **输出数据结构** | 同 Retrieval 输出,metadata 中更新 `score` 为重排序后的分数 |
|
||||
| **下游** | Prompt:接收重排序后的 chunks 组装上下文 |
|
||||
| **边界约定** | Reranking 是**可选层**。未配置 reranker_id 时,HYBRID 结果按 metadata.score 降序截断。配置了 reranker_id 时,调用外部 Rerank API(Jina / DashScope / Xinference)。Rerank 失败时**降级**到原始结果(不阻断流程)。 |
|
||||
|
||||
---
|
||||
|
||||
## 9. Prompt(Prompt 组装层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | Reranking:接收排序后的 chunks;Workflow:接收用户 query |
|
||||
| **输入** | `chunks: List[DocumentChunk], query: str, system_prompt: str`(可选) |
|
||||
| **输出** | `system: str, history: List[Dict]` — LLM 可调用的消息格式 |
|
||||
| **输出数据结构** | `system: str`(含检索上下文 + 系统指令),`history: [{"role": "user", "content": query}]` |
|
||||
| **下游** | LLM:`Base.chat(system, history, gen_conf)` |
|
||||
| **边界约定** | Prompt 层**不**调用 LLM,只负责**文本组装**。组装逻辑包括:citation_prompt(引用标注格式)、keyword_extraction(用于缓存 key)、content_tagging(内容分类)。Prompt 模板以 `.md` 文件形式存储在 `prompts/` 目录,通过 `template.py` 动态加载。 |
|
||||
|
||||
---
|
||||
|
||||
## 10. LLM(大模型生成层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | Prompt:接收 `system` + `history` |
|
||||
| **输入** | `system: str, history: List[Dict], gen_conf: dict(temperature, top_p, max_tokens)` |
|
||||
| **输出** | `(answer: str, tokens: int)` 或流式 `Generator[str \| int]` |
|
||||
| **输出数据结构** | 字符串(生成的回答文本);流式模式下逐 token 返回 |
|
||||
| **下游** | Post-Process:`insert_citations()` 插入引用标注 |
|
||||
| **边界约定** | LLM 层**无上下文记忆**(stateless),每次调用携带完整 history。支持 10+ Provider,通过 `_FACTORY_NAME` 工厂模式匹配。流式输出通过 `chat_streamly()` 实现,返回 Generator。错误处理:API 异常时抛出,由上层(Workflow / Celery)捕获。 |
|
||||
|
||||
---
|
||||
|
||||
## 11. Post-Process(后处理层)
|
||||
|
||||
| 维度 | 定义 |
|
||||
|------|------|
|
||||
| **上游** | LLM:接收生成的 `answer`;Retrieval:接收原始 `chunks` + `chunk_v`(向量) |
|
||||
| **输入** | `answer: str, chunks: List[DocumentChunk], chunk_v: List[np.array], embd_mdl, tkweight, vtweight` |
|
||||
| **输出** | `(answer_with_citations: str, cited_ids: Set[str])` |
|
||||
| **输出数据结构** | 字符串(含 `[1]`, `[2]` 等引用标记),`Set[str]`(被引用的 chunk id 集合) |
|
||||
| **下游** | User:最终展示;Cache:写入 Redis 缓存 |
|
||||
| **边界约定** | Post-Process 只做**引用标注插入**(`insert_citations()`),不做内容修改。引用定位算法基于 `pagerank * similarity` 评分。代码块(```...```)内**不**插入引用。缓存键由 `(model_name, prompt_text)` 组合生成,TTL 由 Redis 配置决定。 |
|
||||
|
||||
---
|
||||
|
||||
## 跨层数据流总表
|
||||
|
||||
| 阶段 | 输入数据类型 | 输出数据类型 | 关键数据结构 / 文件 |
|
||||
|------|-------------|-------------|---------------------|
|
||||
| Loader | URL / Token / File | `CrawledDocument` / `str` (path) | `crawler/models.py`, `integrations/*/models.py` |
|
||||
| Parser | `str` (path) / `bytes` | `List[Tuple[str, str]]` + tables | `deepdoc/parser/*.py` |
|
||||
| Chunking | sections + tables | `List[Dict]` | `nlp/__init__.py`, `app/naive.py` |
|
||||
| Embedding | `List[str]` | `(np.array, int)` | `llm/embedding_model.py` |
|
||||
| VDB | `DocumentChunk` | ack / `List[DocumentChunk]` | `vdb/field.py`, `models/chunk.py` |
|
||||
| GraphRAG | chunk texts | `nx.Graph` + chunks | `graphrag/search.py`, `graphrag/general/index.py` |
|
||||
| Retrieval | `query + config` | `List[DocumentChunk]` | `nlp/search.py` |
|
||||
| Reranking | `query + docs` | `List[DocumentChunk]` | `models/rerank.py` |
|
||||
| Prompt | `chunks + query` | `system + history` | `prompts/generator.py` |
|
||||
| LLM | `system + history` | `str + int` | `llm/chat_model.py` |
|
||||
| Post-Process | `answer + chunks` | `str + Set[str]` | `nlp/search.py:489` |
|
||||
|
||||
---
|
||||
|
||||
## 留白与重叠风险点
|
||||
|
||||
| 风险区域 | 说明 | 建议归属 |
|
||||
|----------|------|----------|
|
||||
| **Parser ↔ Chunking 边界** | Parser 输出的 `sections` 格式(含 tag 和位置信息)被 Chunking 的 `naive_merge` 直接消费。若 Parser 改了 tag 格式,Chunking 会受影响。 | **统一在 Parser 文档中定义 `sections` 数据契约**,Chunking 文档只引用该契约。 |
|
||||
| **Embedding ↔ VDB 边界** | Embedding 输出维度必须与 VDB mapping 中 `dense_vector` 的 dims 一致。动态维度由首次 encode 决定。 | **Embedding 文档声明维度获取方式**,VDB 文档只引用。 |
|
||||
| **GraphRAG ↔ VDB 边界** | GraphRAG 的实体/关系/社区报告以 `DocumentChunk` 格式存入 VDB,与标准 chunk 共用同一 ES index。 | **VDB 文档定义通用存储格式**,GraphRAG 文档只说明使用了该格式。 |
|
||||
| **Retrieval ↔ Reranking 边界** | Retrieval 的 HYBRID 模式在 Node 层已做 dedup,但 `knowledge_retrieval()` 函数也有独立 rerank 调用。 | **Reranking 文档**说明两种调用路径(Node 层 vs 函数层)的区别。 |
|
||||
| **Prompt ↔ LLM 边界** | Prompt 组装的 `history` 格式必须与各 Provider 的 API 格式兼容。 | **Prompt 文档**声明输出格式规范,LLM 文档说明各 Provider 的适配。 |
|
||||
249
docs/rag/overview/source-inventory.md
Normal file
249
docs/rag/overview/source-inventory.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# [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<br/>Celery Workers]
|
||||
A2[controllers/<br/>REST API]
|
||||
A3[workflow/nodes/<br/>知识检索节点]
|
||||
A4[services/memory_<br/>dashboard_service.py]
|
||||
end
|
||||
|
||||
subgraph "RAG Core"
|
||||
B1[rag/app<br/>解析与分块]
|
||||
B2[rag/deepdoc/parser<br/>格式解析]
|
||||
B3[rag/deepdoc/vision<br/>版面/OCR]
|
||||
B4[rag/crawler<br/>网页抓取]
|
||||
B5[rag/integrations<br/>飞书/语雀]
|
||||
B6[rag/nlp<br/>分词/搜索调度]
|
||||
B7[rag/llm<br/>多模型Facade]
|
||||
B8[rag/vdb<br/>ES向量存储]
|
||||
B9[rag/graphrag<br/>知识图谱]
|
||||
B10[rag/prompts<br/>Prompt工厂]
|
||||
B11[rag/models<br/>Chunk模型]
|
||||
B12[rag/common<br/>常量/工具]
|
||||
B13[rag/utils<br/>ES/Redis连接]
|
||||
end
|
||||
|
||||
subgraph "旁路模块"
|
||||
C1[rag_utils<br/>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 文档化的底图直接复用。
|
||||
Reference in New Issue
Block a user