RAG 的 Chunking 有什么好方案?从原理到实战选型

RAG 的 Chunking 有什么好方案?从原理到实战选型

Reddit 上有一个观点说得很直接:

"Chunking 优化的是 embedding 的便利性,不是文档被使用的方式。"

这句话点出了 RAG 工程中最被低估的问题。大多数开发者花了大量时间调 prompt、换模型、优化 rerank,但 chunking 策略却是拍脑袋定的------固定 512 token,加 50 token overlap,完事。

这是 RAG 质量差的根本原因之一。


一、为什么 Chunking 这么重要?

RAG 的工作流是:

复制代码
文档 → Chunk → Embedding → 向量索引 → 检索 → 填入 LLM

Chunking 是第二步,但它的影响贯穿整条链路:

原因 1:Embedding 模型的压缩是有损的

Embedding 模型把一段文本压缩成一个固定维度的向量(通常 768 维)。一个 chunk 里混杂了多个主题,向量就会"稀释",检索时语义匹配精度下降。

原因 2:结构信息在 Chunk 时被抹掉

合同里的日期、条款编号、当事方、状态字段,往往被"切"到不同 chunk 里。检索时只能靠相似度找到"主题接近"的 chunk,但真正回答问题所需的结构信息已经丢失了。

原因 3:Chunk 质量决定了后续所有优化的上限

Rerank 再好,也只是在候选集里重新排序。候选集本身的质量上限取决于 chunking。


二、七种主流 Chunking 策略对比

Vecta 团队做了一次严谨的基准测试:50 篇学术论文,905,746 tokens,7 种策略,公平对比(控制总上下文量而非 top-k 数量)。

策略 准确率 接地性 适用场景
Recursive 512 69% 81% 通用首选
Fixed 512 67% 85% 要求低幻觉
Fixed 1024 61% 86% 长文档覆盖
Doc-Structure 52% 84% 结构化文档
Semantic 54% 81% 实验性
Proposition 51% 87% 精细引用场景

结论:Recursive 512 赢了,"无聊"的策略反而最稳。

但这不是故事的全部。


三、每种策略详解

策略 1:Recursive Character Splitting(推荐默认)

原理 :按分隔符层级递归切分------先试双换行 \n\n,再试单换行 \n,再试句号,最后才按字符数强切。尽可能在自然边界处切割。

python 复制代码
from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=50,
    separators=["\n\n", "\n", ". ", " ", ""]
)
chunks = splitter.split_text(text)

适合:博客文章、技术文档、研究报告------80% 的 RAG 场景。

局限:不理解语义,可能把相关内容切开;不能处理表格、代码块等特殊结构。


策略 2:Markdown Header-Based Chunking

原理 :按文档的标题层级切分。# 一级标题## 二级标题### 三级标题,保留结构关系。

python 复制代码
from langchain_text_splitters import MarkdownHeaderTextSplitter

headers_to_split_on = [
    ("#", "h1"),
    ("##", "h2"),
    ("###", "h3"),
]
splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
chunks = splitter.split_text(markdown_text)
# 每个 chunk 自动携带 metadata: {"h1": "...", "h2": "..."}

关键优势:每个 chunk 自动携带标题路径作为 metadata,检索时既可以用语义匹配,也可以用结构过滤。

适合:技术文档、API 文档、Wiki、FAQ------结构清晰的 Markdown 文档。


策略 3:Parent-Child Chunking(生产环境推荐)

原理:解决"小块精确 vs 大块完整"的矛盾。

复制代码
父块(512-1024 tokens)← 存入索引,提供完整上下文
  ├── 子块 1(128 tokens)← 用于精确向量检索
  ├── 子块 2(128 tokens)
  └── 子块 3(128 tokens)

检索时用子块,填充 LLM 上下文用父块。

python 复制代码
from llama_index.core.node_parser import HierarchicalNodeParser

parser = HierarchicalNodeParser.from_defaults(
    chunk_sizes=[1024, 512, 128]
)
nodes = parser.get_nodes_from_documents(documents)

效果:在长文档问答场景,答案完整性显著提升,同时保持检索精度。

适合:长文档、合同、报告------需要精确定位又需要完整上下文的场景。


策略 4:Semantic Chunking

原理:不按字符数切,而是按语义相似度切。计算相邻句子的 embedding 相似度,当相似度骤降时,判断为语义边界,在此处切割。

python 复制代码
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings

splitter = SemanticChunker(
    OpenAIEmbeddings(),
    breakpoint_threshold_type="percentile"  # 或 "standard_deviation"
)
chunks = splitter.create_documents([text])

理论上很美,实际有坑

  • 每次切分都要调 embedding API,成本高、速度慢
  • 基准测试里准确率反而低于 Recursive(54% vs 69%)
  • chunk 大小高度不稳定(最小 43 tokens,最大几千 tokens)

结论:适合实验,不建议直接上生产。


策略 5:Proposition Chunking(原子级)

