Late Chunking:提高 RAG 在长上下文问答应用中的性能

2024年9月22日星期日

Late Chunking:先做全文嵌入(embedding),再分块(chunk)。

随着大语言模型(LLM)的热潮,越来越多人希冀借助大语言模型来帮助整理、优化自身庞大的知识体系,即所谓知识库,简单点来说让大语言模型能够基于知识库来回答用户的问题。针对于这类问题,有一个常见的解决方案——RAG。

但是当知识库内容较多,且需要从知识库整体来获取相关的信息时,RAG 可能就无能为例了。为了更好的解释这一点,我们先来了解下 RAG 是如何处理知识库的。

RAG 文本处理

在 RAG 流程中,将知识库数据加载到 RAG 系统中后,下一步就是将知识库数据中的文本向量化(verctorize)并保存到向量数据库中,这就是文本处理的流程,共分为两步:

  1. 文本分块(Text Chunking)
  2. 嵌入生成(Embedding Generation)

整个文本处理过程可以用下图来表示:

Naive Chunking

文本分块

在这一步骤中,长文本被分割成较小的块(chunk)。

分块可以基于不同的标准进行,例如:

  • 固定字符数(token)
  • 句子边界(sentence)
  • 段落边界
  • 语义单元

分块的目的是将大型文档分解成更小的、独立的单元,这些单元可以单独处理,同时仍然保留原始文本的上下文和含义。

嵌入生成

一旦文本被分成块,每个块都会被转换成一个数值向量,这个过程就是嵌入(Embedding)。

关于 Embedding 的讲解,可以观看下面的视频获得更直观的理解。

https://www.bilibili.com/video/BV1Hk4y1X7aG/

使用场景限制

当用户查询时,会将查询文字转为 embedding,然后与上图得到的每个 embedding 计算相似度,最终取匹配度高的几个 embedding 对应的 chunk ,交由大语言模型(LLM)总结回答。

问题也就随之而来:由于是匹配分块,当需要基于全文信息了解时,匹配到的少量分块无法满足全文信息的提取,因而大语言模型也就无从得到正确的答案。

基于上述 RAG 的工作原理,我们可以总结出 RAG 在使用场景上的一些限制:

  • 局部信息检索:RAG 擅长回答那些可以从单个或少量文本块中找到答案的问题,但对需要综合整个文档或多个文档的信息来回答的问题效果较差。
  • 上下文丢失:由于文本被分割成小块,可能会导致上下文信息的丢失,特别是当问题需要跨越多个块的信息时。
  • 长文档处理困难:对于非常长的文档,RAG 可能难以捕捉整体结构和主题,因为它主要依赖于局部相似性匹配。

Late Chunking

由 Jina 提出的 Late Chunking 方案相比传统方案显著提升了长文本信息检索的能力,简单来说,就是将原有的分块过程延后,利用长上下文能力的嵌入模型(Embedding Model),先对文本做嵌入,在进行分块。

让我们用一个具体的流程来对比两种解决方案:

  • Late Chunking

Late Chunking

  • Naive Chunking

Naive Chunking

但是,这并非万能的灵丹妙药,Late Chunking 仍有缺陷:

  • 需要硬件投入,无法利用现成的 Embedding API。

调用如 OpenAI 的 Embedding API,最终得到的不过是单一向量 (1, 1536),其中 1536 为向量维度。而 Late Chuking 需要将全文做 Embedding,得到的是全文向量(token_nums, 1536)。

token_nums 取决于你的全文 token 数量,以 jinaai/jina-embeddings-v2-base-en 支持的 8192 token 数量为例,加入向量维度为 1536,则单次计算得到的向量为 (8192,1536),然后将该向量分块,最终计算得到每个块的向量 (1, 1536)。

虽然相比于大语言模型所需的恐怖资源,嵌入模型(Embedding Model)所需资源不值一提,但对于一个 RAG 应用来说,还是带来了过高的运维成本,远没有调用一的 HTTP API 简单。