RAG进阶(二): RAG 融合(rag fusion)

在上一篇博客中,我们学习了多重查询(Multi Query)技术,Multi Query的基本思想是当用户输入查询语句(自然语言)时,我们让大模型(LLM)基于用户的问题再生成多个查询语句,这些生成的查询语句是对用户查询语句的补充,它们是从不同的视角来补充用户的查询语句,然后每条查询语句都会从向量数据库中检索到一批相关文档,最后所有的相关文档都会被喂给LLM,这样LLM就会生成比较完整和全面的答案。这样就可以避免因为查询语句的差异而导致结果不正确。如下图所示:

今天我们来介绍RAG 融合(rag fusion),它的主要思想是在Multi Query的基础上,对其检索结果进行重新排序(即reranking)后输出Top K个最相关文档,最后将这top k个文档喂给LLM并生成最终的答案(answer)。如下图所示:

 一、环境配置

我们需要安装如下python包:

pip install langchain langchain_openai langchain_pinecone langchainhub

接下来我们需要导入所需要设置本次实验所需要用的几个api key:OPENAI_API_KEY,PINECONE_API_KEY,LANGCHAIN_API_KEY,这里需要说明的是本次实验会使用到openai的gpt-3.5-turbo模型,Pinecone向量数据库(PINECONE_API_KEY), LangSmith(LANGCHAIN_API_KEY).

pinecone云向量数据库是一个在线的云端向量数据库,我们需要去其官网申请api key,   LangSmith 是用来跟踪和分析langchain组件在执行过程中产生的中间结果,这对我们理解langchain组件的功能和作用有很大的帮助,因此我们也需要去langchain官网申请一个api key。

import os
from dotenv import load_dotenv, find_dotenv
from langchain_openai import OpenAIEmbeddings
from langchain_pinecone import PineconeVectorStore

 
#导入项目中需要用到的各种的api_key
_ = load_dotenv(find_dotenv()) # read local .env file


os.environ['OPENAI_API_KEY']=os.environ['OPENAI_API_KEY']
os.environ['PINECONE_API_KEY']=os.environ['PINECONE_API_KEY']

# 导入langsmith所需要的api key,用于跟踪中间结果
os.environ['LANGCHAIN_TRACING_V2'] = 'true'
os.environ['LANGCHAIN_ENDPOINT'] = 'https://api.smith.langchain.com'
os.environ['LANGCHAIN_API_KEY'] = os.environ['LANGCHAIN_API_KEY']

接下来我们还需要去pinecone官网创建一个向量数据库,这里我们创建了一个名为:rag-fusion的空向量数据库,后面需要被检索的文档向量会被自动上传到该向量数据库中:

 

下面我们来创建一组本次实验所需的测试文档集合,一共10个文档,每个文档为一句中文的句子,每个文档的内容在语义上基本都和气候变化相关:

all_documents={
    "doc1": "气候变化和经济影响。",
    "doc2": "气候变化引起的公共卫生问题。",
    "doc3": "气候变化:社会视角。",
    "doc4": "气候变化的技术解决方案。",
    "doc5": "应对气候变化需要改变政策。",
    "doc6": "气候变化及其对生物多样性的影响。",
    "doc7": "气候变化:科学和模型。",
    "doc8": "全球变暖:气候变化的一个子集。",
    "doc9": "气候变化如何影响日常天气。",
    "doc10": "气候变化行动主义的历史。",
    }

接下来我们需要创建pinecone的向量数据库,在创建向量数据库时,我们指定使用openai的embedding模型,以及向量数据库名(rag-fusion), 需要说明的是这里我们使用的是from_texts的方法来创建向量数据库,它的作用是往云端的向量数据库"rag-fusion"中上传文档向量,这样云端的"rag-fusion"向量库就不再是一个空的数据库了:

vectorstore = PineconeVectorStore.from_texts(
    list(all_documents.values()), OpenAIEmbeddings(), index_name="rag-fusion"
)

二、定义查询生成器(Multi Quer)

我们现在将定义一个chain来生成多重查询语句,如果对多重查询还不熟悉的朋友,可以查看我之前写的这篇博客。这里我们会首先创建生成多重查询的prompt, 我们可以从langchain官网拉取预先定义好的prompt, 也可以手动定义prompt:

from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
from langchain import hub

prompt = hub.pull("langchain-ai/rag-fusion-query-generation")

