RAGFlow 分块策略全景与 Book 策略深度解析
2026/6/9 16:39:14 网站建设 项目流程

一、RAGFlow 分块策略概览

RAGFlow 一共有15 种分块策略,定义在common/constants.pyParserType枚举中,通过rag/svr/task_executor.pyFACTORY字典分发到各自的实现模块。

整体架构

┌─────────────────────────────────────────────────────────────────┐ │ 用户上传文档 │ │ │ │ │ parser_id 选择 │ │ │ │ │ ┌───────────┼───────────┐ │ │ ▼ ▼ ▼ │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ naive │ │ paper │ │ book │ ...共15种 │ │ │(通用) │ │(论文) │ │(书籍) │ │ │ └───┬────┘ └────────┘ └────────┘ │ │ │ │ │ ┌─────┼──────────┐ (naive 的二级分发) │ │ ▼ ▼ ▼ │ │ deepdoc mineru docling ... (PDF解析引擎) │ └─────────────────────────────────────────────────────────────────┘

15 种策略一览

#策略实现文件适用文件类型核心思路
1naive(通用)rag/app/naive.pydocx, pdf, excel, txt, md, html, json 等用分隔符切分文本,再按 token 数上限合并。支持 overlap、子分隔符、嵌入文件提取。默认策略
2manual(手册)rag/app/manual.pypdf, docx针对 FAQ 型手册,识别层级标题结构,构建问答树
3qa(问答)rag/app/qa.pyxlsx, csv, txt, pdf, docx提取问答对。Excel 第一列=问题,第二列=答案;PDF/Docx 用编号模式匹配
4table(表格)rag/app/table.pyxlsx, xls, txt, csv每行一个 chunk,支持列头的语义扩展(同义词、枚举值)
5paper(论文)rag/app/paper.pypdf检测双栏布局,识别摘要/关键词,确保摘要完整保留
6book(书籍)rag/app/book.pydocx, pdf, txt, html层级合并,检测冒号标题,去除目录页,适合长文档
7laws(法律)rag/app/laws.pydocx, pdf, txt识别条款编号的层级结构(条、款),树形合并保留法律层级
8resume(简历)rag/app/resume.pypdf, docxYOLOv10 布局检测 + LLM 并行提取(基本信息、工作经历、教育)
9picture(图片)rag/app/picture.py图片, 视频OCR 提取文本 + VLM 生成语义描述。每张图/视频一个 chunk
10one(整篇)rag/app/one.pydocx, pdf, xlsx, txt 等整个文档作为一个 chunk,不切分
11audio(音频)rag/app/audio.pywav, mp3, aac 等语音转文字(ASR),转写结果作为一个 chunk
12email(邮件)rag/app/email.pyeml解析邮件头和正文,递归处理附件
13tag(标签)rag/app/tag.pyxlsx, csv, txt两列格式:内容 + 标签,用于构建标签知识库
14presentation(演示)rag/app/presentation.pypdf, pptx每张幻灯片一个 chunk,按位置排序文本/表格/图片
15knowledge_graph委托给 naive同 naive实际的图谱抽取是后处理阶段(graphrag任务类型)

数据流全貌

文档上传 │ ▼ Redis 队列 (te.0.common / te.1.common) │ ▼ Worker 取任务 (collect) │ ▼ FACTORY[parser_id].chunk() ──→ 得到 chunk 列表 │ ▼ 后处理增强: ├─ 自动关键词 (LLM生成) ├─ 自动问题 (LLM生成) ├─ 元数据提取 (LLM生成) └─ 标签匹配 (tag知识库) │ ▼ Embedding 向量化 │ ▼ 写入 ES / Infinity (insert_chunks) │ ▼ 更新文档统计 (chunk数, token消耗)

几个有意思的设计点

  1. naive 是万能底座knowledge_graph直接复用 naive,email内部也调用naive_chunk()处理附件
  2. 二级分发— naive 内部还有PARSERS字典,根据layout_recognizer配置选择 PDF 解析引擎(deepdoc / mineru / docling / paddleocr 等)
  3. 领域特化程度不同lawspaper是结构化很强的领域策略;naive则是通用瑞士军刀;one几乎不做什么

