首页 >科技周边 >人工智能 >拉格的晚期:与Jina AI实施

拉格的晚期:与Jina AI实施

尊渡假赌尊渡假赌尊渡假赌
尊渡假赌尊渡假赌尊渡假赌原创
2025-03-02 09:05:11264浏览

Late Chunking for RAG: Implementation With Jina AI

检索增强生成 (RAG) 应用中,始终存在两种方法之间的权衡:嵌入整个文档以获得更好的上下文,或将其分解成较小的块以实现更精确的检索。

嵌入整个文档可以捕捉全局信息,但可能会丢失重要细节;而较短的块可以保留细节,但常常会忽略整体上下文。

延迟分块提供了一种解决方案,它在保持完整文档上下文的同时,将其分割成更小、更容易处理的块。

本文将介绍延迟分块作为传统朴素分块方法的更好替代方案,并逐步演示其实现方法。

使用 LangChain 的 RAG

使用检索增强生成 (RAG) 和 LangChain 集成外部数据与大型语言模型 (LLM)。探索课程

RAG 中朴素分块及其局限性

在 RAG 管道中,文档在嵌入并存储到向量数据库之前会被分解成较小的块。每个块都独立处理,并在查询时用于检索。然而,这种“朴素分块”方法常常会丢失重要的长距离上下文。

问题在于,传统的分块方法在分割文档时没有考虑信息的关联方式。例如,在关于巴黎的文档中,“这座城市”这个短语可能最终与“巴黎”所在的块不同。如果没有完整的上下文,检索模型可能难以关联这些引用,从而导致结果不够准确。在长文档中,关键上下文分散在多个部分,这个问题更加严重。

延迟分块:在文档分割中保留上下文

延迟分块通过更改分割文档的时间来解决这个问题。延迟分块不是首先将文档分解成块,而是使用长上下文模型嵌入整个文档。只有在此之后,它才会将文档分割成较小的块。

延迟分块的主要优点:

  • 保持上下文:延迟分块通过首先嵌入整个文档来确保每个块都保留整体上下文。这样,文本中的引用和连接在块嵌入中保持完整。
  • 更好的检索:通过延迟分块创建的块嵌入更丰富、更准确,从而提高了 RAG 系统中的检索结果,因为模型对文档的理解更好。
  • 处理长文本:对于传统模型由于标记限制而无法一次处理的长文档非常有用。

使用像 Jina 的 jinaai/jina-embeddings-v2-base-en 这样的长上下文模型(支持最多 8192 个标记),延迟分块允许在将大型文本部分分割成块之前有效地嵌入它们。

实现延迟分块

这是一个使用 Jina 的长上下文嵌入模型实现延迟分块的分步指南。您可以在此处免费获取 Jina 的 API 密钥,我们将使用以下输入文本作为演示:

<code>input_text = """Berlin is the capital and largest city of Germany, both by area and by population.
Its more than 3.85 million inhabitants make it the European Union's most populous city, as measured by population within city limits.
The city is also one of the states of Germany, and is the third smallest state in the country in terms of area."""</code>

步骤 1:获取块和跨度注释

首先,使用您的 Jina API 密钥和下面的辅助函数将输入文本分解成块。这些块带有跨度注释,有助于稍后分割文档嵌入。Jina 的 API 使用段落或句子中断等自然边界来确保块有意义并保留其含义。

<code>import json
import requests

def custom_tokenize_jina_api(input_text: str):
    url = '<https:></https:>'
    headers = {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ENTER_YOUR_JINA_API_KEY'
    }
    data = {
        "content": input_text,
        "tokenizer": "o200k_base",
        "return_tokens": "true",
        "return_chunks": "true",
        "max_chunk_length": "1000"
    }
    # Make the API request
    response = requests.post(url, headers=headers, json=data)
    response_data = response.json()
    chunks = response_data.get("chunks", [])
    i = 1
    j = 1
    span_annotations = []
    for x in response_data['tokens']:
        if j == 1:
            j = len(x)
        else:
            j = len(x) + i
        span_annotations.append((i, j))
        i = j
    return chunks, span_annotations
chunks, span_annotations = custom_tokenize_jina_api(input_text)

