为了账号安全,请及时绑定邮箱和手机立即绑定

先进检索增强生成:从理论到LlamaIndex实现详解

如何通过在Python中实现针对性的高级RAG技术来克服初级RAG管道的局限性

Advanced Retrieval-Augmented Generation \(RAG\) implements pre-retrieval, retrieval, and post-retrieval optimizations to a naive RAG pipeline

Naive RAG与高级RAG的区别(作者创作,灵感来自[1],)

最近的一项针对检索增强生成(RAG) [1]的调查研究指出,总结了三个最新演变的范式如下:

  • Naive RAG,
  • 进阶RAG,
  • 以及模块化RAG。

先进的RAG(检索增强生成)范式包括一套旨在解决基础RAG局限性的技术。本文首先会探讨这些技术,这些技术可以分为预检索、检索和后检索的优化

在第二阶段,你将学习如何使用Llamaindex在Python中实现一个基础的RAG管道,然后将其升级为高级RAG管道,其中将应用一种或多种以下高级RAG技术。

  • 预检索优化:使用句子窗口技术
  • 检索优化:综合搜索
  • 后检索优化:重新排序

这篇文章主要关注高级RAG范式及其应用。如果还不熟悉RAG的基本知识,可以在这里补课。

增强检索生成(RAG):从原学术论文的理论出发,到其Python实现,使用OpenAI、Weaviate和LangChaintowardsdatascience.com来自该源代码页面
你知道什么是高级RAG技术吗?

随着最近RAG领域的发展,先进的RAG形成了一个新的模式,以解决传统RAG范式的一些限制。据最近的一项调查[1]总结,先进的RAG技术可以归为预处理、检索和后处理优化。

Advanced Retrieval-Augmented Generation \(RAG\) implements pre-retrieval, retrieval, and post-retrieval optimizations to a naive RAG pipeline

简单RAG与高级RAG的区别(作者,灵感源于[1])

预检索优化

预检索优化主要关注数据索引和查询优化。数据索引优化旨在以一种有助于提高搜索效率的方式来存储数据,例如:

  • 滑动窗口 利用块之间的重叠,是其中最简单的一种技术。
  • 增强数据粒度 的过程应用了数据清理技术,例如删除无关信息,确认事实准确性,更新过时信息等。
  • 添加元数据 ,如日期、目的或章节,以用于过滤。
  • 优化索引结构 包括多种索引数据策略,例如调整块大小或使用多索引策略。本文我们将实现其中一种技术,即句子窗口检索,这种技术将单个句子嵌入进行检索,并在推理时将其替换为更大的文本窗口。

检索句子窗口 embeds and indexes the document by single sentences but also stored a window of context around the senteces as metadata.

Sentence window retrieval

此外,预检索技术不仅仅局限于数据索引,还可以包括推理时的手段,例如查询路由、查询重写和查询扩展等。

检索优化:

让我们来聊聊检索优化吧。

检索阶段的目标是找到最相关的上下文。通常,检索基于基于向量的搜索,计算查询与索引数据之间的语义相近性。因此,大多数检索优化技术都集中在嵌入模型上 [1]。

  • 根据特定领域的上下文定制嵌入模型,尤其是那些包含不断变化或罕见术语的领域。例如,BAAI/bge-small-en 是一个高性能的嵌入模型,可以进行微调以优化性能(了解更多,请参阅微调指南)。
  • 动态嵌入 能够根据单词使用的上下文进行调整,与静态嵌入不同,静态嵌入为每个单词使用单一的向量。例如,OpenAI 的 embeddings-ada-02 是一个更复杂的动态嵌入模型,能更好地理解单词的上下文。[1]

除了向量搜索之外,还有其他检索技术,例如混合搜索,通常指的是结合向量搜索和基于关键词的搜索。如果您需要精确的关键词匹配,这种检索方式会很有帮助。

改进检索性能在RAG管道中的混合搜索技术如何通过结合传统关键词搜索和现代向量搜索技术来找到更相关的检索结果towardsdatascience.com
检索后的优化

对检索到的上下文进行进一步处理可以帮助解决诸如超出上下文窗口大小或引入噪声等问题,从而影响对重要信息的集中。RAG调查[1]中总结的后检索优化技术有:

  • 压缩提示通过删除无关信息并强调重要信息来减少整体提示长度。
  • 重新排序利用机器学习模型重新评估检索到的相关内容的重要性。

重新排列 recalculates the relevance scores based on the query after the retrieval and only sends the top n to the context window of the LLM

Re-ranking

若想进一步改进您的RAG流程使其具备生产条件,请继续阅读下面的内容:

