前面我们介绍了RAG知识库搭建的一些关键步骤,包括分词器、Embedding词嵌入、向量数据库存储,其实还忽略了一个比较重要的步骤,就是在分词器之前,还需要进行文本切分;
如果我们想要创建一个RAG知识库,想必这个知识库的信息量是比较大的,如果这些知识都是一些文本信息的话,那能称之为库,文本的字数应该也在十万级别,甚至更多;那针对这些海量的文本信息,我们一次性将它输入给分词器是不可能的,即便Embedding可以接受这么大的token同时输入,那输出也只是一个高维向量,这也违背了做知识库的初心;所以我们需要在进入分词器之前,将这些海量的文本进行切分,将切分好的文本块逐一或者批量进行向量化,这样才会获得海量的语义向量数据;
但是,即便是简单的数据切分也是有很多需要注意的点,不可以盲目的随意乱切,下面就简单说一说关于切分数据块的一些小细节,作为整个RAG知识库创建的一个补充。
一、切分要点
在搭建RAG(Retrieval-Augmented Generation)知识库时,文本切块是一个非常重要的步骤。切块的质量会直接影响到后续的检索和生成效果。以下是一些注意事项:
-
保持语义完整性
- 切块时要尽量保证每个块包含完整的语义信息,避免将一句话或一个段落拆分成多个块,从而导致上下文丢失。
- 例如,不要在句子中间断开,而应该以句号、分号等标点符号为边界。
-
控制块的大小
- 块的大小需要根据模型的最大输入长度来调整。通常块的大小建议在100-500个token之间。
- 过大的块可能导致模型无法处理完整内容,过小的块则可能丢失重要上下文信息。
-
重叠窗口
- 在切块时可以设置一定的重叠窗口(overlap),这样可以避免因切割导致的信息断裂。
- 例如,两个相邻的块可以有50-100个token的重叠部分。
-
保留元信息
如果原始文档中有一些重要的结构化信息(如标题、章节号、时间戳等),在切块时应尽量保留这些信息,以便后续检索时能更好地理解上下文。 -
处理特殊格式
对于包含表格、代码、列表等内容的文档,需要特别注意这些格式的处理方式,确保它们在切块后仍然可读且有意义。 -
多语言支持
如果知识库中包含多语言内容,切块时需要考虑不同语言的语法和语义特点。例如,中文没有空格分隔符,因此分词工具可能更合适。 -
去噪处理
在切块前应对文本进行清洗,去除无关的噪声(如HTML标签、广告内容、重复内容等),以提高切块质量。 -
测试与调优
切块策略需要经过实际测试和调优,观察其对检索和生成效果的影响,并根据结果不断优化。
二、常用工具
目前也有很多工具可以帮助高效率的进行数据切分,下面就列几个比较常用的切分工具:
2.1 LangChain
LangChain 是一个流行的框架,专门用于构建基于语言模型的应用程序。它提供了灵活的文本切块功能;
- 特性:
- 支持多种切块策略(按字符数、按句子、按段落)。
- 可以设置重叠窗口。
- 支持多语言处理。
- 文档地址:LangChain
- 代码示例:
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 示例长文本
long_text = """
在构建RAG知识库时,文本切块是一个非常重要的步骤。
切块的质量会直接影响到后续的检索和生成效果。
通常情况下,我们需要根据语义完整性、块大小等因素来设计切块策略。
此外,我们还需要考虑多语言支持、特殊格式处理等问题。
为了实现高效的切块,可以使用LangChain等工具。
"""
# 初始化切分器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=50, # 每个块的最大字符数
chunk_overlap=10, # 块之间的重叠字符数
length_function=len, # 使用len函数计算长度
separators=["\n\n", "\n", "。", ",", " ", ""] # 分隔符优先级列表
)
# 对文本进行切分
chunks = text_splitter.split_text(long_text)
# 打印切分结果
for i, chunk in enumerate(chunks):
print(f"Chunk {i + 1}:\n{chunk}\n")
2.2 Hugging Face Transformers
Hugging Face 提供了 Tokenizer
工具,可以用于按token切分文本;
- 特性:
- 支持多种预训练模型的分词器
- 可以自定义最大长度和重叠窗口
- 代码示例:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
text = "This is a long document that needs to be chunked."
tokens = tokenizer.tokenize(text)
chunks = [tokens[i:i+10] for i in range(0, len(tokens), 10)] # 按10个token切块
2.3 NLTK
NLTK 是一个经典的自然语言处理库,适合处理英文文本;
- 特性:
- 提供句子分割、词性标注等功能
- 可以结合正则表达式实现复杂的切块逻辑
- 代码示例:
import nltk
nltk.download('punkt')
from nltk.tokenize import sent_tokenize
text = "This is the first sentence. This is the second one."
sentences = sent_tokenize(text) # 按句子切块
2.4 spaCy
spaCy 是一个高效的NLP库,支持多种语言;
- 特性:
- 提供句子分割、命名实体识别等功能
- 支持自定义管道处理
- 代码示例:
import spacy
nlp = spacy.load("en_core_web_sm")
text = "This is a sample text. It contains multiple sentences."
doc = nlp(text)
sentences = [sent.text for sent in doc.sents] # 按句子切块
2.5 BeautifulSoup
如果你的文档包含HTML或其他标记语言,BeautifulSoup 是一个强大的工具,可以帮助你提取纯文本并进行切块;
- 特性:
- 支持解析HTML、XML等格式
- 可以去除标签、提取特定部分
- 代码示例:
from bs4 import BeautifulSoup
html_doc = "<p>This is a paragraph.</p><p>Another paragraph.</p>"
soup = BeautifulSoup(html_doc, 'html.parser')
text = soup.get_text() # 提取纯文本
注:如果以上方法均不能满足需求,也可以自己编写合适的脚本进行切分;
三、总结
在选择切块工具时,应根据具体的文档类型、语言特点和应用场景进行选择。对于大多数场景,LangChain 和 Hugging Face 的工具链是非常不错的选择。同时,在切块过程中,务必注意语义完整性、块大小控制和重叠窗口的设置,以确保最终的知识库能够高效地支持检索和生成任务。