二、Book 策略完整机制解析

第一步:解析文档,获取 sections

Book 支持多种文件格式,每种格式的解析路径不同:

┌─────────────────────────────────────────────────────────────────────┐ │ 文档输入 │ │ │ │ .docx ──→ naive.Docx() ──→ [(text, image, html), ...] │ │ │ │ .pdf ──→ PARSERS[layout_recognizer] ──→ (sections, tables) │ │ 支持: deepdoc / mineru / docling / paddleocr 等 │ │ │ │ .txt ──→ 按行切分 ──→ [(line, ""), ...] │ │ │ │ .html ──→ HtmlParser() ──→ [(line, ""), ...] │ │ │ │ .doc ──→ tika 解析 ──→ [(line, ""), ...] │ └─────────────────────────────────────────────────────────────────────┘

每个 section 是一个(text, layout_tag)元组。对于 PDF,layout_tag可能是"title""text"等(由布局分析引擎输出)。

第二步:预处理 — 冒号标题提升

make_colon_as_title(sections)# book.py:163

遍历所有 section,如果一行文本以:结尾,且冒号后面有足够多的内容(≥32 字符),就把冒号前面的部分插入为一个"title"类型的 section。

例子:

之前: [("绪论:本文主要研究...", "text")] 之后: [("绪论", "title"), ("本文主要研究...", "text")]

第三步:检测编号模式

bull=bullets_category([tfort,_insections])# book.py:164

bullets_category把所有 section 的文本拿去匹配 5 种编号模式组:

模式组 0 (中式法律): 第一编/第一章/第一节/第一条/(一) 模式组 1 (阿拉伯): 第1章/第1节/1./1.1/1.1.1/1.1.1.1 模式组 2 (混合): 第一章/第一节/一、/(一)/(1) 模式组 3 (英文): PART ONE/Chapter I/Section 1/Article 1 模式组 4 (Markdown): #/##/###/####/##### /######

返回命中数最多的模式组索引(0~4),如果都没有命中返回-1

第四步:分块 — 两条路径

sections │ make_colon_as_title() ← 冒号行提升为标题 │ bullets_category() ← 检测编号模式 │ ┌───────┴───────┐ ▼ ▼ bull >= 0 bull < 0 (有编号模式) (无编号模式) │ │ hierarchical_merge() naive_merge() (层级树形合并) (按 token 数顺序合并)
路径 A:有编号模式 → hierarchical_merge

depth=5硬编码,核心算法分为两步:层级构建二次合并

层级构建:从叶节点向上找爹

算法首先把每个 section 按匹配到的编号正则分组:

假设文档内容,检测到模式组 1(阿拉伯编号): BULLET_PATTERN[1] = ["第N章", "第N节", "N.", "N.N", "N.N.N", "N.N.N.N"] 输入 sections: ┌───┬──────────────────────┬───────┐ │ i │ text │ level │ ← 匹配到的 BULLET_PATTERN 索引 ├───┼──────────────────────┼───────┤ │ 0 │ "第1章 绪论" │ 0 │ ← "第N章" = pattern[0] │ 1 │ "1.1 研究背景" │ 2 │ ← "N." = pattern[2] │ 2 │ "背景详细内容..." │ 7 │ ← 正文(无匹配) │ 3 │ "1.2 研究目标" │ 2 │ │ 4 │ "目标详细内容..." │ 7 │ │ 5 │ "第2章 方法" │ 0 │ ← 新章 │ 6 │ "2.1 实验设计" │ 2 │ │ 7 │ "实验内容..." │ 7 │ └───┴──────────────────────┴───────┘ levels 数组(按 level 分组索引): Level 0 ("第N章"): [0, 5] Level 1 ("第N节"): [] Level 2 ("N."): [1, 3, 6] Level 3~5: [] Level 6 (title布局): [] Level 7 (正文): [2, 4, 7]