prompt 

 同样我们也可以手动创建多重查询的prompt:


# prompt = ChatPromptTemplate.from_messages([
#     ("system", "You are a helpful assistant that generates multiple search queries based on a single input query."),
#     ("user", "Generate multiple search queries related to: {original_query}"),
#     ("user", "OUTPUT (4 queries):")
# ])

接下来我们来创建一个生成多重查询的chain, 该chain会根据用户的query生成4个多角度的query, 这些多角度的query是对用户原始query的补充。

generate_queries = (
    prompt | ChatOpenAI(temperature=0) | StrOutputParser() | (lambda x: x.split("\n"))
)

original_query = "气候变化的影响"
queries = generate_queries.invoke({"original_query": original_query})
queries

 

这里我们看到用户的原始问题是: 气候变化的影响,generate_queries根据用户的问题生成了4个多角度的问题来对用户问题进行补充。

三、定义完整链

我们现在可以将它们放在一起并定义完整的用于检索的chain。该chain的作用是:

 1. 生成一组查询(queries)
 2. 在检索器中对每个query进行检索
 3. 使用倒排序排名融合方法将所有结果连接在一起

请注意,该chain不执行最后的生成步骤(不会将top k的检索结果喂给LLM)

original_query = "气候变化的影响"

接下来我们来创建一个向量库的实例并通过该向量库实例来创建一个检索器。

vectorstore = PineconeVectorStore.from_existing_index("rag-fusion", OpenAIEmbeddings())
retriever = vectorstore.as_retriever()

 下面我们需要定义倒排序排名算法(Reciprocal Rank Fusion (RRF)),该算法来源于这篇论文:Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods,下面是该算法在论文中的定义:

 RRF 是与滑铁卢大学 (CAN) 和 Google 合作开发的,用其作者的话说,“比任何单独的系统产生更好的结果,比标准的”重新排名方法更好。我们简单解释一下该算法的原理,在RRF算法中,D表示相关文档的全集,k是固定常数60,r(d)表示当前文档d在其子集中的位置。该算法会对文档全集D进行二重遍历,外层遍历文档全集D, 内层遍历文档子集,在做内层变量的时候我们会累计当前文档在其所在子集中的位置并取倒数作为其权重(分数)。

下面是RRF算法的python实现: 

from langchain.load import dumps, loads

def reciprocal_rank_fusion(results: list[list], k=60):
    """ Reciprocal_rank_fusion that takes multiple lists of ranked documents 
        and an optional parameter k used in the RRF formula """
    
    # Initialize a dictionary to hold fused scores for each unique document
    fused_scores = {}

    # Iterate through each list of ranked documents
    for docs in results:
        # Iterate through each document in the list, with its rank (position in the list)
        for rank, doc in enumerate(docs):
            # Convert the document to a string format to use as a key (assumes documents can be serialized to JSON)
            doc_str = dumps(doc)
            # If the document is not yet in the fused_scores dictionary, add it with an initial score of 0
            if doc_str not in fused_scores:
                fused_scores[doc_str] = 0
            # Retrieve the current score of the document, if any
            previous_score = fused_scores[doc_str]
            # Update the score of the document using the RRF formula: 1 / (rank + k)
            fused_scores[doc_str] += 1 / (rank + k)

    # Sort the documents based on their fused scores in descending order to get the final reranked results
    reranked_results = [
        (loads(doc), score)
        for doc, score in sorted(fused_scores.items(), key=lambda x: x[1], reverse=True)
    ]

    # Return the reranked results as a list of tuples, each containing the document and its fused score
    return reranked_results

 下面我们来创建一个完整的chain,它由generate_queries ,retriever.map() ,reciprocal_rank_fusion三部分组成,其中generate_queries会生成4个多角度的query, retriever.map()的作用是根据generate_queries的结果映射出4个retriever(可以理解为同时复制出4个retriever)与中generate_queries会生成4个query对应,并为每个query检索出来的一组相关文档集(默认为4个相关文档),那么4个query总共可以生成16个相关文档。这16个相关文档集最后会经过RRF算法从新排序后输出最终的4个相关度最高的文档:

original_query = "气候变化的影响"

chain = generate_queries | retriever.map() | reciprocal_rank_fusion


chain.invoke({"original_query": original_query})

 这里我们看到了经过最终的RRF算法进行重拍以后的4个最相关的文档,并且从高倒低罗列出了每个相关文档的得分,下面我们来分析一下这些分数是如何统计出来的,为此我们需要提取那些在执行RRF算法之前的结果:

