LLM之RAG实战(三十五)| 使用LangChain的3种query扩展来优化RAG

         RAG有时无法从矢量数据库中检索到正确的文档。比如我们问如下问题:

从1980年到1990年,国际象棋的规则是什么?

       RAG在矢量数据库中进行相似性搜索,来查询与国际象棋规则问题相关的相关文档。然而,在某些情况下,我们的向量数据库没有存储完整的信息,例如,我们的矢量数据库没有存储不同年份的规则。这样,数据库可以返回与国际象棋规则相关但与特定问题不直接相关的文档。

       针对上述情况,我们可以采用查询扩展技术,该技术可以对用户的原始查询生成更全面、信息更丰富的搜索。这个新生成的查询将从矢量数据库中获取更多相关文档。

本文,我们将介绍三种查询扩展方法:

一、后退提示(Step Back Prompting)

       Step back prompting来自论文《Take A Step Back: Evoking Reasoning Via Abstraction In Large Language Models》[1]

       Step back prompting是谷歌deepmind开发的一种方法,它首先使用LLM创建用户查询的抽象(从用户具体查询到通用查询的转换,因此称为后退提示),然后根据生成的通用查询来生成答案。

以下是“原始查询”和“后退查询”的示例:

{    "Original_Query": "Could the members of The Police perform lawful arrests?",    "Step_Back_Query": "what can the members of The Police do?",},{    "Original_Query": "Jan Sindel’s was born in what country?",    "Step_Back_Query": "what is Jan Sindel’s personal history?",}
#---------------------Prepare VectorDB-----------------------------------# Build a sample vectorDBfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain_community.document_loaders import WebBaseLoaderfrom langchain_community.vectorstores import Chromafrom langchain.embeddings import OpenAIEmbeddingsimport osos.environ["OPENAI_API_KEY"] = "Your OpenAI KEY"# Load blog postloader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")data = loader.load()# Splittext_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)splits = text_splitter.split_documents(data)# VectorDBembedding = OpenAIEmbeddings()vectordb = Chroma.from_documents(documents=splits, embedding=embedding)#-------------------Prepare Step Back Prompt Pipeline------------------------from langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplatefrom langchain_core.runnables import RunnableLambdafrom langchain.chat_models import ChatOpenAIretriever = vectordb.as_retriever()llm = ChatOpenAI()# Few Shot Examplesexamples = [    {        "input": "Could the members of The Police perform lawful arrests?",        "output": "what can the members of The Police do?",    },    {        "input": "Jan Sindel’s was born in what country?",        "output": "what is Jan Sindel’s personal history?",    },]# We now transform these to example messagesexample_prompt = ChatPromptTemplate.from_messages(    [        ("human", "{input}"),        ("ai", "{output}"),    ])few_shot_prompt = FewShotChatMessagePromptTemplate(    example_prompt=example_prompt,    examples=examples,)prompt = ChatPromptTemplate.from_messages(    [        (            "system",            """You are an expert at world knowledge. Your task is to step back and paraphrase a question to a more generic step-back question, which is easier to answer. Here are a few examples:""",        ),        # Few shot examples        few_shot_prompt,        # New question        ("user", "{question}"),    ])question_gen = prompt | llm | StrOutputParser()#--------------------------QnA using Back Prompt Technique-----------------from langchain import hubdef format_docs(docs):    doc_strings = [doc.page_content for doc in docs]    return "\n\n".join(doc_strings)response_prompt = hub.pull("langchain-ai/stepback-answer")chain = (    {        # Retrieve context using the normal question        "normal_context": RunnableLambda(lambda x: x["question"]) | retriever | format_docs,        # Retrieve context using the step-back question        "step_back_context": question_gen | retriever | format_docs,        # Pass on the question        "question": lambda x: x["question"],    }    | response_prompt    | llm    | StrOutputParser())result = chain.invoke({"question": "What Task Decomposition that work in 2022?"})

       上面的代码是使用后退提示技术运行QnA的langchain脚本。需要注意的是:使用OPENAI_API_KEY并准备自己的向量数据库。

# Load blog post # You can use different loader to load different type fileloader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")data = loader.load()# Splittext_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)splits = text_splitter.split_documents(data)

我们尝试如下问题:

Original Query: What Task Decomposition that work in 2022?

后退查询结果如下:

Step Back Query: What are some examples of task decomposition in the current year?

       这两个查询将用于提取相关文档,我们将这些文档组合在一起作为上下文,并在下面的这一部分中提供给您的LLM。