原理:用 LLM 把文档分解成最小的自包含命题单元------每个 chunk 是一个独立的事实陈述。

示例:

yaml 复制代码
原文:"GPT-4 于 2023 年 3 月发布,支持 128K 上下文窗口,定价为每百万 input token $30。"

→ Proposition 1: GPT-4 于 2023 年 3 月发布。
→ Proposition 2: GPT-4 支持 128K 上下文窗口。
→ Proposition 3: GPT-4 定价为每百万 input token $30。

优势:精确引用(page F1 达 0.97),接地性最高(87%)。

代价:每个文档都要跑一遍 LLM,成本极高,索引体积膨胀(平均 17 tokens/chunk,需要 top-115 才能覆盖足够上下文)。

适合:需要精确引用的高价值文档(法律、医疗、合规),而非海量文档的通用场景。


策略 6:Document-Structure-First(结构化文档专用)

核心思想:不要"切文档",而是"理解文档"。

流程

  1. 保留完整文档,不破坏结构
  2. 提取真实段落/章节(而不是按 token 数量切)
  3. 给每个章节附上结构化 metadata
  4. 用语义 + 结构双通道检索
  5. 返回答案时带上引用/证据
  6. 让模型显式声明"检索不完整"(很多人忽视这一步)
python 复制代码
# 概念实现
def index_contract(doc_path):
    doc = parse_document(doc_path)
    for section in doc.sections:
        chunk = {
            "content": section.text,
            "metadata": {
                "section_type": section.type,      # "obligation" / "definition" / "payment_term"
                "parties": section.parties,
                "dates": section.dates,
                "clause_id": section.id,
                "dependencies": section.references  # 引用了哪些其他条款
            }
        }
        index(chunk)

适合:合同、法规、标准文档------结构信息本身就是答案的一部分。


四、选型决策树

sql 复制代码
你的文档是什么类型?
│
├── Markdown / 有清晰标题层级
│   └── → Markdown Header Chunking + 标题 metadata
│
├── 长文档,需要精确定位 + 完整上下文
│   └── → Parent-Child Chunking(128/512/1024)
│
├── 合同 / 法律 / 结构化业务文档
│   └── → Document-Structure-First + 结构化 metadata
│
├── 需要精确引用 + 预算充足
│   └── → Proposition Chunking(LLM 辅助)
│
└── 其他(博客/文档/报告/通用场景)
    └── → Recursive Character Splitting,chunk_size=400~512,overlap=10%

五、几个常被忽视的工程细节

关于 overlap :2026 年 1 月的一项研究发现,在 SPLADE 检索 + Mistral-8B 的组合下,overlap 对准确率没有可测量的提升。Overlap 不是万金油,要根据你的检索方式测试。

关于 chunk size:越小越精准,但 top-k 需要越大,上下文拼接成本越高。越大覆盖越完整,但语义越稀释。400-512 tokens 是目前经验最优的平衡点。

关于 PDF 处理 :结构化 chunking 的前提是文档解析质量。推荐先用 marker-pdfMarkItDown 转成干净的 Markdown,再做 chunking,效果远好于直接在原始 PDF 文本上操作。

关于评估:换了 chunking 策略之后,一定要跑一遍评估(用 RAGAS 或自建测试集),不要靠感觉判断好坏。


六、总结

场景 推荐策略
快速上线,通用文档 Recursive 512
技术文档 / Markdown Markdown Header
长文档,精确 + 完整两手抓 Parent-Child
合同 / 法律 / 结构化 Document-Structure-First
需要精确引用,预算充足 Proposition Chunking

Chunk 不是越"聪明"越好。实测数据显示,朴素的 Recursive 512 在大多数场景下依然最稳。

但对于结构化文档,标准的 token 切分从设计上就是错的------你切掉的不只是文字,而是文档的语义骨架。

"Agents 需要的不是附近 chunk 的模糊感觉,而是可靠的状态。"

选对 chunking 策略,是让 RAG 从"能用"到"好用"最关键的一步。

相关推荐
AI攻城狮4 小时前
如何提高 RAG 的检索质量?这才是真正的瓶颈所在
云原生
AI攻城狮7 小时前
DeepSeek KV Cache 入门解读:98% 命中率背后的工程逻辑
云原生
菜鸟的日志10 小时前
【软件架构风格】面向服务架构(SOA)及其微服务演进
微服务·云原生·架构
PH = 711 小时前
K8S集群的搭建
云原生·容器·kubernetes
CS创新实验室11 小时前
CS实验室行业报告:云计算与云原生行业分析报告
云原生·云计算
AI攻城狮11 小时前
如何维护公司级别的 CLAUDE.md 文件?
云原生
AIMath~1 天前
雪花算法+ZooKeeper解决方案+RPC是什么
分布式·zookeeper·云原生
gwjcloud1 天前
Kubernetes从入门到精通(进阶篇)03
云原生·容器·kubernetes
日取其半万世不竭1 天前
PeerTube 部署指南:自建视频托管平台
云原生·eureka·音视频