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://www.rhkb.cn/news/289903.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA使用POI实现Excel单元格合并-02

JAVA使用POI实现Excel单元格合并 实现效果 解释&#xff1a;只要是遇见与前一行相同的数据就合并 引入jar <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></depe…

乐维更改IP地址

1.1 系统IP调整 vim /etc/sysconfig/network-scripts/ifcfg-ens1921.2 Web相关服务IP变更 1.2.1 编辑/itops/nginx/html/lwjkapp/.env文件,更改ZABBIXSERVER、ZABBIXRPCURL、DB_HOST中的IP 1.2.2 进入/itops/nginx/html/lwjk_app/目录下,执行php bin/manager process-conso…

Intellij IDEA安装配置Spark与运行

目录 Scala配置教程 配置Spark运行环境 编写Spark程序 1、包和导入 2、定义对象 3、主函数 4、创建Spark配置和上下文 5、定义输入文件路径 6、单词计数逻辑 7、输出结果 8、完整代码&#xff1a; Scala配置教程 IDEA配置Scala&#xff1a;教程 配置Spark运行环境 …

HTTP

HTTP 概念&#xff1a;HyperTextTransferProtocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则 HTTP协议特点&#xff1a; 1.基于TCP协议&#xff1a;面向连接&#xff0c;安全 2.基于请求-响应模型的&#xff1a;一次请求对应一次响应 …

【计算机网络】第 9 问:四种信道划分介质访问控制?

目录 正文什么是信道划分介质访问控制&#xff1f;什么是多路复用技术&#xff1f;四种信道划分介质访问控制1. 频分多路复用 FDM2. 时分多路复用 TDM3. 波分多路复用 WDM4. 码分多路复用 CDM 正文 什么是信道划分介质访问控制&#xff1f; 信道划分介质访问控制&#xff08;…

RabbitMQ 实验消费原始队列消息, 拒绝(reject)投递死信交换机过程

如果你想通过 RabbitMQ 的死信队列功能实现消费者拒绝消息投递到死信交换机的行为&#xff0c;你可以按照以下步骤操作&#xff1a; 创建原始队列&#xff0c;并将其绑定到一个交换机上&#xff1a; export RABBITMQ_SERVER127.0.0.1 export RABBITMQ_PORT5672 export RAB…

WordPress Git主题 响应式CMS主题模板

分享的是新版本&#xff0c;旧版本少了很多功能&#xff0c;尤其在新版支持自动更新后&#xff0c;该主题可以用来搭建个人博客&#xff0c;素材下载网站&#xff0c;图片站等 主题特点 兼容 IE9、谷歌 Chrome 、火狐 Firefox 等主流浏览器 扁平化的设计加响应式布局&#x…

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

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

verilog设计-cdc:多比特信号跨时钟域(DMUX)

一、前言 多比特一般为数据&#xff0c;其在跨时钟域传输的过程中有多种处理方式&#xff0c;比如DMUX&#xff0c;异步FIFO&#xff0c;双口RAM&#xff0c;握手处理。本文介绍通过DMUX的方式传输多比特信号。 二、DMUX同步跨时钟域数据 dmux表示数据分配器&#xff0c;该方…

GPT-1原理-Improving Language Understanding by Generative Pre-Training

文章目录 前言提出动机模型猜想模型提出模型结构模型参数 模型预训练训练的目标训练方式训练参数预训练数据集预训练疑问点 模型微调模型输入范式模型训练微调建议微调疑问点 实验结果分析 前言 首先想感慨一波 这是当下最流行的大模型的的开篇之作&#xff0c;由OpenAI提出。…

程序员35岁会失业吗?

在科技日新月异的时代&#xff0c;程序员这一职业群体成为了社会发展的重要推动力。然而&#xff0c;随着技术的不断更新迭代和职场竞争的加剧&#xff0c;许多程序员开始担忧自己的职业前景&#xff0c;特别是那些即将步入或已经步入35岁的程序员。他们面临着一个现实的问题&a…

专业130+总分410+西南交通大学924信号与系统考研经验西南交大电子信息通信工程,真题,大纲,参考书。

初试分数出来&#xff0c;专业课924信号与系统130&#xff0c;总分410&#xff0c;整体上发挥正常&#xff0c;但是还有遗憾&#xff0c;其实自己可以做的更好&#xff0c;总结一下经验&#xff0c;希望对大家有所帮助。专业课&#xff1a;&#xff08;130&#xff09; 西南交…

【React】onClick点击事件传参的4种方式

记录React onClick 点击事件传参的 4 种方式 方式一&#xff1a;使用内联箭头函数 import React, { MouseEvent } from "react";function App() {const handleClick (event: MouseEvent<HTMLButtonElement>, name: string) > {console.log(event)console.…

Nginx第三方模块---nginx-sticky-module的使用(基于cookie的会话保持)

目录 Nginx和Sticky介绍 编译安装sticky的nginx环境 安装过程碰到的问题和编译安装过程遇到的错误&#xff1a; &#xff08;1&#xff09;第一个错误&#xff1a;修改源代码ngx_http_sticky_module.c &#xff08;2&#xff09;第二个错误&#xff1a;修改源代码ngx_http_s…

本地部署大模型的几种工具(上-相关使用)

目录 前言 为什么本地部署 目前的工具 vllm 介绍 下载模型 安装vllm 运行 存在问题 chatglm.cpp 介绍 下载 安装 运行 命令行运行 webdemo运行 GPU推理 ollama 介绍 下载 运行 运行不同参数量的模型 存在问题 lmstudio 介绍 下载 使用 下载模型文件…

2024最新版克魔助手抓包教程(9) - 克魔助手 IOS 数据抓包

引言 在移动应用程序的开发中&#xff0c;了解应用程序的网络通信是至关重要的。数据抓包是一种很好的方法&#xff0c;可以让我们分析应用程序的网络请求和响应&#xff0c;了解应用程序的网络操作情况。克魔助手是一款非常强大的抓包工具&#xff0c;可以帮助我们在 Android …

MATLAB:优化与规划问题

一、线性规划 % 线性规划&#xff08;Linear programming, 简称LP&#xff09; fcoff -[75 120 90 105]; % 目标函数系数向量 A [9 4 7 54 5 6 105 10 8 53 8 9 77 6 4 8]; % 约束不等式系数矩阵 b [3600 2900 3000 2800 2200]; % 约束不等式右端向量 Aeq []; % 约束等式系…

八大技术趋势案例(虚拟现实增强现实)

科技巨变,未来已来,八大技术趋势引领数字化时代。信息技术的迅猛发展,深刻改变了我们的生活、工作和生产方式。人工智能、物联网、云计算、大数据、虚拟现实、增强现实、区块链、量子计算等新兴技术在各行各业得到广泛应用,为各个领域带来了新的活力和变革。 为了更好地了解…

数据库管理开发工具Navicat for MySQL Mac版下载

Navicat for MySQL&#xff08;Mac版&#xff09;是一款强大的数据库管理开发工具&#xff0c;专为MySQL设计。它提供直观的用户界面&#xff0c;支持数据建模、查询构建、数据传输等功能&#xff0c;帮助用户轻松管理数据库。其特点包括高效的数据处理能力、安全的数据传输机制…

UE小:基于UE5的两种Billboard material(始终朝向相机材质)

本文档展示了两种不同的效果&#xff0c;分别是物体完全朝向相机和物体仅Z轴朝向相机。通过下面的演示和相关代码&#xff0c;您可以更加直观地理解这两种效果的差异和应用场景。 1. 完全朝向相机效果 此效果下&#xff0c;物体将完全面向相机&#xff0c;不论相机在哪个角度…