大数跨境

LangChain 实战第14课:RAG 为什么必须切分文档?LangChain 给出了这 7 种方案

LangChain 实战第14课:RAG 为什么必须切分文档?LangChain 给出了这 7 种方案 玩AI的方可乐
2025-10-02
1
导读:手把手教学,10 分钟见结果

 

你好,我是方可乐。
一个正在深耕AI编程的30+的AI应用开发工程师。
用AI编程开发过Web应用网站,浏览器插件,

微信小程序,AI智能体,RAG系统。

注公众号&添加微信:ThinkFun666

领取【AI编程资料包】



 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

去年6月份,我做了一个连自己都觉得疯狂的决定:裸辞,All in AI。

现在已经换赛道成功,继续在工作中探索。


 

在上一课,我分享了如何把公司规章制度放进知识库,跑通了一个最小可用的 RAG 系统。

爱动脑子的同学,应该会开始想一些比较实际的问题了:

如果我有一份 100 页的 PDF,公司所有规章制度都在里面,是不是直接丢给 embedding 就行?

答案是:不行。

这么长的东西必须先切分,不然向量模型扛不住。


为什么要切分?

切分是 RAG 的第一步,主要原因有三个:

  1. 1. 向量模型有 token 长度限制 比如 OpenAI 的 text-embedding-3-small 最多支持 8192 tokens,太长直接丢进去就不行,当场报错给你看。
  2. 2. 提高检索精度 用户问“请假规定”,我们希望检索出“请假需提前 3 天申请”,而不是整整一页“考勤制度+请假制度”的混合内容。
  3. 3. 减少大模型负担 检索出来的块更小、更干净,传给 LLM 的上下文更专注,答案自然也更可靠。

所以切分是效果好坏的关键因素


LangChain 的切分方式与应用场景

LangChain 内置了多种切分器,不同文档类型用法不一样,具体场景用到的适合,可以拿这个表参考下怎么做选型:

切分器
机制
适合的文档类型
特点
CharacterTextSplitter
按固定字符数切
日志、配置文件、短文本
简单粗暴,语义可能被截断
RecursiveCharacterTextSplitter
先按段落/句子/标点切,不够再硬切
自然语言文档(规章制度、新闻、合同)
官方推荐,语义保留最好
TokenTextSplitter
按 token 数切
成本敏感、需要精确控制长度的场景
对齐模型的 token 计费逻辑
MarkdownHeaderTextSplitter
按 Markdown 层级(#、##、###)切
技术手册、规章制度、API 文档
保留标题上下文,结构清晰
HTMLSectionSplitter
按 HTML 标签切
网页、公司知识库、wiki
利用标签结构,避免乱切
NLTK / Spacy Splitter
借助 NLP 库按句切
学术论文、技术资料
切分粒度更自然,但要装依赖
Code Splitter
按函数、类切
代码仓库
保证语义完整,避免函数被拆开

案例

老规矩,上代码,新建文件14_rag_split_context.py

这节课的举例,用 10 条规章制度来演示几种常见切分:


           
           
           
           
            
           
           
           
           from langchain.schema import Document
from
 langchain.text_splitter import (
    CharacterTextSplitter,
    RecursiveCharacterTextSplitter,
    TokenTextSplitter,
    MarkdownHeaderTextSplitter
)

# 模拟规章制度文档

raw_text = """
# 公司规章制度

## 考勤制度
1. 员工必须每天打卡。
2. 上班期间禁止使用私人手机。

## 请假制度
3. 员工请假需提前 3 天申请。
4. 公司提供每年 10 天带薪年假。

## 行为规范
5. 办公室内禁止吸烟。
6. 员工需遵守信息安全规范。

## 培训制度
7. 员工每季度需完成一次培训课程。
"""


doc = Document(page_content=raw_text, metadata={"source": "company_policy"})

# 1. 固定长度切分

char_splitter = CharacterTextSplitter(chunk_size=50, chunk_overlap=0)
docs_char = char_splitter.split_documents([doc])

# 2. 递归切分

rec_splitter = RecursiveCharacterTextSplitter(chunk_size=50, chunk_overlap=0)
docs_rec = rec_splitter.split_documents([doc])

# 3. Token 切分

tok_splitter = TokenTextSplitter(chunk_size=30, chunk_overlap=10)
docs_tok = tok_splitter.split_documents([doc])

# 4. Markdown 层级切分

headers_to_split_on = [("#", "header1"), ("##", "header2")]
md_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
docs_md = md_splitter.split_text(raw_text)

print
("\n=== 固定长度切分 ===")
for
 d in docs_char:
    print
(d.page_content)

print
("\n=== 递归切分 ===")
for
 d in docs_rec:
    print
(d.page_content)

print
("\n=== Token 切分 ===")
for
 d in docs_tok:
    print
(d.page_content)

print
("\n=== Markdown 层级切分 ===")
for
 d in docs_md:
    print
(d.page_content, d.metadata)

下面看看运行效果:

在具体的业务中,很难有一个切分策略能够覆盖所有的文档,更多的是见招拆招,灵活切换。

 


 

 

 

 

 


 

 

 

 

 

 

 

 

 

对AI应用开发感兴趣的同学,欢迎加微信申请入群交流学习。

想要学习AI应用开发的同学,可以参照我的代码跑起来,举一反三,一天一个脚印的进步,我相信,会足够坚实。


接下来100天,我会记录从Java程序员到AI应用开发工程师的完整转型路:每一个困惑、每一次突破、每一个真实瞬间。

当前是32/100。

如果你也想了解AI应用开发到底是什么,如果你也在考虑转型但还在犹豫,那就跟着我的记录,一起探索。


继续折腾中,有问题随时交流 🤝
微信号:ThinkFun666

我的免费AI编程交流群,欢迎加入讨论AI编程玩法(说明需求和来意,申请入群)



 

 



推荐阅读:

我就喜欢干这种傻事!为什么转型AI应用开发,我不建议你直接从看书开始学起?

猛然醒悟:原来 AI 编程这件事情,是有门槛的,90%的新手卡在这些地方

30岁转行 AI 应用开发:多久能学会?答案出乎意料

30岁,我放弃写了7年的Java,成功转型AI应用开发

30岁,转型AI应用开发,需要会什么技术?

30岁,空窗期一年,靠什么成功转型AI应用开发?

30岁,没报课,如何从0自学转型AI应用开发?

【声明】内容源于网络
0
0
玩AI的方可乐
1234
内容 502
粉丝 0
玩AI的方可乐 1234
总阅读204
粉丝0
内容502