RAG 分块技术:提升文档处理能力

2024年07月04日 由 alex 发表 361 0

将大型文档分割成较小的部分是一项关键而又复杂的任务,会对检索-增强生成(RAG)系统的性能产生重大影响。这些系统旨在通过结合基于检索和基于生成的方法来提高输出的质量和相关性。有效的分块(或将文档分割成易于管理的片段的过程)对于优化 RAG 系统的检索和嵌入步骤至关重要。各种框架提供了多种分块方法,每种方法都有自己的优势和用例。在本文中,我介绍了一种新颖的技术,它利用句子嵌入来识别文档中的主题变化,从而确保每个分块都包含一个主题。这种方法增强了系统生成连贯且与上下文相适应的回复的能力。


了解检索增强生成(RAG)系统

检索-增强生成(RAG)系统是一种复杂的机器学习模型,它将基于检索的技术与生成模型相结合。RAG 系统的主要目标是通过整合从大型数据集中检索到的信息,提高生成内容的质量和相关性。以下是 RAG 系统工作原理的详细介绍:


  1. 检索阶段: 系统首先根据输入查询检索相关文档或信息。这一阶段依靠搜索算法和索引方法,从大量数据中快速识别出最相关的数据。
  2. 生成阶段: 一旦检索到相关文档,系统就会使用一个生成模型(通常是基于转换器的语言模型,如 GPT-4)来创建一个连贯且与上下文相适应的回复。该模型使用检索到的信息,确保生成的内容准确且信息量大。


RAG 系统的混合性质使其对复杂或知识密集型任务特别有效,检索和生成的结合大大提高了整体性能。


探索文档拆分选项

在深入研究新分块技术的具体细节之前,了解文档分割的标准方法至关重要。文档拆分是许多自然语言处理(NLP)任务中的基础步骤,我们采用了各种技术来确保文本的拆分方式能够保留意义和上下文。下面是一些常见的方法,使用广泛采用的 Langchain 框架进行说明:


  1. 递归字符文本分割器: 这种方法根据字符递归分割文本,从而分割文档。每个分块的长度都不超过指定长度,这对于有自然段落或句子分隔的文档特别有用。这种方法可确保文件块易于管理和处理,同时不会丢失文件的固有结构。
  2. 标记分割器: 这种技术使用标记来分割文档,标记可以是单词或子单词。在使用有标记限制的语言模型时,这种方法非常有用,因为它能确保每个语块都符合模型的限制条件。基于标记的分割常用于 NLP 任务,以在遵守模型限制的同时保持文本的完整性。
  3. 句子分割器: 通过在句子边界分割文档,这种方法可以保持文本上下文的完整性。句子通常代表完整的思想,因此这种方法非常适合需要连贯理解内容的任务。
  4. 正则表达式分割器: 这种方法使用正则表达式定义自定义分割点。它具有最高的灵活性,允许用户根据使用案例的特定模式分割文档。例如,可以在每个特定关键词或标点符号的实例处分割文档。
  5. Markdown拆分器:该方法专为 Markdown 文档量身定制,可根据标题、列表和代码块等 markdown 特定元素分割文本。它能保留 Markdown 文档的结构和格式,因此适用于技术文档和内容管理。


高级分块方法

根据手头任务的具体要求,分块法可以有多种应用方式。以下是满足不同需求的高级分块法概览:


  1. 按字符: 这种方法将文本分解为单个字符。它适用于需要深度和细粒度文本分析的任务,如字符级语言模型或某些类型的文本预处理。
  2. 按字符 + SimplerLLM:SimplerLLM 库中的这种技术可在保留句子结构的同时按字符对文本进行分块。它能在基于字符的分块中保持句子的完整性,从而提供更好、更有意义的分段。
  3. 按标记: 将文本分割成标记(如单词或子单词)是自然语言处理中的一种标准方法。基于标记的分块对于文本分类、语言建模和其他依赖标记化输入的 NLP 应用等任务至关重要。
  4. 按段落: 按段落划分文本块有助于保持文档的整体结构和流程。这种方法非常适合需要较大上下文的任务,如文档摘要或内容提取。
  5. 递归分块: 这包括反复将数据分解成更小的块,通常用于分层数据结构。递归分块有利于需要多层次分析的任务,如主题建模或分层聚类。
  6. 语义分块: 基于意义而非结构元素对文本进行分组,对于需要了解数据上下文的任务来说至关重要。语义分块利用句子嵌入等技术,确保每个分块代表一个连贯的主题或观点。
  7. 代理分块法: 这种方法侧重于根据所涉及的代理(如人或组织)对文本进行识别和分组。它适用于信息提取和实体识别任务,在这些任务中,理解不同实体之间的角色和关系非常重要。