{    # Retrieve context using the normal question    "normal_context": RunnableLambda(lambda x: x["question"]) | retriever | format_docs,    # Retrieve context using the step-back question    "step_back_context": question_gen | retriever | format_docs,    # Pass on the question    "question": lambda x: x["question"],}

二、Multi Query(多查询)[2]

       多查询是一种使用LLM从第一个查询生成更多查询的技术。这种技术试图回答一些用户提示没有那么具体的情况,这些生成的查询将用于在矢量数据库中查找文档。目标是细化查询,使其与主题更加相关,从而从数据库中检索更多相关的文档。

       细节可以参考:LLM之RAG实战(三十四)| 使用LangChain的三个函数来优化RAG

三、Cross Encoding Re-Ranking(交叉编码器重排序)

       交叉编码是多查询和交叉编码器重新排序的结合,因为用户能够使用LLM生成更多的问题,每个生成的查询都能够从矢量数据库中提取出几个文档。这些提取的文档必须通过交叉编码器,以获得与初始查询的相似性分数。现在我们可以对相关文档进行重新排序,并选择前5名作为LLM摘要的上下文。

       为什么我们需要选择前5个文档?在这种情况下,我们试图避免从矢量数据库中检索到不相关的文档,这种选择确保了交叉编码器专注于最相似和最有意义的文档,从而生成更准确、更简洁的摘要。

#------------------------Prepare Vector Database--------------------------# Build a sample vectorDBfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain_community.document_loaders import WebBaseLoaderfrom langchain_community.vectorstores import Chromafrom langchain.embeddings import OpenAIEmbeddingsfrom langchain.chat_models import ChatOpenAIimport osos.environ["OPENAI_API_KEY"] = "Your API KEY"# Load blog postloader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")data = loader.load()llm = ChatOpenAI()# Splittext_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)splits = text_splitter.split_documents(data)# VectorDBembedding = OpenAIEmbeddings()vectordb = Chroma.from_documents(documents=splits, embedding=embedding)#--------------------Generate More Question----------------------------------#This function use to generate queries using LLMdef create_original_query(original_query):    query = original_query["question"]    qa_system_prompt = """            You are an AI language model assistant. Your task is to generate five         different versions of the given user question to retrieve relevant documents from a vector         database. By generating multiple perspectives on the user question, your goal is to help        the user overcome some of the limitations of the distance-based similarity search.         Provide these alternative questions separated by newlines."""        qa_prompt = ChatPromptTemplate.from_messages(        [            ("system", qa_system_prompt),            ("human", "{question}"),        ]    )        rag_chain = (        qa_prompt        | llm        | StrOutputParser()    )        question_string = rag_chain.invoke(        {"question": query}    )        lines_list = question_string.splitlines()    queries = []    queries = [query] + lines_list        return queries#-------------------Retrieve Document and Cross Encoding--------------------from sentence_transformers import CrossEncoderfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.runnables import RunnableLambda, RunnablePassthroughfrom langchain_core.output_parsers import StrOutputParserimport numpy as npcross_encoder = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')#Cross Encoding happens in heredef create_documents(queries):    retrieved_documents = []    for i in queries:        results = vectordb.as_retriever().get_relevant_documents(i)        docString = [doc.page_content for doc in results]        retrieved_documents.extend(docString)            unique_a = []    #If there is duplication documents for each query, make it unique    for item in retrieved_documents:        if item not in unique_a:            unique_a.append(item)        unique_documents = list(unique_a)        pairs = []    for doc in unique_documents:        pairs.append([queries[0], doc])        #Cross Encoder Scoring    scores = cross_encoder.predict(pairs)        final_queries = []    for x in range(len(scores)):        final_queries.append({"score":scores[x],"document":unique_documents[x]})        #Rerank the documents, return top 5    sorted_list = sorted(final_queries, key=lambda x: x["score"], reverse=True)    first_five_elements = sorted_list[:6]    return first_five_elements#-----------------QnA Document-----------------------------------------------qa_system_prompt = """        Assistant is a large language model trained by OpenAI. \        Use the following pieces of retrieved context to answer the question. \        If you don't know the answer, just say that you don't know. \        {context}"""qa_prompt = ChatPromptTemplate.from_messages(    [        ("system", qa_system_prompt),        ("human", "{question}"),    ])def format(docs):    doc_strings = [doc["document"] for doc in docs]    return "\n\n".join(doc_strings)chain = (    # Prepare the context using below pipeline    # Generate Queries -> Cross Encoding -> Rerank ->return context    {"context": RunnableLambda(create_original_query)| RunnableLambda(create_documents) | RunnableLambda(format), "question": RunnablePassthrough()}    | qa_prompt    | llm    | StrOutputParser())result = chain.invoke({"question":"What Task Decomposition that work in 2022?"})

       参考从上面的langchain脚本,创建2个自定义函数用于生成查询和交叉编码。

create_original_query是生成查询,基本上会返回5个生成的问题加上原始查询。

create_documents将用于检索基于6个问题的24个相关文档。这24份相关文件将被复制,因此我们需要保留唯一的文件并删除重复的文件。

scores = cross_encoder.predict(pairs)

       上述代码可以计算出文档和原始查询之间的交叉编码分数。最后,代码将尝试根据交叉编码得分对文档进行重新排序,并只保留前5个文档。

四、结论

       这3种方法真的很有帮助,特别是如果你得到的反馈是RAG没有返回正确和详细的答案,你可以使用上面的查询扩展方法来解决这些问题。

参考文献:

[1] https://arxiv.org/pdf/2310.06117.pdf

[2] https://python.langchain.com/docs/modules/data_connection/retrievers/MultiQueryRetriever

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

论文《Exploring to Prompt for Vision-Language Models》阅读

论文《Exploring to Prompt for Vision-Language Models》阅读 论文概况论文动机(Intro)MethodologyPreliminaryCoOp[CLASS]位置Context 是否跨 class 共享表示和训练 ExperimentsOverall ComparisonDomain GeneralizationContext Length (M) 和 backbon…

Gitlab CI---could not read username for xxx: no such device or address

0 Preface/Foreword 项目开发中&#xff0c;经常会使用第三方的算法或者功能&#xff0c;那么就需要把对应的repo以子模块的方式添加到当前repo中。 添加命令&#xff1a; git submodule add <URL> 1 问题表现 子模块添加成功&#xff0c;但是GitLab CI阶段&#xff…

蓝桥杯 - 小明的背包3(多重背包)

解题思路&#xff1a; 动态规划 多重背包问题需要在01背包问题&#xff08;不重复&#xff09;的基础上多加一层循环进行遍历&#xff0c;并且dp[ j ]的式子也需要修改 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scan …

2024/03/28(C++·day4)

一、思维导图 二、练习题 1、写出三种构造函数&#xff0c;算术运算符、关系运算符、逻辑运算符重载尝试实现自增、自减运算符的重载 #include <iostream>using namespace std;// 构造函数示例 class MyClass { private:int data; public:// 默认构造函数MyClass() {da…

Java与Go:字符串转IP

在本文中&#xff0c;我们将了解如何将简单的对比Java和Go是如何将字符串解析为IP地址。 Java 在Java中&#xff0c;将字符串转换为IP地址最无脑的一个方法&#xff1a; import java.net.InetAddress; import java.net.UnknownHostException;public class Main {public stat…

OpenHarmony实战开发-使用ArkTS语言实现简易视频播放器

介绍 本篇Codelab使用ArkTS语言实现视频播放器&#xff0c;主要包括主界面和视频播放界面&#xff0c;我们将一起完成以下功能&#xff1a; 主界面顶部使用Swiper组件实现视频海报轮播。主界面下方使用List组件实现视频列表。播放界面使用Video组件实现视频播放。在不使用视频…

RTOS线程切换的过程和原理

0 前言 RTOS中最重要的一个概念就是线程&#xff0c;线程的按需切换能够满足RTOS的实时性要求&#xff0c;同时能将复杂的需求分解成一个个线程执行减轻我们开发负担。 本文从栈的角度出发&#xff0c;详细介绍RTOS线程切换的过程和原理。 注&#xff1a;本文参考的RTOS是RT-T…

腾讯云邮件推送功能有哪些?如何有效使用?

腾讯云邮件推送如何设置&#xff1f;怎么用邮件推送做高效营销&#xff1f; 腾讯云作为业界领先的云服务提供商&#xff0c;其邮件推送功能在便捷性、稳定性和安全性上都有着出色的表现。那么&#xff0c;腾讯云邮件推送功能究竟有哪些呢&#xff1f;让AokSend来探个究竟。 腾…

Vite 为什么比 Webpack 快?

目录 1. Webpack 的构建原理 2. Script 的模块化&#xff08;主流浏览器对 ES Modules 的支持&#xff09; 3. Webpack vs Vite 开发模式的差异 对 ES Modules 的支持 底层语言的差异 热更新的处理 1. Webpack 的构建原理 前端之所以需要类似于 Webpack 这样的构建工具&…

windows@系统信息查看若干方法@查看硬件信息@系统信息仪表盘@资源占用OSD悬浮窗口

文章目录 操作系统简要信息查看&#x1f47a;计算机软硬件信息查看windows自带工具msinfo32dxdiagcompmgmtsettingssysteminfo.exe 其他专业软件查看计算机软硬件信息&#x1f47a;OSD系统仪表盘系列软件TrafficMonitor插件功能 Rainmeter时间更改板块刷新显示和关闭 Rainmeter…

实现DevOps需要什么?

实现DevOps需要什么&#xff1f; 硬性要求&#xff1a;工具上的准备 上文提到了工具链的打通&#xff0c;那么工具自然就需要做好准备。现将工具类型及对应的不完全列举整理如下&#xff1a; 代码管理&#xff08;SCM&#xff09;&#xff1a;GitHub、GitLab、BitBucket、SubV…

flutter 修改app名字和图标

一、修改名字 在Android中修改应用程序名称&#xff1a; 在AndroidManifest.xml文件中修改应用程序名称&#xff1a; 打开Flutter项目中的android/app/src/main/AndroidManifest.xml文件。找到<application>标签&#xff0c;然后在android:label属性中修改应用程序的名称…

Xcode删除原本的Git,再添加新的git

本文参考&#xff1a;Xcode怎么删除原本git,在重新设置新的git地址_ios xcode 删除原本git-CSDN博客 开发中会有一个问题。Xcode项目A 提交到Git服务器server1&#xff0c;此时项目A内部已经存在一个Git文件&#xff0c;与server1相关联。 此时你想将项目A提交到 另一个Git…

【InternLM 实战营第二期笔记】书生·浦语大模型全链路开源体系及InternLM2技术报告笔记

大模型 大模型成为发展通用人工智能的重要途径 专用模型&#xff1a;针对特定任务&#xff0c;一个模型解决一个问题 通用大模型&#xff1a;一个模型应对多种任务、多种模态 书生浦语大模型开源历程 2023.6.7&#xff1a;InternLM千亿参数语言大模型发布 2023.7.6&#…

Python拆分PDF、Python合并PDF

WPS能拆分合并&#xff0c;但却是要输入编辑密码&#xff0c;我没有。故写了个脚本来做拆分&#xff0c;顺便附上合并的代码。 代码如下&#xff08;extract.py) #!/usr/bin/env python """PDF拆分脚本(需要Python3.10)Usage::$ python extract.py <pdf-fil…

Linux用户及用户组权限

一、用户和用户组 功能项命令实例作用用户组cat /etc/group查看当前系统存在的用户组groupadd testing添加一个新的用户组testingcat /etc/group查看组是否被新增成功groupmod -n test testing将testing重命名成testgroupdel test删除组testgroups root查看用户root所在的所有…

原型链-(前端面试 2024 版)

来讲一讲原型链 原型链只存在于函数之中 四个规则 1、引用类型&#xff0c;都具有对象特性&#xff0c;即可自由扩展属性。 2、引用类型&#xff0c;都有一个隐式原型 __proto__ 属性&#xff0c;属性值是一个普通的对象。 3、引用类型&#xff0c;隐式原型 __proto__ 的属…

基于单片机小型家用燃气锅炉控制系统设计

**单片机设计介绍&#xff0c;基于单片机小型家用燃气锅炉控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的小型家用燃气锅炉控制系统设计&#xff0c;主要目标是实现锅炉的智能化控制&#xff0c;包括温…

1学习使用axios

一、axios介绍&#xff1a; axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;用于浏览器和 Node.js。它提供了一种简单的方法来发送 HTTP 请求&#xff0c;并且具有很多实用的功能&#xff0c;使得网络请求变得更加方便和可靠。 以下是 axios 的一些主要特点和功能&…

边缘计算AI盒子目前支持的AI智能算法、视频智能分析算法有哪些,应用于大型厂矿安全生产风险管控

一、前端设备实现AI算法 主要是基于安卓的布控球实现&#xff0c;已有的算法包括&#xff1a; 1&#xff09;人脸&#xff1b;2&#xff09;车牌&#xff1b;3&#xff09;是否佩戴安全帽&#xff1b;4&#xff09;是否穿着工装&#xff1b; 可以支持定制开发 烟雾&#xf…