前言
兄弟们,最近大模型是真火啊!但光火有什么用,咱得把它用在自己的项目里,解决实际问题才算牛。于是很多人撸起袖子就开干,想让大模型能回答自己文档、知识库里的问题。
理想很丰满:我扔一堆文档进去,模型“嗖”一下就学会了,然后就有问必答,跟专家一样。
现实很骨感:不管怎么喂数据,模型要么回答得牛头不对马嘴,要么干脆说“我不知道”。
是不是感觉很熟悉?问题到底出在哪?
很多时候,问题并非出在模型本身,而是出在了我们与模型沟通的第一步——数据处理上。而这第一步中的第一环,就是文本分块(Chunking) 。
为了彻底搞懂RAG(Retrieval-Augmented Generation,检索增强生成)系统里的各种“坑”和“招”,我决定开一个全新的系列:
《RAG 每日一技》
顾名思义,这个系列的目标就是每天聚焦一个RAG相关的技巧,用最精炼的篇幅,把它讲透、讲明白。我们会从最基础的数据处理开始,一步步深入到向量嵌入、检索召回和生成优化等各个环节。
今天,作为系列的第一篇,我们就从最基础,也最容易被忽视的“文本分块”开始聊起。废话不多说,发车!
什么是文本分块 (Chunking)?
我们都知道,现在的大模型(比如GPT系列)都有一个叫做“上下文窗口”的东西(Context Window)。你可以把它理解为模型的“短期记忆”,它能同时处理的文本量是有限的。你不可能把一本几百页的PDF直接扔给它,它“吃不下”。
所以,在把我们的文档喂给模型之前,必须先做一个预处理:把长文档切分成一个个更小的、模型能处理的文本块(Chunk) 。
这个过程,就叫 Chunking。
你可能会想:“嗨,这不就是简单的文本切割嘛,so easy!”
别急,正是这个看似简单的步骤,如果处理不好,会直接影响后续整个RAG链路的最终效果。一个糟糕的Chunking,可能会导致:
- 上下文丢失:一个完整的语义被硬生生切开,导致检索到的文本块信息不全。
- 噪声增加:切分出的文本块包含了太多不相关的信息,干扰了模型的理解。
- 检索效率低下:文本块大小不合适,要么太大抓不住重点,要么太小信息量不足。
可以说,Chunking的质量,决定了你的RAG系统性能的下限。
最直观的方法:固定大小分块 (Fixed-Size Chunking)
提到文本切割,我们最先想到的方法是什么?当然是“一刀切”!也就是固定大小分块。
这种方法简单粗暴:设定一个固定的块大小(chunk_size
),比如100个字符,然后再设定一个重叠大小(chunk_overlap
),比如20个字符,来保证块与块之间有一定的上下文连续性。
我们用代码来直观感受一下。这里以langchain
这个流行的框架为例,因为它封装得很好,方便我们理解概念。
# 假设我们有这样一段文本
text = "RAG(Retrieval-Augmented Generation)是一种结合了检索和生成技术的自然语言处理模型。它的核心思想是,在生成答案之前,先从一个大规模的知识库中检索出与问题相关的文档片段,然后将这些片段作为上下文信息,引导生成模型(Generator)产生更准确、更丰富的回答。这个框架显著提升了大型语言模型在处理知识密集型任务时的表现。"
# 导入固定大小分块器
from langchain.text_splitter import CharacterTextSplitter
# 初始化分块器
# chunk_size设置为50个字符,重叠部分为10个字符
text_splitter = CharacterTextSplitter(
separator = "", # 按字符切分
chunk_size = 50,
chunk_overlap = 10,
length_function = len, # 使用Python内置的len函数计算长度
)
# 进行分块
chunks = text_splitter.split_text(text)
# 我们来看看分块结果
for i, chunk in enumerate(chunks):
print(f"--- Chunk {i+1} ---")
print(chunk)
print(f"(长度: {len(chunk)})\n")
输出结果:
--- Chunk 1 ---
RAG(Retrieval-Augmented Generation)是一种结合了检索和生成技术的自然语言处
(长度: 47)
--- Chunk 2 ---
言处理模型。它的核心思想是,在生成答案之前,先从一个大规模的知识库中检索出与问题相关的文档片段
(长度: 50)
--- Chunk 3 ---
相关的文档片段,然后将这些片段作为上下文信息,引导生成模型(Generator)产生更准确、更
(长度: 49)
--- Chunk 4 ---
更准确、更丰富的回答。这个框架显著提升了大型语言模型在处理知识密集型任务时的表现。
(长度: 44)
“一刀切”的问题出在哪?
看到上面的结果了吗?问题非常明显:
- 句子被无情地截断:看看Chunk 1的结尾 “自然语言处”,和Chunk 2的开头 “言处理模型”。一个完整的词“自然语言处理模型”被硬生生劈开。这就像你看书看到一半,下一页被人撕掉了一样难受。
- 语义完整性被破坏:每个Chunk单独看,都可能不是一个完整的、有意义的句子。当后续的检索系统只召回了其中一个Chunk时,模型得到的就是残缺不全的信息,自然很难做出高质量的回答。
结论就是: 固定大小分块虽然实现简单,但在大多数场景下,它都是一个比较糟糕的选择。因为它完全忽略了文本的语义结构,只是机械地进行切割。
所以,如果你现在还在用这种“一刀切”的方式来处理你的文档,也许这就是你RAG效果不佳的“病根”之一。
总结与预告
好了,今天的第一篇我们先开个胃。
今日小结:
- Chunking (文本分块) 是构建RAG系统的第一步,也是决定系统效果下限的关键一步。
- 固定大小分块 (Fixed-Size Chunking) 是最基础的分块方法,简单粗暴,但会破坏句子的完整性和语义,通常不推荐使用。
看到这里,你肯定会问:“那到底该怎么切分,才能既保证大小合适,又保证语义完整呢?”
别急,这正是我们下一篇文章要深入探讨的话题。
明天预告:RAG 每日一技(二):告别“一刀切”,试试更智能的递归字符分块!
对RAG感兴趣的朋友,记得点个关注,跟上《RAG 每日一技》这个系列,我们一起把RAG这个硬骨头啃下来!也欢迎在评论区留下你的问题和看法,我们一起交流。