然后levels = levels[::-1]反转整个数组,从最底层(正文)开始遍历:

反转后: [0] = Level 7 (正文): [2, 4, 7] ← 最底层 [1] = Level 6 (title布局): [] [2] = Level 5 (N.N.N.N): [] [3] = Level 4 (N.N.N): [] [4] = Level 3 (N.N): [] [5] = Level 2 (N.): [1, 3, 6] [6] = Level 1 (第N节): [] [7] = Level 0 (第N章): [0, 5] ← 最顶层

算法从每个叶节点(正文段落)出发,通过二分搜索在上级 levels 数组中找到最近的祖先标题,构建层级链:

j=2 (section "背景内容...") → 从 Level 2 找到 1.1 (index=1) → 从 Level 0 找到 第1章 (index=0) → 链: [第1章 绪论, 1.1 研究背景, 背景内容...] j=4 (section "目标内容...") → 从 Level 2 找到 1.2 (index=3) → 从 Level 0 找到 第1章 (index=0) → 链: [第1章 绪论, 1.2 研究目标, 目标内容...] j=7 (section "实验内容...") → 从 Level 2 找到 2.1 (index=6) → 从 Level 0 找到 第2章 (index=5) → 链: [第2章 方法, 2.1 实验设计, 实验内容...]
二次合并:token 上限 218

构建完层级链后,还有一个二次合并步骤。如果单条链(通常是纯正文段落)的 token 数 < 218,会被拼到前一个 chunk 里,可能跨越标题边界。

路径 B:无编号模式 → naive_merge

退化为顺序拼接,不考虑任何标题结构,纯粹按chunk_token_num配置的 token 数切分。


三、Book 策略中"标题"的真实角色

核心结论:标题是上下文,不是边界

Book 策略确实检测标题、使用标题,但标题在其中的角色是补充上下文,不是切分边界

理想中的"按标题分块" ┌─ 第1章 绪论 ──────────┐ ← 在这里切开 │ 1.1 背景 │ │ 背景内容... │ │ 1.2 目标 │ │ 目标内容... │ └────────────────────────┘ ← 在这里切开 ┌─ 第2章 方法 ──────────┐ │ 2.1 实验设计 │ │ 实验内容... │ └────────────────────────┘ Book 实际的分块 ┌─ [第1章 绪论 · 1.1 研究背景 · 背景内容...] ──┐ ← 以叶节点为单位 └───────────────────────────────────────────────┘ ┌─ [第1章 绪论 · 1.2 研究目标 · 目标内容...] ──┐ ← 同一章被拆成多个 chunk └───────────────────────────────────────────────┘ ┌─ [第2章 方法 · 2.1 实验设计 · 实验内容...] ──┐ └───────────────────────────────────────────────┘
维度按标题分块Book 实际行为
分块单位一级标题下的所有内容每个叶节点段落
标题的角色切分锚点(边界)附加上下文(前缀)
同一章的内容在同一个 chunk 里被拆成多个 chunk
chunk 粒度粗(章级别)细(段落级别)

Book 的hierarchical_merge做的是:给每个正文段落挂上它的祖先标题链作为上下文,但切分点不在标题处,而在每个正文段落处。


四、Book 策略 vs 直接按段落切分的本质差异

具体对比

假设一份文档:

第1章 绪论 1.1 研究背景 深度学习在自然语言处理领域取得了显著进展。 1.2 研究目标 本文旨在提出一种新的注意力机制。 第2章 相关工作 2.1 Transformer架构 Vaswani等人提出的Transformer架构改变了NLP的范式。 2.2 预训练模型 BERT通过双向编码器实现了突破性效果。
直接按段落切(naive 的做法)
Chunk #内容
1深度学习在自然语言处理领域取得了显著进展。
2本文旨在提出一种新的注意力机制。
3Vaswani等人提出的Transformer架构改变了NLP的范式。
4BERT通过双向编码器实现了突破性效果。
Book 的做法(段落 + 祖先标题链)
Chunk #内容
1第1章 绪论 · 1.1 研究背景· 深度学习在自然语言处理领域取得了显著进展。
2第1章 绪论 · 1.2 研究目标· 本文旨在提出一种新的注意力机制。
3第2章 相关工作 · 2.1 Transformer架构· Vaswani等人提出的Transformer架构改变了NLP的范式。
4第2章 相关工作 · 2.2 预训练模型· BERT通过双向编码器实现了突破性效果。

