Files
MemoryBear/docs/rag/overview/boundaries.md
Multica PM Agent 343a5eebe3
Some checks failed
Sync to Gitee / sync (push) Has been cancelled
docs(rag): add MemoryBear RAG implementation docs v1.0
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>
2026-05-09 10:51:48 +08:00

194 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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, tokenWebentry_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 ndarrayfloat32向量维度由模型决定如 OpenAI text-embedding-3: 1536d |
| **下游** | VDB接收 `(chunk_text, vector, metadata)` 组装成 `DocumentChunk` 后入库 |
| **边界约定** | Embedding 层无状态不管理模型生命周期。Provider 通过工厂模式实例化(`Base._FACTORY_NAME` 匹配。输入文本超长时自动截断OpenAI 截到 8000 tokensQWen 截到 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` chunksGeneral only |
| **输出(检索)** | `Dict` with `page_content` = "Entities CSV + Relations CSV + Community Reports"`metadata` 含引用信息 |
| **下游** | VDB索引/存储实体、关系、社区报告 chunksRetrieval`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 APIJina / DashScope / Xinference。Rerank 失败时**降级**到原始结果(不阻断流程)。 |
---
## 9. PromptPrompt 组装层)
| 维度 | 定义 |
|------|------|
| **上游** | Reranking接收排序后的 chunksWorkflow接收用户 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 的适配。 |