全网最细|LangChain 文档切割从入门到精通:原理 + 实战 + 调优

📝 本章学习目标:彻底掌握 LangChain 文档切割全流程,能独立完成纯文本、PDF、Markdown、代码、长文档的智能分割,适配 RAG 系统,解决大模型上下文超限、语义断裂、检索不准问题。


一、引言:为什么文档切割是 RAG 必学核心

在大模型应用爆发的今天,RAG(检索增强生成) 已成为落地私有知识库的标准方案。而文档切割(Text Splitting) 是 RAG pipeline 中最关键、最容易踩坑的一环。

1.1 背景与意义

  • 大模型有严格上下文窗口限制(GPT-3.5 4k/16k、GPT-4 8k/32k、国产模型多在 4k--8k),长文本直接输入必报错。
  • 切割质量直接决定:检索准确率、回答相关性、 hallucination(幻觉)率、系统响应速度
  • 好的切割 = 语义完整 + 长度合规 + 无冗余断裂 + 可复现可调试。

据社区统计,60% 以上 RAG 效果差,根源不在模型 / 向量库,而在文档切割不合理

1.2 本章结构概览

plaintext

复制代码
环境搭建 → 核心概念 → 分割器原理 → 多场景实战代码 → 调优策略 → 常见坑 → 面试/工程最佳实践

二、核心概念解析

2.1 基本定义

  • Document :LangChain 统一文档对象,含 page_content(文本)+ metadata(元信息,页码 / 来源 / 时间等)。
  • Chunk:切割后的文本片段,是向量入库与检索的最小单元。
  • Chunk Size:单块最大长度(字符 / Token)。
  • Chunk Overlap:块间重叠长度,保证上下文连贯。
  • Separator:分隔符(换行、句号、空格、正则等)。
  • Length Function :长度计算方式(len 字符数 / tiktoken Token 数)。

2.2 关键术语

  1. 递归分割:按层级优先分割(段落→句子→词→字符),最大保留语义。
  2. Token 感知分割:按模型真实 Token 数切割,避免窗口溢出。
  3. 语言专属分割:对 Python/JS/HTML/Java 等代码按语法结构分割。
  4. 语义保留:不把一句话、一个概念、一个代码块强行切断。

2.3 文档切割标准架构

plaintext

复制代码
┌─────────────────────────────────┐
│        文档加载(Loader)        │
│  TXT/PDF/MD/DOCX/HTML/DB/爬取    │
├─────────────────────────────────┤
│        文本清洗(预处理)        │
│ 去空行/去多余空格/统一换行/去噪  │
├─────────────────────────────────┤
│        文本分割(Splitter)      │
│  递归字符 / Token / 代码 / 语义  │
├─────────────────────────────────┤
│        块校验与增强              │
│ 长度统计/元数据注入/去重/过滤    │
└─────────────────────────────────┘

三、环境搭建(一步到位)

3.1 安装依赖

bash

运行

python 复制代码
# 核心分割器
pip install -U langchain-text-splitters

# 文档加载器
pip install -U langchain-community pypdf python-docx unstructured markdown

# Token 计算(OpenAI 系)
pip install -U tiktoken

# 环境变量
pip install python-dotenv

3.2 基础导入模板(所有案例通用)

python

运行

python 复制代码
import os
import re
import tiktoken
from dotenv import load_dotenv
from langchain_core.documents import Document
from langchain_text_splitters import (
    RecursiveCharacterTextSplitter,
    CharacterTextSplitter,
    Language
)

# 加载环境变量
load_dotenv()

# ======================
# 全局工具函数
# ======================
def tiktoken_len(text: str, encoding_name: str = "cl100k_base") -> int:
    """
    计算文本的 Token 数量(适配 GPT3.5/4/Claude 等)
    :param text: 输入文本
    :param encoding_name: 编码名,cl100k_base 适配 most
    :return: token 数量
    """
    encoding = tiktoken.get_encoding(encoding_name)
    return len(encoding.encode(text))

