3. 数据加载
- 当前主流 RAG 文档加载器:
| 工具名称 | 特点 | 适用场景 | 性能表现 |
|---|---|---|---|
| PyMuPDF4LLM | PDF → Markdown 转换,OCR + 表格识别 | 科研文献、技术手册 | 开源免费,GPU 加速 |
| TextLoader | 基础文本文件加载 | 纯文本处理 | 轻量高效 |
| DirectoryLoader | 批量目录文件处理 | 混合格式文档库 | 支持多格式扩展 |
| Unstructured | 多格式文档解析 | PDF、Word、HTML 等 | 统一接口,智能解析 |
| FireCrawlLoader | 网页内容抓取 | 在线文档、新闻 | 实时内容获取 |
| LlamaParse | 深度PDF结构解析 | 法律合同、学术论文 | 解析精度高,商业 API |
| Docling | 模块化企业级解析 | 企业合同、报告 | IBM 生态兼容 |
| Marker | PDF→Markdown,GPU加速 | 科研文献、书籍 | 专注 PDF 转换 |
| MinerU | 多模态集成解析 | 学术文献、财务报表 | 集成 LayoutLMv3+YOLOv8 |
4. 文本分块
文本分块(Text Chunking)是构建 RAG 流程的关键步骤,将长篇文档切分成更小、更易于处理的单元,作为后续向量检索和模型处理的基本单位。
4.1 文本分块重要性
4.1.1 满足模型上下文限制
- 嵌入模型: 有严格的输入长度上限(如
bge-base-zh-v1.5为512个token),超出限制会被截断,导致信息丢失。 - 大语言模型: 虽然上下文窗口较大,但检索到的所有文本块、用户问题和提示词都必须能放入窗口中。块过大会限制可参考的信息广度。
4.1.2 为何"块"不是越大越好
块的大小并非越大越好,过大的块会严重影响RAG系统的性能:
- 嵌入过程中的信息损失: 嵌入模型通过池化将所有token向量压缩成单一向量。文本块越长,语义信息越稀释,检索精度下降。
- 生成过程的"大海捞针" (Lost in the Middle): LLM处理长上下文时倾向于记住开头和结尾,忽略中间部分。大块文本会让关键信息被淹没。
- 主题稀释导致检索失败: 好的文本块应聚焦单一主题。包含多个不相关主题的块会导致语义稀释,检索时无法精确匹配。
4.2 基础分块策略
4.2.1 固定大小分块
最简单直接的分块方法,CharacterTextSplitter 的工作原理:
- 按段落分割:使用默认分隔符
"\n\n"按段落分割 - 智能合并:监控累积长度,超过
chunk_size时形成新块,通过chunk_overlap保持上下文连续性
特点:优先保持段落完整性,实际是"段落感知的自适应分块"。
from langchain.text_splitter import CharacterTextSplitter
from langchain_community.document_loaders import TextLoader
loader = TextLoader("../../data/C2/txt/蜂医.txt")
docs = loader.load()
text_splitter = CharacterTextSplitter(
chunk_size=200, # 每个块的目标大小
chunk_overlap=10 # 块之间重叠字符数
)
chunks = text_splitter.split_documents(docs)
优势:实现简单、处理速度快、计算开销小
劣势:可能在语义边界处切断文本
4.2.2 递归字符分块
RecursiveCharacterTextSplitter 通过分隔符层级递归处理,改善超长文本的处理效果。
算法流程:
- 寻找有效分隔符:从分隔符列表中找到第一个存在的分隔符
- 切分与分类:使用分隔符切分文本
- 片段不超过块大小 → 暂存准备合并
- 片段超过块大小 → 先合并已暂存片段,再递归分割或保留为超长块
- 最终处理:合并剩余暂存片段
关键差异:固定大小分块遇到超长段落只能警告并保留;递归分块会继续使用更细粒度分隔符(段落→句子→单词→字符)直到满足大小要求。
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
separators=["\n\n", "\n", "。", ",", " ", ""], # 分隔符优先级
chunk_size=200,
chunk_overlap=10,
)
# 多语言支持(中文、日文、泰文)
separators=["\n\n", "\n", " ", ".", ",", "\u200b", "\uff0c", "\u3001", "\uff0e", "\u3002", ""]
# 编程语言特化支持
from langchain.text_splitter import Language
splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON, # 支持Python、Java、C++等
chunk_size=500,
chunk_overlap=50
)
4.2.3 语义分块
语义分块(Semantic Chunking)不依赖固定字符数或预设分隔符,而是在语义主题发生显著变化的地方进行切分,使每个分块具有高度的内部语义一致性。
实现原理(SemanticChunker):
- 句子分割:将文本拆分成句子列表
- 上下文感知嵌入:通过
buffer_size参数,将每个句子与前后句子组合后进行嵌入,融入上下文语义 - 计算语义距离:计算相邻句子的嵌入向量余弦距离,量化语义差异
- 识别断点:根据统计方法(默认
percentile)确定动态阈值,识别语义断点 - 合并成块:根据断点位置切分并合并句子
断点识别方法:
percentile(百分位法,默认):第95百分位作为阈值standard_deviation(标准差法):平均值 + 3倍标准差interquartile(四分位距法):Q3 + 1.5倍IQRgradient(梯度法):计算差异值变化率,适合法律、医疗文档
from langchain_experimental.text_splitter import SemanticChunker
from langchain_community.embeddings import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh-v1.5",
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True}
)
text_splitter = SemanticChunker(
embeddings,
breakpoint_threshold_type="percentile"
)
4.2.4 基于文档结构的分块
对于具有明确结构标记的文档格式(如Markdown、HTML、LaTex),可利用这些标记实现更智能的分割。
Markdown 结构分块(MarkdownHeaderTextSplitter):
-
实现原理:先按标题分组,再按需细分
- 定义标题层级映射:
[ ("#", "Header 1"), ("##", "Header 2") ] - 内容聚合:将每个标题下的内容聚合,并赋予包含完整标题路径的元数据
- 定义标题层级映射:
-
元数据注入优势:为每个块提供精确"地址",增强上下文准确性
-
组合使用:可与
RecursiveCharacterTextSplitter组合- 先用
MarkdownHeaderTextSplitter按标题分割成带元数据的逻辑块 - 再对逻辑块应用
RecursiveCharacterTextSplitter切分为符合大小要求的小块 - 小块会继承标题元数据
- 先用
优势:既保留文档宏观逻辑结构,又确保块大小适中
4.3 其他开源框架中的分块策略
4.3.1 Unstructured:基于文档元素的智能分块
- 分区 (Partitioning):将文档解析成结构化元素(
Title、NarrativeText、ListItem等) - 分块方法:
basic:连续组合元素直到达到max_characters上限by_title:在basic基础上,将Title元素视为新章节开始,强制在此处切分
优势:"先理解、后分割"策略,最大程度保留文档原始语义结构
4.3.2 LlamaIndex:面向节点的解析与转换
将数据处理抽象为对"节点(Node)"的操作,分块是节点转换的一环。
节点解析器类型:
- 结构感知型:
MarkdownNodeParser、JSONNodeParser、CodeSplitter等 - 语义感知型:
SemanticSplitterNodeParser:类似 LangChain 的SemanticChunkerSentenceWindowNodeParser:将文档切分成单个句子,在元数据中存储前后N个句子作为"窗口"
- 常规型:
TokenTextSplitter、SentenceSplitter等
特点:灵活的转换流水线、丰富的元数据、良好的互操作性(LangchainNodeParser)
4.3.3 ChunkViz:可视化分块工具
可视化工具,用不同颜色块展示每个 chunk 的边界和重叠部分,方便理解分块逻辑。

评论(没有评论)