新颖的分块技术: 主题感知句子嵌入

我介绍的新分块技术旨在利用句子嵌入识别文档中主题的变化。通过识别主题变化点,该技术可确保每个分块都包含一个单一、连贯的主题。这种方法利用先进的 NLP 技术来提高 RAG 系统的性能:


  1. 句子嵌入: 句子嵌入将句子转化为高维向量,以捕捉其语义。通过分析这些向量,我们可以确定主题变化的点。
  2. 主题检测: 该技术使用专为主题建模设计的算法来检测主题的变化,并确定分割文档的最佳点。这就确保了每个分块在主题上的一致性。
  3. 增强检索和嵌入: 通过确保每个分块代表一个主题,RAG 系统中的检索和嵌入步骤变得更加高效。每个信息块的嵌入更有意义,从而提高检索性能和响应准确性。


这项技术已经在主题建模中得到了验证,但它同样适用于 RAG 系统。通过采用这种方法,RAG 系统可以在其生成的内容中实现更高的准确性和相关性,使其在复杂的知识密集型任务中更加有效。


使用 LangChain 的高级文档分割技术

我们探讨了各种文档分割方法及其在检索增强生成(RAG)系统中的应用。现在,让我们深入探讨使用 LangChain 框架实现这些技术的实际案例。此外,我们还将介绍一种新颖的主题感知分块方法,该方法利用句子嵌入来识别文档中的主题转移。


LangChain 中的文档拆分示例

以下是 LangChain 中文档分割方法的一些示例,并附有详细解释和代码片段以演示其用法:


1. 递归字符文本分割器

Recursive Character Text Splitter(递归字符文本分割器)方法会根据字符数将文本分割成若干小块,确保每个小块都低于指定长度。这种方法适用于在文档中保持自然的段落或句子分隔。


# Importing the RecursiveCharacterTextSplitter class from langchain
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Example long document text
text = "Your long document text goes here..."
# Initializing the RecursiveCharacterTextSplitter with a chunk size of 1000 characters and an overlap of 50 characters
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=50)
# Splitting the text into chunks
chunks = splitter.split_text(text)
# Printing each chunk
for chunk in chunks:
    print(chunk)


2. 标记符分割器

标记符分割器方法根据标记符(如单词或子单词)来分割文本。这种方法有利于使用有标记限制的语言模型。


# Importing the TokenSplitter class from langchain
from langchain.text_splitter import TokenSplitter
# Example long document text
text = "Your long document text goes here..."
# Initializing the TokenSplitter with a maximum token limit of 512
splitter = TokenSplitter(max_tokens=512)
# Splitting the text into chunks
chunks = splitter.split_text(text)
# Printing each chunk
for chunk in chunks:
    print(chunk)


3. 句子分割器

Sentence Splitter(句子分割器)方法在句子边界分割文本,保留文本上下文的完整性。这种方法非常适合需要连贯和完整思想的任务。


# Importing the SentenceSplitter class from langchain
from langchain.text_splitter import SentenceSplitter
# Example long document text
text = "Your long document text goes here..."
# Initializing the SentenceSplitter with a maximum length of 5 sentences per chunk
splitter = SentenceSplitter(max_length=5)
# Splitting the text into chunks
chunks = splitter.split_text(text)
# Printing each chunk
for chunk in chunks:
    print(chunk)


4. 正则表达式分割器

Regex Splitter 方法使用正则表达式定义自定义分割点,为各种用例提供了高度灵活性。