def print_chunks(chunks: list[Document], max_show: int = 5):
    """
    友好打印切割结果
    """
    print(f"📦 总块数:{len(chunks)}")
    print("=" * 80)
    for i, chunk in enumerate(chunks[:max_show]):
        print(f"【第 {i+1} 块】")
        print(f"字符数:{len(chunk.page_content)}")
        print(f"Token 数:{tiktoken_len(chunk.page_content)}")
        print(f"内容:{chunk.page_content[:150]}...")
        print(f"元数据:{chunk.metadata}")
        print("-" * 80)

四、最核心:RecursiveCharacterTextSplitter 递归分割(90% 场景首选)

4.1 原理

层级分隔符 依次尝试分割,不满足长度再下钻,最大程度保留段落 / 句子完整性,是通用最强分割器LangChain。

默认分隔符(英文):

plaintext

复制代码
["\n\n", "\n", " ", ""]

中文优化分隔符(强烈推荐)

python

运行

python 复制代码
separators_cn = [
    "\n\n",           # 段落
    "\n",             # 行
    "。", "!", "?", # 句子结束
    ";",             # 分句
    ",", "、",       # 短语
    " ",              # 空格
    ""                # 兜底
]

4.2 基础实战:纯中文文本切割

python

运行

python 复制代码
# ======================
# 1. 准备长文本(示例:长篇文章)
# ======================
long_text = """
人工智能(AI)是一门旨在使计算机系统能够模拟、延伸和扩展人类智能的技术科学。
它包含机器学习、自然语言处理、计算机视觉、专家系统等多个分支。
近年来,随着大模型技术的飞速发展,AI 已经深入渗透到医疗、金融、教育、交通、工业制造等各行各业。
在自然语言处理领域,RAG(检索增强生成)技术有效解决了大模型幻觉、知识滞后等问题,成为企业落地的主流方案。
文档切割作为 RAG 的第一步,直接决定了后续检索精度与生成质量。
合理的切割策略能让模型精准定位知识点,输出稳定可靠的答案。
"""

# ======================
# 2. 初始化分割器(中文专用)
# ======================
splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,          # 单块最大字符数
    chunk_overlap=50,        # 重叠长度,保证上下文连贯
    separators=separators_cn,# 中文分隔符
    length_function=len,     # 按字符长度计算
    is_separator_regex=False # 非正则
)

# ======================
# 3. 执行切割
# ======================
# 方式1:直接切割字符串 → 返回字符串列表
text_chunks = splitter.split_text(long_text)

# 方式2:切割为 Document 对象(推荐,保留元数据)
docs = [Document(page_content=long_text, metadata={"source": "demo_text"})]
splitted_docs = splitter.split_documents(docs)

# ======================
# 4. 查看结果
# ======================
print_chunks(splitted_docs)

4.3 核心参数详解

表格

参数 说明 推荐值
chunk_size 单块最大长度 300--800 字符 / 200--500 Token
chunk_overlap 重叠长度 50--100 字符 / 30--80 Token
separators 分隔符优先级 中文用上面 separators_cn
length_function 长度计算 len(简单)/tiktoken_len(精准)
is_separator_regex 是否正则分隔 False(稳定)

五、Token 感知切割(工程级必用)

5.1 为什么要用

  • 字符数 ≠ Token 数(中文 1 字≈1--2 Token)。
  • 按字符切割容易实际 Token 超限,导致 API 报错。
  • 按真实 Token 切割 = 100% 安全

5.2 实战代码:按 Token 切割

python

运行

python 复制代码
# ======================
# 1. 基于 Token 的分割器
# ======================
token_splitter = RecursiveCharacterTextSplitter(
    chunk_size=400,          # 最大 400 Token
    chunk_overlap=80,        # 重叠 80 Token
    separators=separators_cn,
    length_function=tiktoken_len, # 核心:用 Token 计算长度
    is_separator_regex=False
)

# ======================
# 2. 切割并验证
# ======================
token_chunks = token_splitter.split_documents(docs)

print("🔍 按 Token 切割结果:")
print_chunks(token_chunks)

# 验证每块 Token 不超限
for i, chunk in enumerate(token_chunks):
    token_num = tiktoken_len(chunk.page_content)
    if token_num > 400:
        print(f"⚠️ 第 {i+1} 块超限:{token_num}")
    else:
        print(f"✅ 第 {i+1} 块合规:{token_num}")

