TextSplitter

长 PDF 整页 embedding 会稀释语义,检索时只命中整页噪声。TextSplitter 把 Document 切成更小 chunk,在 上下文长度语义完整 之间折中。LangChain 将切分器独立为 langchain-text-splitters 包,与 Loader、VectorStore 串联。

段末注释TextSplitter(文本切分器)= 按字符/token/结构把长文本拆成多个 Document 的组件。


1. 一句话定位

维度 内容
角色 能力层 索引前处理:长 Document → 多个小 Document
输入 → 输出 list[Document] 或 str → list[Document]
典型调用入口 splitter.split_documents(docs)split_text(text)
与 LangGraph 切分多在离线 ETL;在线 Agent 偶发动态切分

2. 实现逻辑

1
2
3
4
5
6
1. loader.load() → list[Document](可能一页一条)
2. splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
3. chunks = splitter.split_documents(docs)
4. 每条 chunk 继承/合并 metadata(source、page)
5. vectorstore.add_documents(chunks)
6. 检索命中 chunk 级片段 → 拼入 prompt

字段级变形

1
2
3
Document(page_content="AAAA...2000字...", metadata={page:1})
→ split_documents
[Document(content=chunk1, metadata={page:1}), Document(content=chunk2, ...), ...]

3. 原理说明

3.1 RecursiveCharacterTextSplitter

RecursiveCharacterTextSplitter(类,langchain_text_splitters
功能:按分隔符列表从粗到细递归切,尽量在段落边界断开。

参数 类型 默认值 最小维度
chunk_size int 1000 ≥1;须 > chunk_overlap
chunk_overlap int 200 ≥0;0=不重叠
length_function callable len(字符) 返回非负 int
separators list[str] ["\n\n", "\n", " ", ""] len≥1,最后常为 "" 保底
keep_separator bool False
is_separator_regex bool False

split_text(text: str)(方法)
最小输入:任意 str(含空串 → [][''] 视实现);短于 chunk_size 则返回 len=1

1
2
splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
parts = splitter.split_text("短文本无需切分。") # 通常 1 段

split_documents(documents)(方法)
功能:切 Document 并复制 metadata 到各 chunk。
最小维度:documents len≥1。

1
chunks = splitter.split_documents([Document(page_content=text, metadata={"source": "a.md"})])

3.2 chunk_overlap

相邻 chunk 共享尾/头部,避免句子在边界被截断。overlap 过大则索引冗余。
最小有意义:0 ≤ overlap < chunk_size;overlap=0 语法合法但易断句。

3.3 结构化切分

MarkdownHeaderTextSplitter(类)
功能:按 Markdown 标题切,标题写入 metadata。
默认值:headers_to_split_on 必填。最小:至少 1 个 (级别, 元数据键),如 [("#", "h1")]

1
2
from langchain_text_splitters import MarkdownHeaderTextSplitter
MarkdownHeaderTextSplitter(headers_to_split_on=[("#", "h1"), ("##", "h2")]).split_text("# A\n正文")

代码可用 RecursiveCharacterTextSplitter.from_language(Language.PYTHON, ...)Language 为枚举。

3.4 与 RAG 方法论

切分影响召回率与答案完整性;评测与业务架构不在本篇。本篇只讲 API。


4. 最小可运行示例

1
pip install -U langchain-text-splitters langchain-core
1
2
3
4
5
6
7
8
9
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter

text = "LangChain 支持 LCEL。" * 30 # 长文本
doc = Document(page_content=text, metadata={"source": "demo.md"})
splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
chunks = splitter.split_documents([doc])
print(len(chunks), len(chunks[0].page_content) <= 100)
# 预期:多条 True(最后一条可能略短)

纯字符串:

1
2
parts = splitter.split_text("短文本无需切分。")
print(len(parts)) # 1

重要配置参数

参数(API 名) 类型 / 默认值 功能说明 作用与影响 参考起点 配置指导
chunk_size int,默认 1000 单块最大长度(默认按字符,可换 token 计数) 过大超 embedding 窗;过小语义破碎 300~1000 字符 代码库偏小;FAQ 可大
chunk_overlap int,默认 200 相邻块首尾重叠多少,避免句子被切断 过大索引冗余、存储涨;0 易断句 chunk_size 的 10%~20% 必须 < chunk_size
length_function callable,默认 len 用什么函数量「长度」 改成 tiktoken 后 chunk_size 含义变成 token len / tiktoken 按 token 切更贴近模型窗
separators list[str],默认段落→行→空格→空串 从粗到细尝试的切分优先级 中文可保留 \n\n;最后 "" 保底硬切 默认即可 不要删掉最后的 ""
keep_separator bool,默认 False 切分后是否把分隔符留在块里 True 可保留 Markdown 标题标记 False 需标题进 metadata 时另用 Header splitter
is_separator_regex bool,默认 False 把 separators 当正则而非字面量 True 写错正则会切出意外块 False 复杂结构才开

5. 易踩坑

  1. chunk 过大仍超 embedding 模型输入上限:需在 splitter 层压长度。
  2. split 丢 metadata:用 split_documents 而非 split_text+手动组,除非自行复制 metadata。
  3. overlap=0 且 chunk 边界在表格/代码中间:检索到半表半码,模型胡答。

小结

  • RecursiveCharacterTextSplitter 是最常用的通用切分器。
  • chunk_size / chunk_overlap 是 RAG 质量的一阶旋钮。
  • 切分输出仍是 Document,直接 add_documents
  • 策略评测与业务切分见 RAG 目录。

参考链接

-------------本文结束感谢您的阅读-------------