大家好,我是飞哥!👋

欢迎来到吴恩达《LangChain:Chat with Your Data》系列课程的第三讲。上一讲我们把文档加载进来了,今天我们要进行关键的一步:Document Splitting (文档拆分)


1. 为什么:切不好,AI 就吃不消 🍽️

💡 场景锚定

你给 AI 喂书,不能整本塞进去。

  1. 胃口有限:大模型的上下文窗口(Context Window)是有限的(比如 GPT-3.5 只有 4k/16k token)。
  2. 消化不良:就算塞进去了,太长的文本会让 AI 抓不住重点(Lost in the Middle 现象)。

⚠️ 核心痛点

所以,我们必须把长文档切成小块(Chunks)。但切分不是简单的“数数”。

  • 切坏了:把“我爱”和“你”切到了两个块里,AI 就不知道谁爱谁了。
  • 切好了:既要块小,又要保持句子的语义完整性。

2. 是什么:LangChain 的拆分策略 ✂️

LangChain 提供了多种拆分器(Text Splitters),核心参数通常有两个:

  1. chunk_size: 每个块的大小(字符数或 Token 数)。
  2. chunk_overlap: 重叠部分的大小。这是关键!就像接力赛跑的交接棒区,确保上下文不会在切分点丢失。

🦴 骨架图

原始文档: "人工智能(AI)是模拟人类智能过程的计算机系统。这些过程包括..."
    |
    v
[拆分器 (Splitter)] --(Size=20, Overlap=5)-->
    |
    |-- 块1: "人工智能(AI)是模拟人类智能过程的计算机系统"
    |
    |-- 块2: "过程的计算机系统。这些过程包括..."  <-- 注意这里的重叠!

3. 怎么用:实战代码 💻

3.1 基础字符拆分 (CharacterTextSplitter) 🔡

最简单粗暴的方法,按字符数硬切。

from langchain_text_splitters import CharacterTextSplitter

text = "人工智能(AI)是模拟人类智能过程的计算机系统。这些过程包括学习、推理和自我修正。"

# 初始化拆分器
splitter = CharacterTextSplitter(
    separator="。",      # 分隔符:尝试按中文句号切分
    chunk_size=20,      # 块大小:每个块最大字符数
    chunk_overlap=5     # 重叠大小:相邻块之间重叠的字符数(保持上下文)
)

chunks = splitter.split_text(text)
# 输出: 
# 块 0: 人工智能(AI)是模拟人类智能过程的计算机系统
# 块 1: 这些过程包括学习、推理和自我修正

3.2 递归字符拆分 (RecursiveCharacterTextSplitter) 🔄 (推荐)

这是最常用的拆分器。它很聪明,会尝试按顺序使用一组分隔符 ["\n\n", "\n", " ", ""] 来切分。

  • 先看能不能按段落(双换行)切?
  • 不行就按句子(单换行)切?
  • 还不行就按单词(空格)切?

这样能最大程度保留语义的完整性。

from langchain_text_splitters import RecursiveCharacterTextSplitter

text_long = """
第一章:什么是大模型?
大模型是基于深度学习的海量参数模型。它们在自然语言处理领域取得了巨大成功。

第二章:大模型的核心技术
大模型的核心是 Transformer 架构。通过自注意力机制,模型可以理解长距离的上下文关系。
"""

# 初始化递归拆分器
recursive_splitter = RecursiveCharacterTextSplitter(
    chunk_size=50,      # 每个块的目标大小
    chunk_overlap=10,   # 块之间的重叠大小
    separators=["\n\n", "\n", " ", ""] # 拆分优先级:段落 -> 句子 -> 空格 -> 字符
)

chunks = recursive_splitter.split_text(text_long)
# 输出: 保持了段落的完整性

3.3 Token 拆分 (TokenTextSplitter) 🪙

大模型是按 Token 计费和处理的。如果你对 Token 数限制很严格,可以用这个。

注意:中文在 Tokenizer 里可能会被切成乱码,使用时需小心。

3.4 Markdown 拆分 (MarkdownHeaderTextSplitter) 📑

如果你的文档是 Markdown 格式,这个神器可以按标题(Header)来切分,并且把标题保留在 Metadata 里!这对于 RAG 检索非常有帮助,因为标题往往包含了关键的上下文。

from langchain_text_splitters import MarkdownHeaderTextSplitter

markdown_document = "# 标题1\n\n## 章节1.1\n内容A\n\n## 章节1.2\n内容B"

# 定义要拆分的标题级别和对应的 Metadata 键名
headers_to_split_on = [
    ("#", "Header 1"),  # 一级标题 -> Metadata['Header 1']
    ("##", "Header 2")  # 二级标题 -> Metadata['Header 2']
]

splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
splits = splitter.split_text(markdown_document)

print(splits[0].page_content) # 输出: 内容A
print(splits[0].metadata)     # 输出: {'Header 1': '标题1', 'Header 2': '章节1.1'}

📝 飞哥总结

  1. Recursive 是首选:90% 的情况下,直接用 RecursiveCharacterTextSplitter,它最懂人类语言的结构。
  2. Overlap 不能省:一定要设置 chunk_overlap,否则切分边缘的信息会丢失。
  3. 结构化拆分:如果文档有结构(如 Markdown, HTML),尽量用对应的结构化拆分器,把标题信息存入元数据。

一句话记住它 💡:文档拆分就像切牛排,切得大小适中且不切断纹理(语义),AI 才能吃得香、消化好!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