5.3 快捷方式:from_tiktoken_encoder

python

运行

python 复制代码
# ======================
# 直接用封装好的 Token 分割器
# ======================
token_quick_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    encoding_name="cl100k_base",  # GPT 系列编码
    chunk_size=400,
    chunk_overlap=80
)

quick_chunks = token_quick_splitter.split_documents(docs)
print_chunks(quick_chunks)

六、多格式文档实战(PDF/Markdown/DOCX/ 代码)

6.1 实战 1:PDF 文档切割(最常用)

python

运行

python 复制代码
from langchain_community.document_loaders import PyPDFLoader

# ======================
# 1. 加载 PDF
# ======================
pdf_path = "人工智能技术白皮书.pdf"
loader = PyPDFLoader(pdf_path)
pdf_docs = loader.load()  # 列表,每个元素是一页 PDF → Document

# ======================
# 2. 切割(保留页码元数据)
# ======================
pdf_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=100,
    separators=separators_cn,
    length_function=tiktoken_len
)

pdf_splitted = pdf_splitter.split_documents(pdf_docs)

# ======================
# 3. 查看(页码自动保留在 metadata)
# ======================
print_chunks(pdf_splitted)

6.2 实战 2:Markdown 切割(按标题层级)

python

运行

python 复制代码
from langchain_community.document_loaders import UnstructuredMarkdownLoader

# ======================
# 1. 加载 MD(按结构解析:标题/段落/列表)
# ======================
md_path = "LangChain实战教程.md"
md_loader = UnstructuredMarkdownLoader(md_path, mode="elements")
md_docs = md_loader.load()

# ======================
# 2. 分割
# ======================
md_splitter = RecursiveCharacterTextSplitter(
    chunk_size=400,
    chunk_overlap=50,
    separators=["\n#", "\n##", "\n###", "\n\n", "\n", "。", " "]
)

md_chunks = md_splitter.split_documents(md_docs)
print_chunks(md_chunks)

6.3 实战 3:代码切割(Python/JS/HTML/Java)

适合代码库、技术文档、接口说明,按语法结构切割,不破坏函数 / 类 / 代码块LangChain。

python

运行

python 复制代码
# ======================
# 1. 示例代码
# ======================
python_code = """
def rag_pipeline(doc_path: str, question: str) -> str:
    # 加载文档
    loader = PyPDFLoader(doc_path)
    docs = loader.load()
    
    # 切割文档
    splitter = RecursiveCharacterTextSplitter(chunk_size=300)
    chunks = splitter.split_documents(docs)
    
    # 向量化
    embeddings = OpenAIEmbeddings()
    db = Chroma.from_documents(chunks, embeddings)
    
    # 检索
    retriever = db.as_retriever(search_kwargs={"k": 3})
    relevant_docs = retriever.get_relevant_documents(question)
    
    # 生成答案
    chain = RetrievalQA.from_chain_type(llm=ChatOpenAI(), chain_type="stuff", retriever=retriever)
    return chain.run(question)

# 调用
if __name__ == "__main__":
    ans = rag_pipeline("test.pdf", "什么是RAG?")
    print(ans)
"""

# ======================
# 2. 代码专用分割器
# ======================
code_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.PYTHON,
    chunk_size=300,
    chunk_overlap=30
)

# ======================
# 3. 切割代码
# ======================
code_docs = [Document(page_content=python_code)]
code_chunks = code_splitter.split_documents(code_docs)

print("🐍 Python 代码切割结果:")
print_chunks(code_chunks)

支持语言:

  • Python / JavaScript / TypeScript
  • HTML / CSS / Java / Go / PHP / C++ / C#

6.4 实战 4:Word(DOCX)切割

python

运行

python 复制代码
from langchain_community.document_loaders import Docx2txtLoader

# 加载 Word
docx_loader = Docx2txtLoader("企业知识库.docx")
docx_docs = docx_loader.load()

# 切割
docx_splitter = RecursiveCharacterTextSplitter(
    chunk_size=400,
    chunk_overlap=80,
    separators=separators_cn,
    length_function=tiktoken_len
)