# Importing the RegexSplitter class from langchain
from langchain.text_splitter import RegexSplitter
# Example long document text
text = "Your long document text goes here..."
# Initializing the RegexSplitter with a pattern to split text at double newline characters
splitter = RegexSplitter(pattern=r'\n\n+')
# Splitting the text into chunks
chunks = splitter.split_text(text)
# Printing each chunk
for chunk in chunks:
    print(chunk)


5. 标记符分割器

Markdown Splitter 方法专为 Markdown 文档量身定制,可根据标题、列表和代码块等 Markdown 特定元素分割文本。


# Importing the MarkdownSplitter class from langchain
from langchain.text_splitter import MarkdownSplitter
# Example long markdown document text
text = "Your long markdown document goes here..."
# Initializing the MarkdownSplitter
splitter = MarkdownSplitter()
# Splitting the text into chunks
chunks = splitter.split_text(text)
# Printing each chunk
for chunk in chunks:
    print(chunk)


介绍一种新颖的主题感知分块方法

在数字内容分析中,将大规模文档分割成基于主题的连贯部分是一项重大挑战。上述传统方法往往难以准确检测到微妙的主题变化。我们的新方法利用句子嵌入来增强分割过程,从而提供更精确、更有意义的分块。


核心挑战

学术论文、冗长报告和详细文章等大型文档通常包含多个主题。传统的分割技术,从简单的基于规则的方法到先进的机器学习算法,都很难准确识别主题转换点。这些方法经常会错过微妙的转换或错误地识别它们,从而导致章节支离破碎或重叠。


利用句子嵌入

我们的方法采用句子嵌入式嵌入(Sentence-BERT,SBERT)来生成单个句子的嵌入。这些嵌入是密集的向量表示,囊括了句子的语义内容。


1. 生成嵌入词

SBERT 用于为文档中的每个句子生成嵌入。这些嵌入词可以捕捉句子的语义,让我们可以测量它们的相似性。


from sentence_transformers import SentenceTransformer
# Example sentences
sentences = ["Sentence 1...", "Sentence 2...", ...]
# Initializing the SBERT model
model = SentenceTransformer('paraphrase-MiniLM-L6-v2')
# Generating embeddings for each sentence
embeddings = model.encode(sentences)


2. 计算相似度

句子之间的相似度使用余弦相似度或其他距离测量方法(如曼哈顿距离或欧几里得距离)进行测量。这有助于识别连续句子之间的一致性。


from sklearn.metrics.pairwise import cosine_similarity
# Calculating cosine similarity between embeddings
similarity_matrix = cosine_similarity(embeddings)


3. 差距分数和平滑

为了检测主题转换,我们定义了一个参数 n,用于指定需要比较的句子数量。算法根据余弦相似度计算差距分数。


import numpy as np
# Define the parameter n
n = 2
# Calculate gap scores
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 决定了平滑的程度。


# Define the window size k
k = 3
# Smoothing the gap scores
smoothed_gap_scores = np.convolve(gap_scores, np.ones(k)/k, mode='valid')


4. 边界检测

对平滑后的差距得分进行分析,以确定局部最小值,这表示潜在的话题转换。使用阈值 c 来确定重要的边界。


# Detecting local minima
local_minima = (np.diff(np.sign(np.diff(smoothed_gap_scores))) > 0).nonzero()[0] + 1
# Setting the threshold c
c = 1.5
# Identifying significant boundaries
significant_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
# Convert segments into embeddings
segment_embeddings = [np.mean(embeddings[start:end], axis=0) for start, end in zip(significant_boundaries[:-1], significant_boundaries[1:])]
# Apply clustering
kmeans = KMeans(n_clusters=5)
clusters = kmeans.fit_predict(segment_embeddings)


结论

我们的方法为在大型文档中进行准确的主题建模提供了一种稳健高效的解决方案。通过利用 SBERT 和先进的平滑与聚类技术,这种方法比传统的文档分割方法有了显著的改进。这一创新提高了 RAG 系统的性能,使其能够为复杂的知识密集型任务生成更相关、更连贯的内容。

文章来源:https://medium.com/gopenai/mastering-rag-chunking-techniques-for-enhanced-document-processing-8d5fd88f6b72
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消