差异体现在 RAG 检索环节

RAG 的流程是:用户提问 →检索相关 chunk→ 喂给 LLM 生成回答。差异就在检索环节。

场景 1:用户问 “绪论部分的研究背景是什么?”

直接按段落切— 检索命中的 chunk:

❌ "深度学习在自然语言处理领域取得了显著进展。"

这个 chunk 里**没有"绪论"、没有"研究背景"**这些关键词。向量检索和全文检索都会困难——因为"深度学习"、"自然语言处理"跟用户问题的语义距离很远。

Book 的做法— 检索命中的 chunk:

✅ "第1章 绪论 · 1.1 研究背景 · 深度学习在自然语言处理领域取得了显著进展。"

这个 chunk 里包含"绪论"、“研究背景”,跟用户问题高度匹配。检索命中率大幅提升。

场景 2:用户问 “Transformer 相关的工作在哪一章?”

直接按段落切

❌ "Vaswani等人提出的Transformer架构改变了NLP的范式。"

没有章节信息,LLM 拿到这个 chunk 后不知道它属于哪一章,无法回答"在哪一章"。

Book 的做法

✅ "第2章 相关工作 · 2.1 Transformer架构 · Vaswani等人提出的..."

LLM 能看到 “第2章 相关工作”,能直接回答

总结

┌─────────────────────────────────────────────────────┐ │ │ │ 直接按段落切:每个 chunk 只有 "WHAT"(内容) │ │ │ │ Book 策略: 每个 chunk 有 "WHERE" + "WHAT" │ │ (位置上下文 + 内容) │ │ │ │ 标题链的作用:给每个段落 chunk 带上它所在的 │ │ "章节路径",解决检索时 "这段话属于哪、 │ │ 在什么上下文中" 的问题 │ │ │ └─────────────────────────────────────────────────────┘

Book 策略的核心价值不是"怎么切",而是"切完之后每个 chunk 携带什么上下文"。它把层级标题作为前缀注入每个 chunk,提升检索命中率。


五、Paper 策略与 Book 策略的对比

Paper 策略同样利用标题信息,但机制不同:

维度PaperBook
标题检测依赖 PDF 布局分析(layoutno含 “title”)+BULLET_PATTERN同左 + 额外的make_colon_as_title(冒号行提升为标题)
分块依据"出现频率最高的标题级别"作为切分锚点完整的层级树构建,自底向上合并
层级深度扁平——只看 most_level 这一层depth=5,最多支持 5 级嵌套
无标题退化不退化,强制用title_frequency退化到naive_merge(纯按 token 数)
特殊处理摘要独占 chunk;双栏布局检测目录页移除(remove_contents_table

六、关键源码索引

模块文件路径
Book 策略入口rag/app/book.py
Paper 策略入口rag/app/paper.py
Laws 策略入口rag/app/laws.py
编号模式定义BULLET_PATTERNrag/nlp/__init__.py:169-201
编号模式检测bullets_categoryrag/nlp/__init__.py:216-233
层级合并hierarchical_mergerag/nlp/__init__.py:980-1067
树形合并tree_mergerag/nlp/__init__.py:931-978
标题频率title_frequencyrag/nlp/__init__.py:901-920
冒号标题提升make_colon_as_titlerag/nlp/__init__.py:879-898
顺序合并naive_mergerag/nlp/__init__.py:1070-1126
策略枚举ParserTypecommon/constants.py:106-122
工厂分发FACTORYrag/svr/task_executor.py:114-131

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询