业界常用的五种 RAG 分块策略核心思想、LlamaIndex 代码演示以及 RAGFlow/Dify 等框架实践思路。
1.RAG 与分块的重要性
在正式开始前,老规矩温故知新,先来复习下传统 RAG 出现的背景、典型 RAG 流程以及分块的重要意义所在。
*1.1.典型 RAG 流程*
为了让大模型能够回答私有知识的问题,抛开高成本的 LLM 微调方法外,我们可以选择在提问时,直接传入私有知识相关的参考信息,这种方法更加简便且高效。
然而,这种方法的缺点很明显。毕竟提示词长度有限,当私有数据量过大时,传入所有背景信息可能导致提示词过长,从而影响模型的处理效率或达到长度上限。
而 RAG 巧妙地将 LLM 的生成能力与外部知识库的信息检索能力结合起来:
接收问题 (Query): 用户向系统提出查询。
信息检索 (Retrieval): 系统在向量数据库或搜索引擎中查找与问题相关的文档片段。
上下文增强 (Augmentation): 将检索到的信息片段整合进发送给 LLM 的提示 (Prompt) 中。
答案生成 (Generation): LLM 基于原始问题和增强的上下文生成最终回答。
在这个流程中,要实现高质量的检索,需要对原始知识文档进行有效的预处理,这也就引出了 RAG 流程中一个至关重要的准备工作——文档分块 (Chunking)。
*1.2.为啥分块这么重要*
分块,简单来说就是将原始文档按照某种策略分割成更小的、语义相对完整、适合进行索引和检索的文本单元(Chunks)的过程。 这一步通常在文档被送入向量数据库进行 Embedding(向量化)之前完成。分块策略选择和执行质量,是构建一个 RAG 应用的准确性基础。结合以下三种情形,会更好理解些:
分块过大: 可能导致检索到的单个块包含过多无关信息(噪音),增加了 LLM 理解上下文的难度,降低了答案的精确性,甚至可能超出 LLM 的上下文窗口限制。
分块过小或切分不当: 可能破坏原文的语义连贯性,导致一个完整的知识点被拆散到多个块中。检索时可能只召回了部分信息,使得 LLM 无法获得完整的背景,难以生成全面、准确的答案。
未能适应文档结构: 不同的文档类型(如论文、手册、报告、网页)具有不同的结构特点。死板的分块方式可能无法有效利用标题、列表、表格等结构信息,影响信息提取的完整性。
2.五种分块策略详解
*2.1.固定大小分块*
核心思想
这是最直观、最简单的分块方式。按照预先设定的固定长度( 最大 token 数)将文本进行切割。为了尽量减少信息损失,通常会在相邻的块之间保留一部分重叠内容(Overlap)。
优点:
实现简单,处理速度快。
块大小统一,便于批量处理和管理,能精确控制输入 LLM 的 token 数量。
缺点:
容易在句子或语义完整的表达中间被“拦腰斩断”,破坏文本的语义连贯性。
可能将关联紧密的关键信息分散到不同的块中,影响后续检索和理解的完整性。
适用场景:
处理结构简单、对语义连贯性要求不高的文本。
需要快速实现或作为基线对比策略时。
对块大小有严格限制的应用。
*2.2.语义分块*
核心思想
尝试根据文本的语义含义进行切分,将语义关联紧密的句子或段落聚合在一起。通常做法是先将文本分成基础单元(如句子),然后计算相邻单元的语义相似度(例如通过嵌入向量的余弦相似度),如果相似度高于某个阈值,则合并这些单元,直到相似度显著下降时才创建一个新的块。
优点
能更好地保持文本的语义连贯性和上下文的完整性。
生成的块通常包含更集中的信息,有助于提升检索精度。
为 LLM 提供更高质量的上下文,有助于生成更连贯、相关的回答。
缺点
实现相对复杂,依赖于嵌入模型的质量和相似度阈值的设定。
阈值可能需要根据不同的文档类型进行调整和优化。
计算成本通常高于固定大小分块。
适用场景
对上下文理解和语义连贯性要求较高的场景,如问答系统、聊天机器人、文档摘要等。
处理叙事性或论述性较强的长文本。
*2.3.递归分块*
核心思想:
采用“分而治之”的策略。首先尝试使用一组优先级较高的、较大的文本分隔符(如段落、章节标记)来分割文本。然后,检查分割出的每个块的大小。如果某个块仍然超过预设的大小限制,就换用下一组优先级更低、更细粒度的分隔符(如句子结束符、换行符)对其进行再次分割,此过程递归进行,直到所有块都满足大小要求。
优点:
在保持一定语义结构的同时,能灵活地控制块的大小。
比固定大小分块更能尊重原文的自然结构。
适应性较好,是一种常用的通用分块策略。
缺点:
实现比固定大小分块更复杂一些。
需要预先定义好一组有效的分隔符及其优先级顺序。
注:两个段落(紫色)被识别为初始块,接着第一个段落再被拆成更小的块。这种方式既保留了语义完整性,又能灵活控制分块大小。
适用场景:
适用于大多数类型的文档,特别是那些具有一定层次结构(如章节、段落、列表)但又不完全规整的文档。
是许多 RAG 框架(如 LangChain)中推荐的默认策略之一。
*2.4.基于文档结构的分块*
核心思想:
直接利用文档本身固有的、明确的结构元素(如标题层级、章节、列表项、表格、代码块、Markdown 标记等)来定义块的边界。目标是使每个块尽可能对应文档中的一个逻辑组成部分。
优点:
能最大程度地保留文档的原始逻辑结构和上下文信息。
块的划分方式自然,符合人类的阅读和理解习惯。
缺点:
强依赖于文档本身具有清晰、一致的结构,这在现实世界的文档中并非总是得到满足。
生成的块大小可能差异巨大,某些块可能非常长,超出 LLM 的处理限制。
通常需要结合递归分块等方法来处理过大的块。
适用场景:
特别适合处理结构化或半结构化特征明显的文档,如技术手册、法律合同、API 文档、教程、带有章节的书籍、格式良好的 Markdown 文件等。
注:某些结构下的分块长度差异较大,可能会超出模型支持的 token 限制。可以考虑结合递归切分法来处理。
*2.5.基于 LLM 的分块*
核心思想: 不再依赖固定的规则或启发式方法,而是利用大型语言模型 (LLM) 自身的理解能力来判断文本的最佳分割点。可以通过设计合适的提示 (Prompt),让 LLM 将文本分割成语义上内聚且与其他部分相对独立的块。
优点:
理论上具有最高的潜力,能实现最符合语义逻辑的分割效果,因为 LLM 能更深入地理解文本内容、上下文和细微差别。
缺点:
计算成本最高昂,处理速度最慢,因为涉及到多次调用 LLM。
需要精心设计有效的 Prompt 来指导 LLM 完成分块任务。
同样受到 LLM 本身上下文窗口大小的限制。
适用场景:
对分块质量有极致要求,并且能够承担高昂计算成本和较慢处理速度的场景。
用于处理语义关系特别复杂、传统方法难以处理的文本。
也可能作为更复杂策略(如生成摘要树、构建知识图谱)的一部分。
3.LlamaIndex 分块策略演示
为了更好的理解五种不同的分块策略原理和实现细节,下面以 LlamaIndex 为例,展示五种策略对应的示例 python 代码。
在具体介绍前,先补充说明两个问题:LlamaIndex 是什么?以及为什么不选择 RAGFlow/Dify 等框架来进行分块策略的演示?
*3.1.LlamaIndex 扫盲介绍*
LlamaIndex 也是一个非常流行的开源数据框架,与 Ragflow 不同,LlamaIndex 更像是一个灵活的工具箱或库,提供了丰富、模块化的组件来处理 RAG 流程中的各个阶段,特别是数据加载、转换(包括分块/节点解析)、索引和查询。
*主要组件特点*
数据连接器 (Data Connectors): 支持从各种来源(文件、API、数据库等)加载数据。
数据索引 (Data Indexes): 提供多种索引结构(如向量存储索引、列表索引、关键词表索引、树状索引、知识图谱索引等)来组织数据,以适应不同的查询需求。
节点解析/文本分割 (Node Parsing / Text Splitting): 这是 LlamaIndex 处理分块的核心部分。它提供了多种可配置的文本分割器 (Text Splitters),让开发者可以精细地控制文档如何被分割成“节点 (Nodes)”(LlamaIndex 中对“块/Chunk”的称呼)。
检索器 (Retrievers): 基于索引,提供不同的方式来检索与查询相关的节点。
查询引擎 (Query Engines): 结合检索器和 LLM,构建端到端的查询和响应能力。
代理 (Agents): 构建更复杂的、可以自主规划和使用工具的 LLM 应用。
模块化和可扩展性: 开发者可以方便地组合、替换或自定义各个组件。
*演示底层机制的优势*
LlamaIndex 的设计哲学就是提供明确的、可编程的接口。对于分块(节点解析),我们可以直接在代码中:
导入特定的 TextSplitter 类: LlamaIndex 提供了与多种分块策略对应的类。
实例化分割器并配置参数: 显式地设置块大小、重叠大小、分隔符、模型(用于语义分割)、结构解析规则等。
调用分割器的 split_text 或类似方法: 将原始文本输入,直接获得分割后的节点列表。
下文会通过具体的 Python 代码清晰和直接地展示五种分块策略的实现。
*3.2.高集成度的局限*
像 Ragflow、Dify 这样封装度较高的框架,提供的开箱即用的端到端解决方案,必然会通过 UI 或 API 参数将底层的实现细节抽象化。
这虽然方便用户快速搭建应用,但对于希望理解**“引擎盖”**下面发生了什么的用户来说会不够透明,难以窥见不同策略的具体代码实现和细微差别。具体来说:
抽象层级的差异: Ragflow/Dify 等平台为了易用性,会将底层的分块逻辑封装在更高级的选项(如 Ragflow 的 chunk_method 下拉菜单和相关配置)。用户无法直接编写或修改 LlamaIndex 那样的底层分块代码。
平台特定实现: 即便 Ragflow 提供了一个名为 “Paper” 的分块方法,其内部的具体实现逻辑、使用的分隔符、递归策略等细节,与 LlamaIndex 的 MarkdownNodeParser 组合有所不同。
配置而非编码: 在这些平台上,用户更多的是通过图形界面 (UI) 或平台的 Python API 来配置分块选项,而不是直接编写分块算法的代码。
*3.3.LlamaIndex 五种分块策略代码参考*
固定大小分块:
可以使用SentenceSplitter(设置 chunk_size控制token数,chunk_overlap 控制重叠) 或 TokenTextSplitter。代码会清晰展示如何设置大小和重叠。
from llama_index.core.node_parser import SentenceSplitter
splitter = SentenceSplitter(chunk_size=128, chunk_overlap=20)nodes = splitter.get_nodes_from_documents(documents) # 'documents' 是加载后的文档对象# 可以打印 nodes[0].get_content() 查看第一个块的内容
语义分块:
LlamaIndex 提供了 SemanticSplitterNodeParser。需要配置一个嵌入模型,并设定相似度阈值 (breakpoint_percentile_threshold)。
from llama_index.core.node_parser import SemanticSplitterNodeParserfrom llama_index.embeddings.openai import OpenAIEmbedding # 或其他嵌入模型
embed_model = OpenAIEmbedding()splitter = SemanticSplitterNodeParser( buffer_size=1, breakpoint_percentile_threshold=95, embed_model=embed_model)nodes = splitter.get_nodes_from_documents(documents)
递归分块
SentenceSplitter 本身就具有一定递归特性,它会按顺序尝试使用不同的分隔符(默认从 \n\n 到 . 到 等)。可以自定义 paragraph_separator 等参数。更复杂的递归(如构建摘要树)可能涉及 HierarchicalNodeParser。
from llama_index.core.node_parser import SentenceSplitter
# 默认行为就是递归的,可以定制分隔符splitter = SentenceSplitter( separator=" ", # 可以简化分隔符用于演示 chunk_size=256, chunk_overlap=30, paragraph_separator="\n\n\n", # 示例:自定义段落分隔符)nodes = splitter.get_nodes_from_documents(documents)
基于文档结构的分块
LlamaIndex 有专门的 MarkdownNodeParser 或 JSONNodeParser。对于 PDF 中提取的 Markdown,MarkdownNodeParser 能很好地利用标题、列表等结构。
from llama_index.core.node_parser import MarkdownNodeParser
parser = MarkdownNodeParser()nodes = parser.get_nodes_from_documents(documents) # 假设 documents 是加载的 Markdown 内容# 对于从 PDF 解析得到的 Markdown 尤其有效
基于 LLM 的分块
虽然没有一个现成的 LLMTextSplitter,但 LlamaIndex 的灵活性允许我们构建自定义的 NodeParser,在其中调用 LLM 来决定分割点或生成摘要块。例如结合 LLM 进行章节总结或主题划分,或者利用 LLM 对元数据进行分析来指导分割。这部分后续我结合具体案例再做演示。
4.写在最后
*4.1.如何在 Ragflow/Dify 中应用不同分块策略*
上述 LlamaIndex 的演示只是提供了评估的思路和方向,不能替代在目标平台上的实际验证。各位可以利用上述LlamaIndex 演示中的原理,去解读 Ragflow/Dify等框架提供的分块选项。
以RAGFlow为例,相关分块选项和上述的五种分块策略很难一一映射,结合官方的python api解读参考如下:
固定大小分块: Ragflow 的 “naive” 方法最接近这个概念,尤其是当配置了 chunk_token_num 时。它可能也结合了 delimiter 进行分割。
语义分块: API 文档中没有直接命名为 “semantic” 的选项。然而,某些高级方法(像 “qa”、“knowledge_graph” 某种程度上)可能隐含了语义理解。但 API 没有提供一个像 LangChain 那样明确的 Semantic Splitter 选项。
递归分块: 像 “book” 或 “paper” 这样的方法内部猜测是采用了递归或基于结构的分块逻辑,会先尝试按大纲(章节、标题)分割,如果块太大再按段落或句子递归分割。但API 文档没有明确说明其内部递归逻辑。
基于文档结构的分块: “paper”, “book”, “laws”, “presentation”, “table” 这些方法明显是针对特定文档结构的,它们会优先利用文档的固有结构(标题、章节、表格结构、幻灯片等)来定义块边界。
基于 LLM 的分块:API 中没有通用的、直接让 LLM 决定分块边界的选项。
这里需要特别说明的是,在RAGFlow中创建知识库环节,自动关键词/问题提取不是LLM-based Chunking,而是分块后的 LLM 增强。但RAPTOR(递归摘要树,多粒度检索) 策略涉及对初始块进行聚类,并使用 LLM 对聚类进行摘要,生成新的、更高层次的“摘要块”。 这个策略可以被认为是“基于 LLM 的分块”的一种高级形式或应用。虽然它可能建立在初始分块之上,但它确实利用 LLM 生成了新的、语义层级更高的块(摘要),这些新块是文档内容的一种 LLM 驱动的重新组织和分割。它不仅仅是分析现有块,而是创造了新的块边界和内容。
*4.2.成熟框架的分块策略定制问题*
如果你想实现的功能(例如一种非常特定的、Ragflow 没有内置或通过 API 参数暴露的分块方法,或者你想彻底改变其检索逻辑)超出了 Ragflow 提供的 API 和配置选项的范畴,理论上唯一的途径就是修改 Ragflow 的源代码。
但像 Ragflow 这样的框架通常有复杂的内部结构和依赖关系,理解并安全地修改其核心代码需要投入大量时间和精力。而且鉴于 RAGFlow 在常态化更新中,创建一个 Ragflow 的“定制分支”意味着官方的更新、补丁或新功能无法直接合并,需要自己手动同步或重新应用你的修改,维护成本很高。
类似Dify 支持编写插件来添加自定义功能,而无需修改核心代码。RAGFlow 等类似框架后续预期都会陆续支持更加灵活的扩展机制,建议短期内不要在二开上耗费精力。
*4.3.使用 LlamaIndex 替代 Ragflow/Dify?*
这是我近期被问到比较多的一个问题,我在实施或咨询的一些项目中,部分企业选择直接基于 LlamaIndex(或 LangChain 等类似库)来构建自己的企业级 RAG 应用,而不是使用封装好的平台。
除了可以更好的与现有技术栈集成外,企业可以完全掌控 RAG 流程的每一个环节,选择最适合需求的模型(嵌入、LLM、重排)、向量数据库、索引策略、检索逻辑等,并进行深度定制和优化。
但问题也随着而来,这需要开发或集成几乎所有“外围”组件,包括 UI、API、数据库、部署运维在内的所有周边系统。 毕竟LlamaIndex 虽然提供了 RAG 的核心“引擎”和“管道”,但它本身不是一个可以直接部署给最终用户的完整应用。
一般的建议是,针对企业级知识库项目落地,如果需求与某个成熟框架的功能高度匹配,且对定制化要求不高,或者时间紧迫需要快速验证,那么选择 Ragflow/Dify 显然更高效。但如果企业对 RAG 的性能、逻辑有深度定制的需求,希望完全掌控技术栈,拥有较强的内部研发能力,或者需要将 RAG 深度嵌入现有复杂系统,那么基于 LlamaIndex 自建通常是更长远、更灵活的选择,尽管前期投入更大。
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。