为什么要分段?
即便大模型开始普通支持更大的上下文,但 RAG 技术目前仍然具有不可替代的价值,RAG 需要外部知识库。外部知识文档往往比较长,可能是包含几十页甚至数百页的内容,如果直接使用会存在以下问题:
- 大模型处理的上下文长度有限:大模型在预训练过程都有上下文长度限制,如果超过长度限制大模型会将超出部分丢弃,从而影响回答的性能表现。(注:目前很多大模型已经支持 192 K 甚至更大的超长上下文窗口+搜索增强知识库,但基于成本和性能考虑,大文档分 chunk 依然是 RAG 方案必须包含的环节)。
- 语义杂揉不利于任务检索:长文档中各个片段的语义之前可能存在较大的差异,如果当成一个整体来做知识检索会存在语义的杂揉,应当将长文档切分成更多的小块,促使每个小块内部表意一致,块之间表意存在多样性,从而更充分的发挥知识检索的作用
所以我们需要根据一定策略将文本切分为小块,以便适应大模型的上下文窗口,同时提高知识检索的精度。
将大文档分割成较小的分块是一项关键而复杂的任务,对 RAG 系统的性能有着重大的影响。一般地,RAG 系统旨在通过将基于检索的方法和基于生成的方法相结合,提高产出的质量和相关性。
文本分块(chunk)最核心的目的就是把相同语义的 token 聚集在一起,不同语义的 token 互相分开,利于后续的 retrieve 和 rerank。举个例子:我们有一个 word 文档,分为多个段落,每个段落都是一个问题的问答对。那么显然把一个问答对作为一个 chunk 划分是最理想的结果。
但是实际情况要复杂的多:图像的语义怎么描述?代码处理?不同类型文件差异?干扰项如何消除?表格怎么正确识别,超长段落如何处理?段落间关系怎么处理等等!
现有的分段技术
Langchain 作为一个 LLM 协调框架,内置了一些用于分块以及加载文档的工具,提供了很多可以开箱即用的 chunk 方法:
- CharacterTextSplitter
- RecursiveCharacterTextSplitter
- Split by tokens
- Semantic Chunking
- HTMLHeaderTextSplitter
- MarkdownHeaderTextSplitter
- RecursiveJsonSplitter
幸运的是:langChain和llamaIndex已经实现了Semantic Chunk。然而不幸的是:这两者提取语义embedding用的都是openAI的接口,要收费不说,大陆地区还面临被封API的风险,所以最好自己实现Semantic Chunk的功能!
已经有许多 python 实现代码,目前滑动窗口的分段法比较受推崇。
进阶的处理框架
RAPTOR:
RAPTOR 模型提出了一种创新的策略。它通过递归地进行文本片段的向量化、聚类和摘要生成,构建了一个树状索引结构。这种结构不仅捕捉了文档的高层次主题,还保留了低层次的细节,允许基于语义相似性而非仅仅是文本顺序对节点进行分组。这样的树状结构使得 RAPTOR 能够在不同的抽象层次上加载文档的上下文片段,从而有效地回答不同层次的问题。
GraphRAG:
2024 年 4 月微软推出 GraphRAG,并于 7 月 2 日开源。GraphRAG 仍然沿袭了 RAG 的思路,即通过检索来增强模型的准确性。不过,与 RAG 不同的是,GraphRAG 还引入了“知识图谱”(Knowledge Graph) 技术,以增强模型的“检索”能力,以实现对复杂信息的高效和可靠检索,从而提高 LLM 问答系统对于复杂信息的答案生成的准确性。
大模型 RAG:文档分块方案与 RAG 全流程
原文链接: https://xie.infoq.cn/article/d15dc2f986801a54112abb338
Chunk的方法有很多,最常见的就是按照固定长度chunk,但这样做容易把同样语义的文本拦腰截断;稍微变通一点就是按照句号、分号、问号、段落分割,但这样也容易把同样语义的句子分开,和按固定长度分割没有本质区别!
怎么才能按照语义切割文本?
既然语义相似的句子一般都在附近,距离不会太远,那就近计算附近语句embedding的距离不久行了么?改进后的方案如下(核心思路是滑动窗口,为了解决差异分数中的噪声,可以采用平滑算法,窗口大小 k 决定了平滑的程度,通过分析平滑后的差距得分来识别局部极小值,这表明潜在的话题转换,可以用阈值来确定重要的边界):
- 还是先简单粗暴按照句号、分号、问好、感叹号、换行符等分割文本,形成一个个的句子,用sen1、sen2、sen3. … senN表示
- 从sen1开始,以此和前后一个句子组合,形成combined_sentence,比如sen1+sen2 = combined_sentence1,sen1+sen2+sen3=combined_sentence2,sen2+sen3+sen4=combined_sentence3,以此类推
- 以此计算combined_sentence1、combined_sentence2、combined_sentence3 … combined_sentenceN之间的相似度,如果相似度突然变化,那么新加入sen的语义肯定不同,从这里截断!
举例如下:前面三个combined_sentence的距离都比较近,第4个combined_sentence和第三个的距离突然增加很多,说明sen4和sen1sen3之间的语义肯定差异较大,可以从sen4开始分割,sen1sen3合并成一个chunk!
原文链接: LLM大模型: RAG的最优chunk方法 — 利用本地离线LLM的embedding实现Semantic Chunking
面向LLM 的分块策略
Chunking Strategies for LLM Applications | Pinecone 讨论了在构建与大型语言模型(LLM)相关的应用程序时,如何通过分块(chunking)策略来优化内容的相关性。
-
分块(Chunking)的重要性:
- 分块是将大型文本分解为更小的段落,以优化从向量数据库检索内容的相关性。
- 正确的分块策略可以确保搜索结果准确捕捉用户查询的精髓。
-
分块的应用场景:
- 语义搜索:通过有效的分块策略,可以确保搜索结果准确地反映用户查询的内容。
- 对话代理:使用嵌入的分块构建对话代理的上下文,基于知识库,确保代理基于可信信息。
-
分块方法:
- 固定大小分块:决定分块中的标记数量,并可选地决定分块之间是否有重叠。
- 内容感知分块:利用内容的特性进行更复杂的分块,例如句子分块、递归分块、特殊格式内容(如 Markdown 和 LaTeX)的分块。
- 语义分块:基于句子组的嵌入来创建主题或话题一致的分块。
-
分块考虑因素:
- 内容的性质、使用的嵌入模型、用户查询的预期长度和复杂性、检索结果在特定应用中的使用方式。
-
确定最佳分块大小:
- 预处理数据以确保质量。
- 选择一系列潜在的分块大小进行测试。
- 评估每种分块大小的性能,通过迭代测试不同分块大小对不同查询的性能,以确定最佳分块大小。
结论:
- 分块是一个简单的过程,但在特定情况下可能会面临挑战。
- 没有一种分块策略适用于所有情况,需要根据具体用例来确定。
上述文章发表于 23 年 6 月,内容已经有些过时:如果提示词算得上工程的话,目前分块已经复杂到算是一个工程了(知识工程?),Chunking 难度显然是大于 Prompt Engineering。
释放语义分块的力量
最大化应用潜力通常需要将大块文本分解为更易消化的部分。这个被称为语义分块的过程,在增强 ChatGPT 等模型性能和促进应用的长期记忆方面发挥了关键作用。
From Fixed-Size to NLP Chunking - A Deep Dive into Text Chunking Techniques的主要观点:
-
分块的重要性:分块是确保搜索结果准确捕捉用户查询本质的关键技术,有助于提高语义搜索和语言模型的性能。
-
影响分块策略的因素:
- 文本的大小:分块单元和大小应根据文本的性质进行调整。
- 用户查询的长度和复杂性:长查询或复杂查询通常从较小的分块长度中受益。
- 检索结果的应用:搜索结果在应用中的使用方式对分块大小有重要影响。
-
分块方法:介绍了多种分块方法,每种方法都有其特定的应用场景和优缺点。
-
添加额外上下文:通过添加元数据或摘要等形式的额外上下文,可以增加每个分块的价值,并改善对文本的整体理解。
文章提出的比较新颖的方法:
结构感知分割(按句子、段落、章节、章节)
使用场景:
- 需要良好理解上下文和语义的任务,如文本摘要、情感分析和文档分类。
优点:
- 尊重文本的自然语言边界,避免在中间切断单词、句子或思想。
- 保持每个分块内信息的语义完整性。
缺点:
- 处理结构复杂性不同的文本可能具有挑战性。
- 对于较大的结构单位,如章节或章节,不能保证分块内完美的语义一致性。
NLP分块:追踪主题变化
使用场景:
- 需要理解语义上下文和主题连续性的任务,如文本摘要、情感分析和文档分类。
优点:
- 通过追踪主题变化,确保每个分块在语义上与其他分块不同,捕捉文本的固有结构和含义。
缺点:
- 需要高级NLP技术来准确检测主题变化,增加了实现的复杂性。
- 分块的准确性严重依赖于所使用的主题建模和检测技术的有效性。
内容感知分割(Markdown、LaTeX、HTML)
使用场景:
- 处理结构化文档或具有清晰格式的内容,如技术文档、学术论文或网页。
优点:
- 确保不同类型的内容不会在单个分块中混合。
- 尊重并保持每个分块内内容的完整性和上下文。
缺点:
- 需要理解和解析结构化文档格式的特定语法,增加了实现的复杂性。
- 可能不适用于缺乏清晰结构划分的文档或纯文本文档。
# Content-Defined Chunking
Intro to Content-Defined Chunking 介绍了内容定义分块,探讨了内容定义分块(CDC),这是一种基于内容的分块策略,通过寻找字节序列中的模式来确定分块边界。
内容定义分块(CDC):
- CDC根据内容来确定分块边界,通常使用滚动哈希函数来识别字节序列中的模式。
- CDC能够避免FSC中的边界偏移问题,提高数据去重比率,但计算成本更高。
最佳实践
根据经验,如果文本块尽量是语义独立的,也就是没有对上下文很强的依赖,这样对语言模型来说是最易于理解的。因此,为语料库中的文档找到最佳块大小对于确保搜索结果的准确性和相关性至关重要。
考虑分块长度设置时要思考:我们到底是想要结果中返回单独的一行文字,还是整个 section 内容?这就需要根据使用场景进行判断。如果一个块包含的内容过多,向量就会失去对特定内容的准确描述。如果分块太小,则会失去数据的上下文。
选择合适的分块方法取决于用例和应用的具体需求。每种方法都有其优势和局限性,理解这些对于实施有效的分块策略至关重要。为分块添加额外上下文可以进一步提升每个分块的价值,并改善对文本的整体理解。实验性策略如关键词标记、情感分析和实体识别为分块提供了新的探索方向。