docx_chunks = docx_splitter.split_documents(docx_docs)
print_chunks(docx_chunks)

七、高级功能:自定义分割、清洗、增强

7.1 自定义正则分割(精准控制)

python

运行

python 复制代码
# ======================
# 按【章节】【条目】【问题】等正则切割
# ======================
regex_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=[r"\n第[\d一二三四五六七八九十]+章", r"\n\d+\.", "。", " "],
    is_separator_regex=True  # 开启正则
)

# 带章节的文本
book_text = """
第1章 人工智能概述
1.1 AI的定义
人工智能是模拟人类智能的技术...
1.2 AI发展历史
从图灵测试到大模型...
第2章 RAG技术原理
2.1 检索增强生成流程
2.2 文档切割最佳实践
"""

regex_chunks = regex_splitter.split_text(book_text)
for i, c in enumerate(regex_chunks):
    print(f"第{i+1}章块:\n{c}\n{'-'*50}")

7.2 文本预处理清洗(提升切割质量)

python

运行

python 复制代码
def clean_text(text: str) -> str:
    """
    文本清洗:去多余空格、空行、特殊符号
    """
    # 去多余空行
    text = re.sub(r"\n+", "\n", text)
    # 去多余空格
    text = re.sub(r" +", " ", text)
    # 去首尾空格
    text = text.strip()
    return text

# 使用
raw_text = "  我   是  空  格  怪  \n\n\n  文档切割实战教程  "
cleaned = clean_text(raw_text)
print("清洗前:", repr(raw_text))
print("清洗后:", repr(cleaned))

7.3 块增强:自动添加元数据、过滤短块

python

运行

python 复制代码
def enhance_chunks(chunks: list[Document], min_len: int = 50) -> list[Document]:
    """
    块增强:
    1. 过滤过短的无效块
    2. 自动添加序号、时间戳元数据
    """
    enhanced = []
    for idx, chunk in enumerate(chunks):
        content = chunk.page_content
        # 过滤过短
        if len(content) < min_len:
            continue
        # 新增元数据
        chunk.metadata["chunk_id"] = idx + 1
        chunk.metadata["char_length"] = len(content)
        chunk.metadata["token_length"] = tiktoken_len(content)
        enhanced.append(chunk)
    return enhanced

# 调用
enhanced_chunks = enhance_chunks(splitted_docs)
print_chunks(enhanced_chunks)

八、工程最佳实践(直接复制到生产)

8.1 通用切割函数(生产级封装)

python

运行

python 复制代码
def split_document(
    file_path: str,
    chunk_size: int = 400,
    chunk_overlap: int = 80,
    use_token: bool = True
) -> list[Document]:
    """
    通用文档切割入口,支持 TXT/PDF/MD/DOCX
    :param file_path: 文件路径
    :param chunk_size: 块大小
    :param chunk_overlap: 重叠
    :param use_token: 是否按 Token 切割
    :return: 切割后的 Document 列表
    """
    # 1. 自动选择 Loader
    ext = os.path.splitext(file_path)[-1].lower()
    if ext == ".pdf":
        loader = PyPDFLoader(file_path)
    elif ext == ".docx":
        loader = Docx2txtLoader(file_path)
    elif ext == ".md":
        loader = UnstructuredMarkdownLoader(file_path)
    elif ext == ".txt":
        loader = UnstructuredMarkdownLoader(file_path)
    else:
        raise ValueError(f"不支持文件类型:{ext}")

    # 2. 加载文档
    docs = loader.load()

    # 3. 选择长度函数
    length_func = tiktoken_len if use_token else len

    # 4. 初始化分割器
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=chunk_size,
        chunk_overlap=chunk_overlap,
        separators=separators_cn,
        length_function=length_func
    )

    # 5. 切割 + 增强
    splits = splitter.split_documents(docs)
    final_chunks = enhance_chunks(splits)

    return final_chunks

# ======================
# 一行调用
# ======================
if __name__ == "__main__":
    final = split_document("人工智能白皮书.pdf")
    print(f"✅ 最终有效块:{len(final)}")
    print_chunks(final)

8.2 不同场景推荐参数

表格

