将大型文档划分为较小的部分是一项至关重要但又复杂的任务,它对检索增强生成 (RAG) 系统的性能有重大影响。这些系统旨在通过结合基于检索和基于生成的方法,提高输出的质量和相关性。有效的分块,即将文档拆分为可管理的片段的过程,对于优化 RAG 系统的检索和嵌入步骤至关重要。各种框架提供了几种分块方法,每种方法都有自己的优势和用例。在本文中,我介绍了一种新技术,它利用句子嵌入来识别文档中的主题变化,从而确保每个块都封装一个主题。这种方法增强了系统生成连贯且适合上下文的响应的能力,我们之前已经在主题建模的背景下探索过这一点。
了解检索增强生成 (RAG) 系统
检索增强生成 (RAG) 系统是一种复杂的机器学习模型,它将基于检索的技术与生成模型相结合。RAG 系统的主要目标是通过整合从大型数据集中检索到的信息来提高生成内容的质量和相关性。以下是 RAG 系统工作原理的细分:
- 检索阶段:系统首先根据输入查询检索相关文档或信息。此阶段依靠搜索算法和索引方法从大量数据中快速识别最相关的数据。
- 生成阶段:检索到相关文档后,将使用生成模型(通常是基于转换器的语言模型,如 GPT-4)来创建连贯且适合上下文的响应。该模型使用检索到的信息来确保生成的内容准确且信息丰富。
RAG 系统的混合特性使其特别适用于复杂或知识密集型任务,其中检索和生成的结合显著提高了整体性能。
文档拆分探索
在深入研究新分块技术的细节之前,了解文档拆分的标准方法至关重要。文档拆分是许多自然语言处理 (NLP) 任务的基础步骤,并且采用各种技术来确保以保留含义和上下文的方式划分文本。以下是一些常用方法,使用广泛采用的 Langchain 框架进行说明:
- 递归字符文本分割器:此方法通过基于字符递归地划分文本来分割文档。每个块的长度保持在指定长度以下,这对于具有自然段落或句子分隔的文档特别有用。此方法可确保块易于管理且易于处理,而不会丢失文档的固有结构。
- 标记分割器:此技术使用标记(可以是单词或子单词)来分割文档。在使用具有标记限制的语言模型时,它非常有用,因为它可以确保每个块都符合模型的限制。基于标记的分割通常用于 NLP 任务中,以在遵守模型限制的同时保持文本的完整性。
- 句子分割器:通过在句子边界处分割文档,此方法可保持文本的上下文完整性。句子通常代表完整的想法,因此这种方法非常适合需要连贯理解内容的任务。
- 正则表达式拆分器:此方法使用正则表达式来定义自定义拆分点。它提供了最高的灵活性,允许用户根据特定于其用例的模式拆分文档。例如,可以在每个特定关键字或标点符号实例处拆分文档。
- Markdown 拆分器:此方法专为 Markdown 文档量身定制,可根据标题、列表和代码块等 Markdown 特定元素拆分文本。它保留了 Markdown 文档的结构和格式,适合用于技术文档和内容管理。
高级分块方法
根据手头任务的具体要求,可以以各种方式应用分块。以下是满足不同需求的高级分块方法的概述:
- 按字符:此方法将文本分解为单个字符。它对于需要深入细致的文本分析的任务很有用,例如字符级语言模型或某些类型的文本预处理。
- 按字符 + SimplerLLM:此技术位于 SimplerLLM 库中,按字符对文本进行分块,同时保留句子结构。通过保持基于字符的块内句子的完整性,它可以提供更好、更有意义的片段。
- 按标记:将文本分割为标记(例如单词或子单词)是自然语言处理中的标准方法。基于标记的分块对于文本分类、语言建模和其他依赖标记化输入的 NLP 应用程序等任务至关重要。
- 按段落:按段落分块文本有助于维护文档的整体结构和流程。此方法非常适合需要更多上下文的任务,例如文档摘要或内容提取。
- 递归分块:这涉及反复将数据分解为较小的块,通常用于分层数据结构。递归分块对于需要多级分析的任务(例如主题建模或分层聚类)非常有用。
- 语义分块:对于需要理解数据上下文的任务来说,根据含义而不是结构元素对文本进行分组至关重要。语义分块利用句子嵌入等技术来确保每个块代表一个连贯的主题或想法。
- 代理分块:此方法侧重于根据所涉及的代理(例如人员或组织)识别和分组文本。它在信息提取和实体识别任务中很有用,在这些任务中,了解不同实体之间的角色和关系非常重要。
新颖的分块技术:主题感知句子嵌入
我介绍的新分块技术旨在使用句子嵌入来识别文档中主题的变化。通过识别主题发生变化的点,该技术可确保每个块都封装一个连贯的主题。此方法利用先进的 NLP 技术来增强 RAG 系统的性能:
- 句子嵌入:句子嵌入将句子转换为高维向量,以捕捉其语义。通过分析这些向量,我们可以识别主题发生变化的点。
- 主题检测:该技术使用专为主题建模而设计的算法,检测主题的变化并确定拆分文档的最佳点。这确保每个块在主题上都是连贯的。
- 增强的检索和嵌入:通过确保每个块代表一个主题,RAG 系统中的检索和嵌入步骤变得更加高效。每个块的嵌入更有意义,从而实现更好的检索性能和更准确的响应。
这种技术已在主题建模中得到证实,但它同样适用于 RAG 系统。通过采用这种方法,RAG 系统可以在其生成的内容中实现更高的准确性和相关性,使其更有效地完成复杂且知识密集型的任务。
使用 LangChain 的高级文档拆分技术
在上一节中,我们探讨了各种文档拆分方法及其在检索增强生成 (RAG) 系统中的应用。现在,让我们深入研究使用 LangChain 框架实现这些技术的实际示例。此外,我们将介绍一种新颖的主题感知分块方法,该方法利用句子嵌入来识别文档中的主题转变。
LangChain 中的文档拆分示例
以下是 LangChain 中文档拆分方法的一些示例,以及详细的解释和代码片段来演示它们的用法:
- 递归字符文本分割器
递归字符文本分割器方法根据字符数将文本分成多个块,确保每个块的长度不超过指定长度。此方法对于在文档中保持自然的段落或句子分隔非常有用。
# 从 langchain 导入 RecursiveCharacterTextSplitter 类
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 示例长文档文本
text = "您的长文档文本在此处..."
# 使用 1000 个字符的块大小和 50 个字符的重叠部分初始化 RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size= 1000 , chunk_overlap= 50 )
# 将文本拆分为块
chunks = splitter.split_text(text)
# 打印每个块
for chunk in chunks:
print (chunk)
2. Token拆分器
Token Splitter 方法根据 token(例如单词或子单词)划分文本。在使用具有 token 限制的语言模型时,这种方法非常有用。
# 从 langchain 导入 TokenSplitter 类
from langchain.text_splitter import TokenSplitter
# 示例长文档文本
text = "您的长文档文本在此处..."
# 使用最大 token 限制 512 初始化 TokenSplitter
splitter = TokenSplitter(max_tokens= 512 )
# 将文本拆分为块
chunks = splitter.split_text(text)
# 打印每个块
for chunk in chunks:
print (chunk)
3.句子分割器
句子分割器方法在句子边界处分割文本,保留文本的上下文完整性。此方法非常适合需要连贯完整思想的任务。
# 从 langchain 导入 SentenceSplitter 类
from langchain.text_splitter import SentenceSplitter
# 示例长文档文本
text = "您的长文档文本在此处..."
# 初始化 SentenceSplitter,每个块的最大长度为 5 个句子
splitter = SentenceSplitter(max_length= 5 )
# 将文本拆分为块
chunks = splitter.split_text(text)
# 打印每个块
for chunk in chunks:
print (chunk)
4.正则表达式分割器
Regex Splitter 方法使用正则表达式来定义自定义分割点,为各种用例提供高度的灵活性。
# 从 langchain 导入 RegexSplitter 类
from langchain.text_splitter import RegexSplitter
# 示例长文档文本
text = "您的长文档文本在此处..."
# 使用模式初始化 RegexSplitter,在双换行符处拆分文本
splitter = RegexSplitter(pattern= r'\n\n+' )
# 将文本拆分为块
chunks = splitter.split_text(text)
# 打印每个块
for chunk in chunks:
print (chunk)
5. Markdown 分割器
Markdown Splitter 方法是针对 markdown 文档量身定制的,根据 markdown 特定元素(如标题、列表和代码块)拆分文本。
# 从 langchain 导入 MarkdownSplitter 类
from langchain.text_splitter import MarkdownSplitter
# 长 markdown 文档示例文本
text = "您的长 markdown 文档在此处..."
# 初始化 MarkdownSplitter
splitter = MarkdownSplitter()
# 将文本拆分为块
chunks = splitter.split_text(text)
# 打印每个块
for chunk in chunks:
print (chunk)
引入一种新颖的主题感知分块方法
将大型文档分割成连贯的主题部分是数字内容分析中的一项重大挑战。如上所述,传统方法通常难以准确检测细微的主题变化。我们的新方法利用句子嵌入来增强分割过程,提供更精确、更有意义的区块。
核心挑战
大型文档(例如学术论文、长篇报告和详细文章)通常包含多个主题。传统的分割技术(从简单的基于规则的方法到高级机器学习算法)都难以识别主题转换的精确点。这些方法通常会错过细微的转换或错误地识别它们,从而导致部分内容支离破碎或重叠。
利用句子嵌入
我们的方法采用 Sentence-BERT (SBERT) 为单个句子生成嵌入。这些嵌入是封装句子语义内容的密集向量表示。
- 生成嵌入
SBERT 用于为文档中的每个句子生成嵌入。这些嵌入可以捕捉句子的语义,使我们能够衡量它们的相似性。
from sentence_transformers import SentenceTransformer
# 例句
sentences = [ "句子 1..." , "句子 2..." , ...]
# 初始化 SBERT 模型
model = SentenceTransformer( 'paraphrase-MiniLM-L6-v2' )
# 为每个句子生成嵌入
embeddings = model.encode(sentences)
2. 计算相似度
句子之间的相似度使用余弦相似度或其他距离测量方法(如曼哈顿距离或欧几里得距离)来衡量。这有助于识别连续句子之间的连贯性。
from sklearn.metrics.pairwise import cosine_similarity
# 计算嵌入之间的余弦相似度
similarity_matrix = cosine_similarity(embeddings)
3.差距得分和平滑
为了检测主题转换,我们定义了一个参数n
来指定要比较的句子数量。该算法根据余弦相似度计算差距分数。
import numpy as np
# 定义参数 n
n = 2
# 计算差距分数
gap_scores = []
for i in range ( len (embeddings) - n):
similarity = cosine_similarity(embeddings[i:i+n], embeddings[i+n:i+ 2 *n])
gap_scores.append(np.mean(similarity))
为了解决差距分数中的噪音问题,我们采用了平滑算法。窗口大小k
决定了平滑的程度。
# 定义窗口大小 k
k = 3
# 平滑差距分数
smoothed_gap_scores = np.convolve(gap_scores, np.ones(k)/k, mode= 'valid' )
4.边界检测
分析平滑后的差距分数以识别局部最小值,这表明潜在的主题转换。c
使用阈值来确定重要边界。
# 检测局部最小值
local_minima = (np.diff(np.sign(np.diff(smoothed_gap_scores))) > 0 ).nonzero()[ 0 ] + 1
# 设置阈值 c
c = 1.5
# 识别显著边界
significance_boundaries = [i for i in local_minima if smoothed_gap_scores[i] < np.mean(smoothed_gap_scores) - c * np.std(smoothed_gap_scores)]
5.聚类片段
对于较长的文档,类似的主题可能会重复出现。为了解决这个问题,该算法将具有类似内容的片段聚类,从而减少冗余并确保每个主题都有唯一的表示。
from sklearn.cluster import KMeans
# 将文本段转换为嵌入
segment_embeddings = [np.mean(embeddings[start:end], axis= 0 ) for start, end in zip (significant_boundaries[:- 1 ], significance_boundaries[ 1 :])]
# 应用聚类
kmeans = KMeans(n_clusters= 5 )
clusters = kmeans.fit_predict(segment_embeddings)
未来发展方向
该方法提出了一种复杂的文档分割方法,将传统原理与尖端的句子嵌入相结合。未来的研究可以探索以下领域以进一步增强该方法:
- 自动参数优化:利用机器学习技术动态调整参数。
- 广泛的数据集试验:在多样化、大型数据集上测试该方法以验证其有效性。
- 实时分割:探索动态文档的实时应用。
- 模型改进:集成更新的变压器模型以增强性能。
- 多语言分割:使用多语言 SBERT 将该方法应用于不同的语言。
- 分层分割:调查多个层次的分割以进行详细的文档分析。
- 用户界面开发:创建交互式工具,以便更轻松地调整分割结果。
- 与NLP任务的集成:将算法与其他自然语言处理任务相结合。
结论
我们的方法为大型文档中的精确主题建模提供了一种强大而有效的解决方案。通过利用 SBERT 和先进的平滑和聚类技术,这种方法比传统的文档分割方法有了显著的改进。这项创新提高了 RAG 系统的性能,使它们能够为复杂且知识密集型的任务生成更相关、更连贯的内容。