chain1 = generate_queries | retriever.map() 
chain1_result = chain1.invoke({"original_query": original_query})
chain1_result

 

 下面我们可以根据RRF算法在论文中的定义,手动来计算上面这些相关文档的分数:

#气候变化和经济影响。0.16344044051606188
score0 = 1/60+1/61+1/62+1/60+1/61+1/62+1/63+1/60+1/61+1/62 

#气候变化引起的公共卫生问题。0.049189141547682
score1 = 1/60+1/61+1/62 

#气候变化及其对生物多样性的影响。0.16344044051606188
score2 = 1/63+1/63 

# 气候变化如何影响日常天气。0.015873015873015872
score3 = 1/63 
print(score0)
print(score1)
print(score2)
print(score3)

 

 这里我们看到我们手动计算的分数与RRF的python算法计算的分数是一致的。

下面我们可以在LangSmith平台中查看最终chain的执行过程中的中间结果,如下图的左侧为最终chain的所有组件如:ChatPromptTemplate,ChatOpenAI,Retriever(4个),reciprocal_rank_fusion,下图的右侧为每个组件所对应的输入和输出的内容:

下图为ChatPromptTemplate组件对应的输入和输出结果:

 

 下图为ChatOpenAI(LLM)组件对应的输入和输出结果:

 

  下图为第一个Retriever的输入和输出结果:

 

下图为最后一个Retriever的输入和输出结果: 

下图为RRF算法的输入和输出结果: 

 

 未完待续。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/595223.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机毕业设计 | vue+springboot 在线花店后台管理系统(附源码)

1,绪论 1.1 项目背景 随着社会发展,网上购物已经成为我们日常生活的一部分。但是,至今为止大部分电商平台都是从人们日常生活出发,出售都是一些日常用品比如:食物、服装等等,并未发现一个专注于鲜花的电商…

BSC链震撼登场:X314暴涨500倍

在Solana链上疯狂的“狗币”行情落下帷幕后,链上的最新热点再次来到了BSC链上。此次,BSC链上出现了备受关注的新协议,据说这是继Ordinals协议之后的又一创新之作。该协议被誉为现象级产品,自推出以来涨幅已达500倍,但其…

C补充1—1章1.0—C程序语言设计(许宝文,李志)

二手书到了,好消息,前主人看的很认真,坏消息,只看到这页了 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊最后几题好难啊啊啊啊啊,再议 目录 1.1 入门 1.2 变量与算数表达式 练习1-3 //打印温度对照表 练习1-4 //摄氏-华氏温…

古墓丽影年度版喜加一 亚马逊免费游戏领取教程+下载安装教程

最近我们的老朋友亚马逊平台又为玩家们带来了一款免费的3A大作,这款游戏作为古墓丽影的续作在全球范围内都有着很高的热度和评价。但是许多玩家不知道这款游戏该如何领取,下面小编就为大家带来详细教程。 在领取之前,我们一定要优化我们的网…

【Js逆向】某博反爬机制的逆向分析

相信很多接触过爬虫的师傅,在对某博进行请求的时候,发现某博是会对cookie校验的,而我们在模拟操作的时候,是直接把浏览器的cookie进行copy,虽然我没有测试过这个cookie的有效期,但我觉得这样只适合日常测试…

LNMP一键安装包

LNMP一键安装包是什么? LNMP一键安装包是一个用Linux Shell编写的可以为CentOS/RHEL/Fedora/Debian/Ubuntu/Raspbian/Deepin/Alibaba/Amazon/Mint/Oracle/Rocky/Alma/Kali/UOS/银河麒麟/openEuler/Anolis OS Linux VPS或独立主机安装LNMP(Nginx/MySQL/PHP)、LNMPA(Nginx/MySQ…

亚马逊云科技产品测评:玩转云服务器(EC2)

文章目录 📑引言一、亚马逊发展历史介绍二、云服务器资源地域分布三、云服务器实例规格四、EC2计费模式五、亚马逊免费EC2领取 📑引言 亚马逊:世界上最大的云服务器提供商 亚马逊云科技 是由亚马逊公司提供的一系列云计算服务。它提供了弹性计…

KNOWLEDGE DISTILLATION BASED ON TRANSFORMED TEACHER MATCHING

摘要 温度标度作为logit匹配和概率分布匹配的bridge技术,在知识蒸馏(KD)中起着至关重要的作用。传统上,在蒸馏中,温度标度适用于教师的logits和学生的logits。在本文中,受到最近一些研究成果的启发&#x…

Leetcode—622. 设计循环队列【中等】

2024每日刷题(128) Leetcode—622. 设计循环队列 实现代码 class MyCircularQueue { public:MyCircularQueue(int k): q(k) {qSize k;}bool enQueue(int value) {if(isFull()) {return false;}q[rear] value;rear (rear 1) % qSize;deflag false;…

数据结构相关

数据结构相关 文章目录 数据结构相关[TOC](文章目录)前言一、数据结构介绍二、不同的逻辑结构的存储方案(Java实现)2.1 线性结构:线性表、数组2.2 线性结构:栈2.3 线性结构:队列2.4 树形结构:树 三、一些常见的3.1 布隆过滤器Bloo…

网络安全是否有需求

● 由于网络威胁数量不断增加,网络安全的需求很高。 ● 组织正在大力投资网络安全以保护其数据。 ● 就业市场缺乏熟练的网络安全专业人员。 ● 网络安全认证可以提升您在网络安全领域的职业前景。 ● 持续学习并了解最新的安全趋势在该领域至关重要。 网络安全重磅…

stm32f103zet6_串口实现-DHT11-tim1(定时)

1思路 1打开时钟 1.1使用定时器实现us级的计时 1.2在打开串口 1,3在DHT11驱动中修改引脚 stm32cudeMX 配置 1打开时钟 2打开串口 3打开tim1(定时器) 4生成代码 代码设置 1导入DHT11库(tim.h是定时器的文件系统自动生成的) DHT11.c #include "dht11.h" #inc…

鸿蒙内核源码分析(信号量篇) | 谁在负责解决任务的同步

基本概念 信号量(Semaphore) 是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。 一个信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数…

咖啡机定量出水的原理是什么

咖啡机实现定量出水的原理主要依赖于流量计的使用。流量计是一种能够测量液体或气体通过管道的速度和体积的装置。在咖啡机中,常用的小型流量计有霍尔式流量计和光电式流量计两种。 霍尔式流量计利用了霍尔效应的原理来实现流量测量。它包含一个带有两极磁铁的叶轮…

信创基础软件之操作系统

操作系统概述 操作系统是计算机系统软硬件资源的纽带。操作系统是连接硬件和数据库、中间件、应用软件的纽带,是承载各种信息设备和软件应用的重要基础软件。操作系统控制和管理整个计算机系统的硬件、软件资源,组织和调度计算机工作和资源,…

等保建设技术建议书(Word原件)

1信息系统详细设计方案 1.1安全建设需求分析 1.1.1网络结构安全 1.1.2边界安全风险与需求分析 1.1.3运维风险需求分析 1.1.4关键服务器管理风险分析 1.1.5关键服务器用户操作管理风险分析 1.1.6数据库敏感数据运维风险分析 1.1.7“人机”运维操作行为风险综合分析 1.2…

C语言结构体类型

C语言结构体类型 个人主页:大白的编程日记 个人主页:C语言学习之路 文章目录 C语言结构体类型前言一.结构体1.1结构体类型的声明1.2结构体变量的创建和初始化1.3结构成员访问操作符1.4结构的特殊声明1.5 结构的自引用 二.结构体内存对齐2.1对齐规则2.2内…

嵌入式linux学习第一天

参考正点原子Linux开发文档。记录下知识点。 Shell 基本操作 前面我们说 Shell 就是“敲命令”,那么既然是命令,那肯定是有格式的,Shell 命令的格式 如下: command -options [argument] command: Shell 命令名称。 options&…

27 JavaScript学习:异步编程

异步的概念 在JavaScript中,异步编程是一项重要的概念,特别在处理用户交互、网络请求和文件读写等场景下非常常见。JavaScript是一门单线程语言,因此需要通过异步编程来避免阻塞主线程,保证程序的流畅性和响应性。 在JavaScrip…

避雷!7.7分,新增1区TOP被标记On Hold,5本已被踢除!

本周投稿推荐 SSCI • 2/4区经管类,2.5-3.0(录用率99%) SCIE(CCF推荐) • 计算机类,2.0-3.0(最快18天录用) SCIE(CCF-C类) • IEEE旗下,1/2…