昨天,我们谈了句子分段,我们再来回顾一下段落的分段方法,目前已经有其他方案,图来自于:https://www.rungalileo.io/blog/mastering-rag-advanced-chunking-techniques-for-llm-applications,可以看到其中的一些优劣势;
例如:
1、递归分块:文档根据段落分隔符、新行、空格和单个字符等分隔符的层级进行分割,使用Langchain的RecursiveCharacterTextSplitter函数(https://api.python.langchain.com/en/latest/character/langchain_text_splitters.character.RecursiveCharacterTextSplitter.html)。
2、语义分块:段落块被嵌入了OpenAI的text-ada-embedding-002。通过识别相邻块嵌入距离发生显著变化的断点来分割文本,如果两个连续段落的嵌入向量之间的距离超过了某个阈值,这可能表明它们在语义上有很大的不同,因此可以在这个位置设置断点。当然,这个的核心点在于阈值。
一旦确定了断点,就可以根据这些断点将文本分割成独立的块。每个块在语义上相对独立,但可能仍然与前一个或后一个块有联系。这对于在更大的文本体中识别连贯且相关的信息块非常有用。
这块可以参考:https://github.com/agamm/semantic-split
3、命题分块:这其实已经是基于大模型的方式来切分了。文本按照论文 《Dense X Retrieval》(https://arxiv.org/abs/2312.06648) 中介绍的方式进行分割,其是一种新的检索单元——命题(proposition),就是将一个文本送入到chagpt等大模型中,生成命题,,核心在于prompt的设计:
然后,在检索生成阶段,将其作为混合来源之一参与召回。
问题2:基于大模型进行动态分块的LumberChunker思想
而针对较长规模的叙事文本而言,也有另一个工作,《LumberChunker: Long-Form Narrative Document Segmentation》(https://arxiv.org/pdf/2406.17526) 这个工作提出了一个名为LumberChunker的文本分割方法,利用大型语言模型(LLM)动态地将长篇叙事文档分割成语义独立的部分。
我们可以重点看几个点:
1、先看实现思想
这种方法的核心思想是,通过允许内容块具有动态大小,可以更好地捕捉内容的语义独立性,从而提高检索效率。LumberChunker通过迭代地提示LLM,在一系列连续段落中识别内容开始转变的点,确保每个分割后的块在语义上是连贯的,但与相邻块有所区别,从而增强了信息检索的有效性。
如下图所示,LumberChunker遵循一个三步流程。
首先,按段落对文档进行分割。将目标文档按照段落进行分割,每个段落被赋予一个唯一的递增ID编号。
其次,通过追加连续的块,创建一个组(Gi),直到超过预定义的标记计数θ;将这些段落按顺序串联起来,直到它们的总标记数超过预定义的阈值θ。
值得注意的是,这个阈值θ是一个经验值,旨在避免将相关较大的段落分割开,同时确保它不会太大以至于用过多的上下文超出模型最大长度,影响其推理准确性。例如,实验表明,θ=550时,LumberChunker在所有测试的k值上都达到了最高的DCG@k得分,表明大约550个标记的提示在捕获上下文和段落长度之间实现了有效平衡。
最后,将段落组合Gi作为输入提供给LLM(例如Gemini 1.0-Pro),并指示LLM找出Gi中内容与前文显著不同的特定段落。这种检测标志着一个块的结束。
这个的细节在于prompt的设计:
文档继续以循环方式被分割成块,每个新的Gi+1组的起始点是前一次迭代中识别出的段落。这个过程在整个文档中重复进行。
2、再看其实现效果
为了评估LumberChunker的性能,作者们创建了一个新的基准测试GutenQA,它包含3000对问题-答案对,这些数据对是从Project Gutenberg网站上的100本公共领域叙事书籍中手动提取的。
其中关于其RAG的设计框架也有一些借鉴的点:
构建了一个特别为传记类书籍量身定制的基于RAG的问答流程,采用了一种混合检索格式,结合了OpenAI text-ada-embedding-002密集嵌入和BM25。
如图4所示:
1)查询路由和文档集成(Query Routing and Document Integration): 每个查询都经过一个检测器的评估,该检测器识别人名或事件的提及。如果检测器在查询中识别到相关提及,使用BM25算法检索前3个最相关的块。
如果没有检测到相关提及(承认偶尔的检测器失败),则作为预防措施检索单个文档。
同时,通过密集检索机制检索前15个块。这一步旨在通过访问BM25可能错过的深层语义关系来提高检索质量。
此外,其还实现了BM25检索的文档和密集检索的文档之间的交集检查,并删除了BM25中的重叠文档以避免冗余。然后,将BM25检索到的排名最高的文档优先放置在检索列表的顶部,第二和第三个(如果有的话)放在最后,确保检索策略的混合。
2)文档重新排序和重新排名(Document Re-Ordering and Re-Ranking):检索到的块被集成到ChatGPT(gpt-3.5-turbo)的上下文窗口中。如果上下文包含六个或更多的块,则采用一种策略,从中间点开始反转块的顺序。 这种重新排序旨在潜在地最小化模型的“中间丢失”问题,即模型对于长上下文中位于中间位置的信息的性能下降,但开始朝着末端恢复,形成一个U形的性能曲线。然后提示ChatGPT根据它们与查询的相关性递减来识别和重新排序文档。
3)最终答案生成(Final Answer Generation):在这最后一步生成响应。模型确定的前5个文档被保留用于最终答案生成。模型从顶级文档中综合信息,形成一个连贯且上下文准确的答案,旨在全面解决查询。
实验结果表明,LumberChunker在检索性能上超越了其他竞争性基线方法7.37%(在DCG@20指标上),并且当集成到RAG(检索增强生成)流程中时,LumberChunker证明比其他分块方法和竞争性基线(例如Gemini 1.5M Pro)更有效。
3、最终看看其方案评价
但是,其缺陷也很明显。正如该工作所说的,LumberChunker的局限性,包括它需要使用LLM,这使得它比其他传统方法更昂贵和更慢。
此外,LumberChunker是为叙事文本设计的,这些文本结构松散,能从语义文本解释中受益。然而,在处理像法律领域这样高度结构化的文本时,LumberChunker可能是一个过于复杂的解决方案。
代码:https://github.com/joaodsmarques/LumberChunker