print(chunks)
print(span_annotations)</code>
<code>['Berlin is the capital and largest city of Germany, both by area and by population.\n\n', "Its more than 3.85 million inhabitants make it the European Union's most populous city, as measured by population within city limits.\n\n", 'The city is also one of the states of Germany, and is the third smallest state in the country in terms of area.']
[(1, 17), (17, 44), (44, 69)]</code>

步骤 2:标记化文本并生成标记级文档嵌入

首先,使用与长上下文模型兼容的标记器,例如 Jina 的 embeddings-v2-base-en,将整个文档分解成标记。接下来,使用长上下文转换器模型为每个标记创建嵌入。这意味着文档中的每个单词或标记都会获得其独特的嵌入,以捕捉其含义。

<code>from transformers import AutoModel
from transformers import AutoTokenizer

# load model and tokenizer
tokenizer = AutoTokenizer.from_pretrained('jinaai/jina-embeddings-v2-base-en', trust_remote_code=True)
model = AutoModel.from_pretrained('jinaai/jina-embeddings-v2-base-en', trust_remote_code=True)
inputs = tokenizer(input_text, return_tensors='pt')
model_output = model(**inputs)
model_output[0].shape</code>
<code>torch.Size([1, 71, 768]) # 71 代表整个文档中的标记数</code>

步骤 3:延迟分块

一旦您拥有整个文档的标记嵌入,您就可以进行延迟分块了。使用步骤一中的跨度注释将这些标记嵌入分割成较小的块。然后,应用平均池化来平均每个块内的嵌入,为每个块创建一个单一嵌入。我们现在有了包含整个文档强大上下文信息的块嵌入。

<code>def late_chunking(
    model_output: 'BatchEncoding', span_annotation: list, max_length=None
):
    token_embeddings = model_output[0]
    outputs = []
    for embeddings, annotations in zip(token_embeddings, span_annotation):
        if (
            max_length is not None
        ):  # remove annotations which go bejond the max-length of the model
            annotations = [
                (start, min(end, max_length - 1))
                for (start, end) in annotations
                if start = 1
        ]
        pooled_embeddings = [
            embedding.detach().cpu().numpy() for embedding in pooled_embeddings
        ]
        outputs.append(pooled_embeddings)
    return outputs</code>
<code>embeddings = late_chunking(model_output, [span_annotations])[0]
len(embeddings)</code>
<code>3 # 与步骤 1 中的块数匹配</code>

步骤 4:延迟分块与传统分块结果的比较

为了了解延迟分块的优势,让我们将其与传统分块进行比较:

<code>embeddings_traditional_chunking = model.encode(chunks)</code>
<code>import numpy as np

cos_sim = lambda x, y: np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y))
q = "Berlin"
berlin_embedding = model.encode(q)

print(q)
print('\n')
for chunk, new_embedding, trad_embeddings in zip(chunks, embeddings, embeddings_traditional_chunking):
  print(chunk.strip())
  print(f'Late chunking:', cos_sim(berlin_embedding, new_embedding))
  print(f'Traditional chunking:', cos_sim(berlin_embedding, trad_embeddings))
  print("------------------------------------------------------------------")</code>
<code>Berlin

Berlin is the capital and largest city of Germany, both by area and by population.
Late chunking: 0.84954596
Traditional chunking: 0.84862185
------------------------------------------------------------------
Its more than 3.85 million inhabitants make it the European Union's most populous city, as measured by population within city limits.
Late chunking: 0.82489026
Traditional chunking: 0.70843375
------------------------------------------------------------------
The city is also one of the states of Germany, and is the third smallest state in the country in terms of area.
Late chunking: 0.84980094
Traditional chunking: 0.7534553
------------------------------------------------------------------</code>

正如您在第二个和第三个块中看到的,与单词“Berlin”相比,传统分块显示相似度评分为 70-75%。然而,使用延迟分块(保持整个文档的上下文),这些分数上升到 82-84%。这表明延迟分块在保留上下文和创建更有意义的嵌入方面做得更好,从而产生更准确的搜索结果。

结论

延迟分块是对文档检索系统(尤其是在 RAG 管道中)的重大改进。通过等到文档完全嵌入后再分割文档,延迟分块在每个块中保留了完整的上下文。这导致更准确和更有意义的嵌入。

项目:为技术文档构建 RAG 聊天机器人

使用 LangChain 实现 RAG 以创建用于回答有关技术文档问题的聊天机器人。探索项目

以上是拉格的晚期:与Jina AI实施的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn