跳到主要内容

文档处理与分块策略

问题

RAG 中如何进行文档解析和分块?有哪些分块策略?分块大小如何选择?

答案

文档处理是 RAG 的第一步也是最关键的一步——分块质量直接决定检索质量。

一、文档解析

不同格式的文档需要不同的解析工具:

格式解析工具注意事项
PDFPyPDF2、pdfplumber、Unstructured扫描件需 OCR
Wordpython-docx、Unstructured注意表格和图片
Markdown直接按标题分割保留层级结构
HTMLBeautifulSoup、Unstructured去除导航/广告噪声
代码按函数/类/文件分块保留 import 上下文
表格转为自然语言或 Markdown 表格列-值对比纯文本更有效

二、分块策略

1. 固定大小分块(Fixed Size)

from langchain.text_splitter import CharacterTextSplitter

splitter = CharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separator="\n"
)
  • 最简单,按固定字符/Token 数切割
  • 可能在句子中间断开,破坏语义

2. 递归分块(Recursive)

from langchain.text_splitter import RecursiveCharacterTextSplitter

# 按优先级尝试不同分隔符
splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=50,
separators=["\n\n", "\n", "。", ";", ",", " ", ""]
)
  • 最常用的策略——先尝试段落分割,段落太大再按句子,依次递减
  • 较好地保留语义完整性

3. 语义分块(Semantic)

from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import OpenAIEmbeddings

# 基于 Embedding 相似度判断分割点
splitter = SemanticChunker(
OpenAIEmbeddings(),
breakpoint_threshold_type="percentile", # 相似度突变处分开
)
  • 用 Embedding 计算相邻句子的语义相似度,在语义突变处分割
  • 质量最高,但成本也最高(需要调用 Embedding API)

4. 按文档结构分块

from langchain.text_splitter import MarkdownHeaderTextSplitter

# 按 Markdown 标题层级分块
splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=[
("#", "h1"),
("##", "h2"),
("###", "h3"),
]
)
  • 适用于结构化文档(Markdown、HTML、代码)
  • 天然保留文档结构和上下文

三、分块大小选择

分块大小优点缺点适用场景
小块(128-256 Token)检索精确上下文不足事实性问答
中块(256-512 Token)平衡精度和上下文通用默认选择大多数场景
大块(512-1024 Token)上下文丰富可能引入噪声摘要、分析
分块大小与 Embedding 模型匹配

不同 Embedding 模型有最佳输入长度。例如 text-embedding-3-small 最大支持 8191 Token,但实际在 256-512 Token 效果最好。过长的输入会稀释语义。

四、分块优化技巧

重叠(Overlap)

块 1: [A B C D E F G H]
块 2: [F G H I J K L M] ← 重叠部分保证跨块信息不丢失
  • 一般设置 chunk_overlap = chunk_size × 10%-20%

元数据附加

# 为每个块附加元数据,提升检索和引用能力
for chunk in chunks:
chunk.metadata.update({
"source": "产品手册v3.2",
"page": 15,
"section": "退款政策",
"created_at": "2024-01-15"
})

Parent-Child 策略

  • 检索时用小块(精准匹配),生成时返回大块(上下文丰富)
  • LlamaIndex 的 SentenceWindowNodeParser 实现了这个策略

常见面试问题

Q1: 表格数据如何分块?

答案

  1. 转为自然语言:将每行转为 "产品A的价格是199元,库存100件"
  2. 保持表格格式:用 Markdown 表格格式保留结构
  3. 列-值对:每行拆为独立块,并附加表头作为上下文

Q2: 如何处理跨页/跨段落的信息?

答案

  1. Overlap:相邻块重叠 50-100 Token
  2. Parent-Child:小块检索,大块返回
  3. 前置上下文:每个块前面附加章节标题

Q3: 分块太大或太小分别会导致什么问题?

答案

  • 太小:上下文不足,LLM 无法理解完整语义,导致回答片面
  • 太大:包含无关信息(噪声),稀释关键内容,且 Embedding 质量下降

相关链接