场景 chunk_size chunk_overlap 分割器
通用文章 300--500 字符 50--100 递归中文
技术文档 400--600 Token 80--120 Token 递归
代码文件 200--300 字符 20--40 语言专属
法律 / 合同 500--800 字符 100--150 正则 + 递归
新闻 / 对话 200--300 字符 30--50 短句优先

九、常见问题与避坑指南

9.1 高频问题

Q1:切割后句子被截断怎么办?

  • 增大 chunk_overlap
  • 调整 separators,把句子结束符放更前面
  • 适当增大 chunk_size

Q2:按字符切割,Token 还是超限?

  • 必须改用 tiktoken_len 按 Token 切割
  • 模型不同编码不同,不要估算字符→Token

Q3:PDF 切割乱码、内容错乱?

  • PyPDFLoader 而非 UnstructuredPDFLoader
  • 先清洗文本,再切割
  • 检查 PDF 是否是图片版(需 OCR)

Q4:块太多 / 太少,检索不准?

  • 太多:调大 chunk_size
  • 太少:调小 chunk_size
  • 配合向量库 search_kwargs={"k":3--5} 使用

9.2 经典错误代码对比

❌ 错误:无重叠、无清洗、按字符硬切

python

运行

复制代码
bad_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=0)

✅ 正确:中文分隔符 + Token 计算 + 合理重叠

python

运行

复制代码
good_splitter = RecursiveCharacterTextSplitter(
    chunk_size=400,
    chunk_overlap=80,
    separators=separators_cn,
    length_function=tiktoken_len
)

十、未来趋势与职业发展

  1. 语义切割:基于 embedding 自动聚类语义块,未来主流。
  2. 自适应切割:根据内容复杂度自动调整块大小。
  3. 多模态切割:文本 + 图片 + 表格统一结构化分割。
  4. 端侧切割:浏览器 / 移动端本地切割,保护隐私。

学习路径

  • 入门:掌握递归字符分割 → 1 周
  • 进阶:Token 切割 + 多格式文档 → 2 周
  • 专家:自定义分割 + 工程 pipeline + 调优 → 1 个月

十一、本章小结

本章从原理→环境→基础→多格式→高级→工程 完整覆盖 LangChain 文档切割,提供可直接复制到生产的代码,解决 RAG 最核心痛点。

核心记住三句话:

  1. 90% 场景用 RecursiveCharacterTextSplitter + 中文分隔符
  2. 生产环境必须按 Token 切割,不要按字符估算
  3. 切割质量 = 语义完整 + 长度合规 + 元数据齐全

💖 看完点赞 + 关注,下期更硬核!

我是专注 RAG 大模型落地 的实战派博主,持续输出:✅ LangChain 全栈教程 ✅ RAG 优化调优 ✅ 私有知识库搭建 ✅ 大模型应用开发

点赞 + 收藏 + 关注,持续更新不迷路~

相关推荐
想你依然心痛21 天前
【腾讯位置服务开发者征文大赛】时空数据智能洞察:基于MCP协议与腾讯位置服务的商业选址AI决策系统实战
人工智能·tag·腾讯地图·mcp·腾讯位置服务
weixin_462446234 个月前
Milvus + LangChain + Ollama 搭建生产级 RAG(含 Tag / Metadata 解析)
langchain·milvus·tag·ollama
淡海水8 个月前
【URP】Unity Shader Tags
unity·游戏引擎·渲染·shader·tag·urp
漫步企鹅1 年前
【Git】面对发布或重要节点,Git如何打Tag?
git·tag·节点·发布
百锦再1 年前
Razor编程中@Helper的用法大全
.net·web·blazor·tag·core·razor·helper
梁萌1 年前
10-DevOps-Jenkins参数化构建实现多版本发布
运维·gitlab·jenkins·devops·tag
烫青菜1 年前
Unity | Tag、Layer常量类生成工具
unity·游戏引擎·tag
大模型之路1 年前
Table-Augmented Generation(TAG):Text2SQL与RAG的升级与超越
llm·tag·text2sql·rag·检索增强生成
大熊猫侯佩1 年前
SwiftUI 撸码常见错误 2 例漫谈
swiftui·xcode·tag·tabview·preview·coredata·fetchrequest