12种让RAG应用程序准备就绪的调优策略指南如何通过这些“超参数”优化您的检索增强生成(RAG)管道的性能……向数据科学.com
前提条件

本节将介绍跟随本文所需的软件包和API密钥。

必备软件包

本文将指导你如何在Python中利用LlamaIndex实现一个基础的和一个进阶的RAG管道。

使用pip安装llama-index包:

pip install llama-index

在本文中,我们将使用LlamaIndex[v0.10版本](https://blog.llamaindex.ai/llamaindex-v0-10-838e735948f8)。如果你是从旧版本的LlamaIndex更新到新版本,你需要运行以下命令来正确地安装和运行LlamaIndex:

    pip uninstall llama-index  
    pip install llama-index --upgrade --no-cache-dir --force-reinstall

LlamaIndex 提供了将向量嵌入本地存储于 JSON 文件的选项,这对于快速原型设计非常方便。不过,我们会选择使用向量数据库来存储数据,以实现持久化,因为高级的 RAG 技术旨在打造可以投入生产的应用。

为了满足这些需求,我们将使用开源向量数据库Weaviatev3.26.2),它支持元数据存储和混合搜索。

使用pip安装这两个Python包:```
pip install weaviate-client llama-index-vector-stores-weaviate


## API钥

我们将使用Weaviate的嵌入版本,您可以免费使用,无需注册API密钥。不过,本教程使用了由OpenAI([OpenAI](https://openai.com/))提供的嵌入模型和LLM,为此,您需要申请一个OpenAI API密钥。要获取它,您需要一个OpenAI账户,然后在[API密钥](https://platform.openai.com/account/api-keys)页面创建新的密钥。

接下来,在你的根目录下创建一个名为 `.env` 的本地文件,并在该文件中定义你的 API 密钥,如下所示:

OPENAI_API_KEY="<YOUR_OPENAI_API_KEY>" # 请将此处替换为您的实际API密钥


之后,你可以通过下面的代码来设置你的API密钥。
# 安装python-dotenv包
import os  # 导入os模块
from dotenv import load_dotenv, find_dotenv  # 从dotenv库中导入load_dotenv和find_dotenv函数

# 使用find_dotenv找到.env文件,然后通过load_dotenv加载它
load_dotenv(find_dotenv())

# 使用LlamaIndex实现简单的RAG

本节讨论如何使用LlamaIndex实现基础的RAG管道。您可以在[这个Jupyter Notebook](https://github.com/weaviate/recipes/blob/main/integrations/llamaindex/retrieval-augmented-generation/naive_rag.ipynb)中找到完整的基础RAG管道的实现。有关使用LangChain实现的版本,您可以在[这篇文章](https://medium.com/towards-data-science/retrieval-augmented-generation-rag-from-theory-to-langchain-impl...)中继续了解使用LangChain的实现。

## 第一步:定义嵌入模型和大型语言模型

首先,你可以在一个全局设置中定义嵌入模型和语言模型。这样你就不必再在代码里明确指定这些模型了。

* 嵌入模型:用于为文档片段(段落)和查询生成向量表示。
* 大型语言模型(LLM):根据用户查询和相关上下文来作答。

from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
from llama_index.core.settings import Settings

设置LLM模型为gpt-3.5-turbo,温度为0.1

Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0.1)

设置嵌入模型为OpenAIEmbedding

Settings.embed_model = OpenAIEmbedding()


## 先加载一下数据。

接下来,你在你的根目录下创建一个名为 `data` 的目录,并从 [LlamaIndex GitHub 仓库](https://github.com/run-llama/llama_index)(MIT 许可证下)下载一些示例数据,例如。
!mkdir -p 'data'  
!wget '<https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt>' -O 'data/paul_graham_essay.txt'

之后,你可以加载数据,然后进行进一步处理。
从 llama_index.core 中导入 SimpleDirectoryReader  

# 下面加载数据  
文档 = SimpleDirectoryReader(  
        input_files=["./data/paul_graham_essay.txt"]  
).load_data()

## 第三步:首先将文档分割成节点

因为整个文档太大,无法完全放入LLM的上下文窗口,因此你需要将其分割成较小的文本块,在LlamaIndex中称为`节点`。你可以使用`SimpleNodeParser`,设置块大小为1024,将加载的文档解析成节点。
导入 SimpleNodeParser 从 llama_index.core.node_parser

node_parser = SimpleNodeParser.from_defaults(chunk_size=1024)  

# 从文档中提取节点信息
nodes = node_parser.get_nodes_from_documents(documents)

## 步骤四:建立索引

接下来,你将在[Weaviate](https://weaviate.io/),一个开源向量数据库中构建一个存储所有外部知识的索引。

首先,你需要连接到一个Weaviate实例。在这种情况中,我们使用了[Weaviate Embedded](https://weaviate.io/developers/weaviate/installation/embedded),它允许你在Notebook中免费实验,无需API密钥。对于生产环境中的解决方案,建议你自己部署Weaviate,例如,可以通过Docker来部署[这里](https://weaviate.io/developers/weaviate/installation/docker-compose),或使用[托管服务](https://weaviate.io/developers/weaviate/installation/weaviate-cloud-services)。
导入 weaviate 模块  

# 连接到 Weaviate  
client = weaviate.Client()  

接下来,你将使用Weaviate客户端来构建一个`VectorStoreIndex`(向量存储索引),来存储你的数据,并通过它进行交互。
from llama_index.core import VectorStoreIndex, StorageContext  
from llama_index.vector_stores.weaviate import WeaviateVectorStore  

index_name = "MyExternalContext"  

# 构建向量存储  
vector_store = WeaviateVectorStore(  
    weaviate_client=client,   
    index_name=index_name  
)  

# 设置存储嵌入  
storage_context = StorageContext.from_defaults(vector_store=vector_store)  

# 设置索引  
# 构建 VectorStoreIndex,负责将文档切分成块  
# 并将分块编码为嵌入  
index = VectorStoreIndex(  
    nodes,  
    storage_context=storage_context,  
)

### 第五步:搭建查询引擎

最后一步是将索引设置为查询引擎。
# QueryEngine 类装备了一个生成器
# 设置便于执行检索和生成操作
query_engine = index.as_query_engine()

## 步骤 6:在您的数据上运行一个基本的检索和生成查询

现在你可以对你数据运行一个基础的RAG查询,如下所示:
运行你的简单的RAG查询

response = query_engine.query(
"在Interleaf发生了什么事?"
)


# 使用LlamaIndex实现高级检索和生成技术(RAG)

在本节中,我们将介绍一些简单的调整,以将上述基础的RAG流程转变为一个更高级的版本。本部分将介绍以下几种高级RAG技术。

* 预检索处理:句子窗口法
* 检索处理:混合检索
* 后检索处理:重新排序

这里我们只介绍修改内容,您可以在下面的 Jupyter Notebook 中找到高级 RAG 管道:[高级 RAG 管道](https://github.com/weaviate/recipes/blob/main/integrations/llamaindex/retrieval-augmented-generation/advanced_rag.ipynb)。

# 索引优化示例:句子窗口提取

这个[sentence window retrieval技术](https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/MetadataReplacementDemo.html)需要做两处修改:首先,你必须调整存储和后处理数据的方法。我们将采用`SentenceWindowNodeParser`,而不是使用`SimpleNodeParser`。
导入 llama_index.core.node_parser 中的 SentenceWindowNodeParser   

# 使用默认设置创建一个句子窗口节点解析器  
node_parser = SentenceWindowNodeParser.from_defaults(  
    window_size=3,  
    window_metadata_key="window",  
    original_text_metadata_key="原始文本元数据键",  
)

这个 `SentenceWindowNodeParser` 主要负责两件事情如下:

1. 它将文档拆分成单一的句子,这些句子会被嵌入。
2. 对于每个句子,它会创建一个上下文窗口。如果你指定 `window_size = 3`,窗口将会是三句长,从即将被嵌入的句子前一句开始,包含该句子以及它之后的一句。这个窗口将作为元数据存储。

在检索过程中,返回与查询最接近的句子。检索完成后,你需要用来自元数据的整个窗口替换该句子,这可以通过定义一个 `MetadataReplacementPostProcessor` 并将其添加到 `node_postprocessors` 列表中来实现。
从 llama_index.core.postprocessor 导入 MetadataReplacementPostProcessor 作为  

# 这里的目标键默认为 `window`,以匹配 node_parser 的默认设置  
postproc = MetadataReplacementPostProcessor(  
    target_metadata_key="window"  
)  

...  

query_engine = index.as_query_engine(   
    node_postprocessors = [postproc],  
)

# 搜索优化示例:混合搜索方法

如果底层向量数据库支持混合搜索查询,只需更改 `query_engine` 的两个参数就可以实现在 LlamaIndex 中的混合搜索。`alpha` 参数用于调整向量搜索和关键词搜索之间的比重,其中 `alpha=0` 表示仅进行基于关键词的搜索,而 `alpha=1` 表示仅进行纯向量搜索。
query_engine = index.作为查询引擎(  
    ...,  
    vector_store_query_mode="向量存储查询模式",   
    alpha=0.5,  # alpha值为0.5
    ...  
)

## 检索后优化示例:重新排列

只需三个简单的步骤就可以在你的高级 RAG 管道中添加 reranker:

1. 首先,定义一个重排序器模型。这里我们使用的是 `[BAAI/bge-reranker-base](https://huggingface.co/BAAI/bge-reranker-base)`。
2. 在查询引擎中,将重排序器模型添加到 `node_postprocessors` 列表中。
3. 增加查询引擎中的 `similarity_top_k`,以检索更多的上下文段,这些段落在重排序后可以减少到 `top_n`。
# !pip install torch sentence-transformers  
from llama_index.core.postprocessor import SentenceTransformerRerank  

# 定义重排序模型  
rerank = SentenceTransformerRerank(  
    top_n = 2,   
    model = "BAAI/bge-reranker-base"  
)  

...  

# 添加重排序器到查询引擎  
query_engine = index.as_query_engine(  
        similarity_top_k = 6,  
        ...,  
                node_postprocessors = [rerank],  
        ...,  
)


在更高级的RAG框架中还有许多其他不同的技术。如果你想了解更多实现方法,我推荐这两个资源。

## [构建和评估先进的RAG应用,学习方法如句子窗口检索技术与自动合并检索技术,提升你的RAG管道的性能……www.deeplearning.ai](https://www.deeplearning.ai/short-courses/building-evaluating-advanced-rag/?source=post_page-----4de1464a9930--------------------------------)

## [高级RAG第01期:从小到大的递归检索方法(小到大检索)和带有Llama的句子窗口检索](https://medium.com/advanced-rag-01-small-to-big-retrieval-172181b396d4?source=post_page-----4de1464a9930--------------------------------)

# 简单说一下

这篇文章讨论了高级RAG的概念,高级RAG涵盖了一系列技术,用来解决基本RAG框架的限制。首先,文章概述了高级RAG中的几种技术,包括预检索、检索和后检索步骤。文章还使用LlamaIndex工具实现了从简单到高级的RAG流程。

The RAG管道组件包括由来自[OpenAI](https://openai.com/)的语言模型、来自[BAAI](https://www.baai.ac.cn/english.html)的重排序模型,该模型托管在[Hugging Face](https://huggingface.co/)上,以及[Weaviate](https://weaviate.io/)向量数据库组成。

我们采用了以下技术选型,在Python中使用LlamaIndex:

* 预检索优化:滑动窗口检索
* 检索优化:混合检索
* 后检索优化:重新排序

你可以在这里(点击链接)找到这些包含完整端到端流程的Jupyter Notebook。

* [简单的RAG在LlamaIndex中的实现](https://github.com/weaviate/recipes/blob/main/integrations/llamaindex/retrieval-augmented-generation/naive_rag.ipynb)
* [高级的RAG在LlamaIndex中的实现](https://github.com/weaviate/recipes/blob/main/integrations/llamaindex/retrieval-augmented-generation/advanced_rag.ipynb)

# 泰国你喜欢这个故事吗? 

(Note: It seems there was an additional locale reference "泰国" (Thailand) which doesn't align with the context. Given the provided XML tags and expert suggestions, the locale reference is removed for a more generic translation. The correct translation based on the expert suggestions is:)

# 你喜歡這個故事嗎?

[_免费订阅_](https://medium.com/@iamleonie) _以便在有新故事时收到通知。_

## [每当 Leonie Monigatti 发布新文章时都会收到电子邮件。通过订阅,如果您还没有账号,将会为您创建一个 Medium 账号…medium.com](https://medium.com/@iamleonie/subscribe?source=post_page-----4de1464a9930--------------------------------)

 找找我, 在[_LinkedIn_](https://www.linkedin.com/in/804250ab/),[_Twitter_](https://twitter.com/helloiamleonie) 和 [_Kaggle_](https://www.kaggle.com/iamleonie) 找到我!

# 这里不承担责任

写这篇文章的时候,我是 Weaviate 的一名开发者倡导员。

# 参考文献

## 文学分类

高, Y., 熊, Y., 高, X., 贾, K., 潘, J., 毕, Y., … & 王, H. (2023). 大规模语言模型中的检索增强的生成:综述文章。[_arXiv预印本 arXiv:2312.10997_](https://arxiv.org/pdf/2312.10997.pdf)。

## 图片

除非特别注明,所有图片均为作者原创。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消