RAG中的3个高级检索技巧

RAG系统检索的文档可能并不总是与用户的查询保持一致,这是一个常见的现象。当文档可能缺乏查询的完整答案或者包含冗余信息或包含不相关的细节,或者文档的顺序可能与用户的意图不一致时,就会经常出现这种情况。

本文将探讨三种有效的技术来增强基于rag的应用程序中的文档检索,通过结合这些技术,可以检索与用户查询密切匹配的更相关的文档,从而生成更好的答案。

查询扩展

查询扩展指的是一组重新表述原始查询的技术。

本文将讨论两种易于实现的流行方法。

1、使用生成的答案扩展查询

给定一个输入查询,首先让LLM提供一个假设答案(不管其正确性),然后将查询和生成的答案组合在一个提示中并发送给检索系统。

这种技术效果非常的好。这篇论文有详细的介绍:https://arxiv.org/abs/2212.10496

这个方法的思想是,我们希望检索看起来更像答案的文档,我们感兴趣的是它的结构和表述。所以可以将假设的答案视为帮助识别嵌入空间中相关邻域的模板。

下面是一个示例提示:

 You are a helpful expert financial research assistant.Provide an example answer to the given question, that might be found in a document like an annual report.

2、通过包含多个相关问题扩展查询

第二种方法指示LLM生成与原始查询相关的N个问题,然后将它们(+原始查询)全部发送到检索系统。

这样可以从vectorstore中检索更多文档。但是其中一些将是重复的,所以需要执行后处理来删除它们。

这个方法的思想是扩展可能不完整或不明确的初始查询,合并成最终可能相关和互补最终结果。

下面是用来生成相关问题的提示:

 You are a helpful expert financial research assistant. Your users are asking questions about an annual report.Suggest up to five additional related questions to help them find the information they need, for the provided question.Suggest only short questions without compound sentences. Suggest a variety of questions that cover different aspects of the topic.Make sure they are complete questions, and that they are related to the original question.Output one question per line. Do not number the questions.

这种方法的缺点是最终会得到更多的文档,而这些文档可能会分散LLM的注意力,使其无法生成有用的答案。

所以就衍生出一个新的方法,重排序

重排序

该方法根据量化其与输入查询的相关性的分数对检索到的文档重新排序。

使用cross-encoder进行重新排序:

交叉编码器cross-encoder是一种深度神经网络,它将两个输入序列作为单个输入处理。允许模型直接比较和对比输入,以更综合和细致的方式理解它们的关系。

给定一个查询,用所有检索到的文档对其进行编码。然后按降序排序。得分高的认为是最相关的文件。

下面有一个简单的示例:

首先安装sentence-transformers

 pip install -U sentence-transformers

使用它加载cross-encoder模型:

 from sentence_transformers import CrossEncoder cross_encoder = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-6-v2")

这里我们选择ms-marco-MiniLM-L-6-v2,对于排序的性能度量可以参考SBERT选择更好的模型。

每对(查询,文档)打分:

 pairs = [[query, doc] for doc in retrieved_documents] scores = cross_encoder.predict(pairs) print("Scores:") for score in scores:     print(score)  # Scores: # 0.98693466 # 2.644579 # -0.26802942 # -10.73159 # -7.7066045 # -5.6469955 # -4.297035 # -10.933233 # -7.0384283 # -7.3246956

重新整理文件:

 print("New Ordering:") for o in np.argsort(scores)[::-1]:print(o+1)

重排序可以与查询扩展一起使用,在生成多个相关问题并检索相应文档(假设最终有M个文档)之后,对它们重新排序并选择最前面的K (K < M)。这样可以选择最重要的部分并且减小上下文的大小。

嵌入的适配器

这个方法利用用户检索文档相关性的反馈来训练一个新的适配器。

适配器是完全微调预训练模型的轻量级替代方案。一盘情况下适配器会插入到预训练模型层之间的小型前馈神经网络中,所以训练适配器的目标是更改嵌入查询,以便为特定任务生成更好的检索结果。

嵌入适配器是一个可以在嵌入阶段之后和检索之前插入的阶段。把它想象成一个对原始嵌入进行缩放的矩阵。

要训练适配器,需要执行以下步骤。

1、准备数据

这些数据可以手工标记或由LLM生成。数据必须包括元组(query, document)及其相应的标签(如果文档与查询相关,则为1,否则为-1)。

为了演示,我们将创建一个合成数据集,首先生成金融分析师在分析财务报告时可能会问的示例问题。

让我们使用LLM直接生成:

 import osimport openaifrom openai import OpenAIfrom dotenv import load_dotenv, find_dotenv_ = load_dotenv(find_dotenv())openai.api_key = os.environ['OPENAI_API_KEY']PROMPT_DATASET = """You are a helpful expert financial research assistant. You help users analyze financial statements to better understand companies.Suggest 10 to 15 short questions that are important to ask when analyzing an annual report.Do not output any compound questions (questions with multiple sentences or conjunctions).Output each question on a separate line divided by a newline."""def generate_queries(model="gpt-3.5-turbo"):messages = [{"role": "system","content": PROMPT_DATASET,},]response = openai_client.chat.completions.create(model=model,messages=messages,)content = response.choices[0].message.contentcontent = content.split("\n")return contentgenerated_queries = generate_queries()for query in generated_queries:print(query)# 1. What is the company's revenue growth rate over the past three years?# 2. What are the company's total assets and total liabilities?# 3. How much debt does the company have? Is it increasing or decreasing?# 4. What is the company's profit margin? Is it improving or declining?# 5. What are the company's cash flow from operations, investing, and financing activities?# 6. What are the company's major sources of revenue?# 7. Does the company have any pending litigation or legal issues?# 8. What is the company's market share compared to its competitors?# 9. How much cash does the company have on hand?# 10. Are there any major changes in the company's executive team or board of directors?# 11. What is the company's dividend history and policy?# 12. Are there any related party transactions?# 13. What are the company's major risks and uncertainties?# 14. What is the company's current ratio and quick ratio?# 15. How has the company's stock price performed over the past year?

然后,我们对每个生成的问题进行文档检索,得到了一个结果的合集

 results = chroma_collection.query(query_texts=generated_queries, n_results=10, include=['documents', 'embeddings'])retrieved_documents = results['documents']

然后需要评估每个问题与其相应文件的相关性。这里也使用LLM来完成这项任务:

 PROMPT_EVALUATION = """You are a helpful expert financial research assistant. You help users analyze financial statements to better understand companies.For the given query, evaluate whether the following satement is relevant.Output only 'yes' or 'no'."""def evaluate_results(query, statement, model="gpt-3.5-turbo"):messages = [{"role": "system","content": PROMPT_EVALUATION,},{"role": "user","content": f"Query: {query}, Statement: {statement}"}]response = openai_client.chat.completions.create(model=model,messages=messages,max_tokens=1)content = response.choices[0].message.contentif content == "yes":return 1return -1

现在就得到了我们的训练数据:每个元组将包含查询的嵌入、文档的嵌入和标签(1,-1)。

 retrieved_embeddings = results['embeddings']query_embeddings = embedding_function(generated_queries)adapter_query_embeddings = []adapter_doc_embeddings = []adapter_labels = []for q, query in enumerate(tqdm(generated_queries)):for d, document in enumerate(retrieved_documents[q]):adapter_query_embeddings.append(query_embeddings[q])adapter_doc_embeddings.append(retrieved_embeddings[q][d])adapter_labels.append(evaluate_results(query, document))

然后将它们放在Torch Dataset中作为训练集

 adapter_query_embeddings = torch.Tensor(np.array(adapter_query_embeddings))adapter_doc_embeddings = torch.Tensor(np.array(adapter_doc_embeddings))adapter_labels = torch.Tensor(np.expand_dims(np.array(adapter_labels),1))dataset = torch.utils.data.TensorDataset(adapter_query_embeddings, adapter_doc_embeddings, adapter_labels)

2、定义模型

我们定义了一个函数,它将查询嵌入、文档嵌入和适配器矩阵作为输入。该函数首先将查询嵌入与适配器矩阵相乘,并计算该结果与文档嵌入之间的余弦相似度。

 def model(query_embedding, document_embedding, adaptor_matrix):updated_query_embedding = torch.matmul(adaptor_matrix, query_embedding)return torch.cosine_similarity(updated_query_embedding, document_embedding, dim=0)

3、损失

我们的目标是最小化由前一个函数计算的余弦相似度。所以可以直接使用均方误差(MSE)

 def mse_loss(query_embedding, document_embedding, adaptor_matrix, label):return torch.nn.MSELoss()(model(query_embedding, document_embedding, adaptor_matrix), label)

4、训练过程

初始化适配器矩阵并训练它超过100次。

 # Initialize the adaptor matrixmat_size = len(adapter_query_embeddings[0])adapter_matrix = torch.randn(mat_size, mat_size, requires_grad=True)min_loss = float('inf')best_matrix = Nonefor epoch in tqdm(range(100)):for query_embedding, document_embedding, label in dataset:loss = mse_loss(query_embedding, document_embedding, adapter_matrix, label)if loss < min_loss:min_loss = lossbest_matrix = adapter_matrix.clone().detach().numpy()loss.backward()with torch.no_grad():adapter_matrix -= 0.01 * adapter_matrix.gradadapter_matrix.grad.zero_()

训练完成后,适配器可用于扩展原始嵌入并适应用户任务。

我们需要做的就是将原始的嵌入输出与适配器矩阵相乘,然后再将其输入到检索系统。

 test_vector = torch.ones((mat_size,1))scaled_vector = np.matmul(best_matrix, test_vector).numpy()test_vector.shape# torch.Size([384, 1])scaled_vector.shape# (384, 1)best_matrix.shape# (384, 384)

这样,我们检索系统后续使用的嵌入向量就是经过我们微调后的向量了,这相当于针对特定的任务进行优化

总结

我们介绍的这些检索技术有助于提高文档的相关性。但是这方面的研究还正在进行,还有很多其他方法例如,

利用真实反馈数据对嵌入模型进行微调;直接微调LLM以使其检索能力最大化(RA-DIT);探索更复杂的嵌入适配器使用深度神经网络而不是矩阵;深度和智能分块技术

这些技术我们也会在后面进行整理和介绍,感谢阅读。

https://avoid.overfit.cn/post/2f2d747462c44425be906b7c5611fe37

作者:Ahmed Besbes

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

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

相关文章

DC-5靶机做题记录

靶机下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1aZRB-hqvqLlGUmAPFljnIA?pwdelxg 提取码&#xff1a;elxg 参考&#xff1a; DC5官方地址&#xff1a;https://www.vulnhub.com/entry/dc-5,314/DC5靶机地址&#xff1a;https://download.vulnhub.com/d…

2024年17款最好用的免费录制网课软件分享

近年来&#xff0c;在线课程越来越受欢迎&#xff0c;为学习者提供了方便、灵活的教育内容获取方式。随着电子学习和网络培训的兴起&#xff0c;有许多工具可以帮助课程创建者记录和编辑其在线内容。虽然市场上有许多免费和付费工具&#xff0c;但本文将重点介绍 17 个用于录制…

前端学习路线图和一些经验

关于前端目前个人建议的一个路线,也是自己之前前端学习时候的一个大致路线,给想要学习前端的小白一个参考,以前自己刚开始接触前端的时候就是不知道该按照什么路线学习 eg-前端是做什么的&#xff1f; 就是开发网站,移动端&#xff0c;小程序之类的页面 调调接口完成页面的渲…

Ansible详解(架构,模块)及部署示例

Ansible概述 Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;几乎可以实现Puppet和Saltstack能实现的功能。 Ansible是一款开源的IT自动化工具&#xff0c;它能够自动执行配置管理、…

如何免费从 SD 卡恢复已删除的文件?(照片、视频、MP3)

今天我们将告诉您如何免费从格式化的 SD 卡或闪存卡恢复文件。 特别是如果您是一名摄影师、博主或任何处理内容的人&#xff0c;您的 SD 卡上有一些内容&#xff0c;但您不小心删除或格式化了&#xff0c;现在您要向自己道歉。 无需担心&#xff0c;因为今天我们将告诉您如何…

vue写了debugger谷歌浏览器打开控制台没进断点

vue代码中打了断点&#xff0c;谷歌打开f12进不了断点解决方案如下 1、打开谷歌浏览器控制台&#xff0c;点击设置 2、在 Ignore List 中将“Enable Ignore Listing”勾选去掉&#xff0c;然后就可以正常使用debugger了

为了最大限度利用带宽,传输通道容量如何计算

一、结论&#xff1a; 传送通道容量 带宽 ✖️ 往返时延 二、过程&#xff1a; 1、传播时延和发送时延&#xff08;带宽&#xff09;通常决定一个报文的发送时间。 传输介质确定的时候&#xff0c;传播时延固定&#xff0c;发送时延根据数据报文的大小而不同。 ①传播时延…

GPT应用开发:编写插件获取实时天气信息

欢迎阅读本系列文章&#xff01;我将带你一起探索如何利用OpenAI API开发GPT应用。无论你是编程新手还是资深开发者&#xff0c;都能在这里获得灵感和收获。 本文&#xff0c;我们将继续展示聊天API中插件的使用方法&#xff0c;让你能够轻松驾驭这个强大的工具。 插件运行效…

elasticsearch6.6.0设置访问密码

elasticsearch6.6.0设置访问密码 第一步 x-pack-core-6.6.0.jar第二步 elasticsearch.yml第三步 设置密码 第一步 x-pack-core-6.6.0.jar 首先破解 x-pack-core-6.6.0.jar 破解的方式大家可以参考 https://codeantenna.com/a/YDks83ZHjd 中<5.破解x-pack> 这部分 , 也可…

SQL Server Management Studio创建数据表

文章目录 一、建表注意事项1.1 数据类型1.2 建立数据表的基本SQL语法 二、实例说明2.1 创建数据表2.2 实例2 三、标识列和主键示例&#xff1a; 一、建表注意事项 1.1 数据类型 可以看这个去了解数据类型&#xff1a; 1.2 建立数据表的基本SQL语法 建立数据表的基本 SQL 语…

【正点原子STM32连载】 第四十四章 外部SRAM实验 摘自【正点原子】APM32E103最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子APM32E103最小系统板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/docs/boards/xiaoxitongban 第四…

【备战蓝桥杯】快来学吧~ 图论巩固,Delia的生物考试

蓝桥杯备赛 | 洛谷做题打卡day12 文章目录 蓝桥杯备赛 | 洛谷做题打卡day12最大食物链计数题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题解代码总的思路&#xff1a;拓扑排序 我的一些话 最大食物链计数 题目背景 你知道食物链吗&#xff1f;Delia 生…

SSM汽车维修管理系统

工具使用情况&#xff1a; eclipsetomcatmysqljdk 技术架构&#xff1a; 后台&#xff1a;springspring mvcmybatis 前台&#xff1a;easyui 功能介绍&#xff1a; 汽车维修管理、车辆接待、维修项目登记、维修领料、质检完工、消费结算 配件管理、财务管理、基础数据管理…

二进制表示(14)

题目 public class Main {public static String con01(int x,int n) {StringBuffer s new StringBuffer();while(x!0) {s.append(x%n);x/n;}return s.reverse().toString();}public static int con02(int x,int n) {StringBuffer s new StringBuffer();int sum 0;while(x!0…

二、VS2019编译的VTK9.0.0 + Qt 5.14.2 环境测试

1. 使用CMake VS2019 编译vtk 9.0.0 时,需要启用支持Qt开关、如下图 如果不会编译的可以参见我的这篇文章: 一、VTK 9.0.0 编译安装步骤 VS2019 CMake3.26.0-CSDN博客 打开Qt5.14.2 ,创建Qt Widget 项目: 构建设置选择 MSVC2017 64bit pro 项目文件加入两行配置: …

鸿蒙开发系列教程(四)--ArkTS语言:基础知识

1、ArkTS语言介绍 ArkTS是HarmonyOS应用开发语言。它在保持TypeScript&#xff08;简称TS&#xff09;基本语法风格的基础上&#xff0c;对TS的动态类型特性施加更严格的约束&#xff0c;引入静态类型。同时&#xff0c;提供了声明式UI、状态管理等相应的能力&#xff0c;让开…

GetShell的姿势

0x00 什么是WebShell 渗透测试工作的一个阶段性目标就是获取目标服务器的操作控制权限&#xff0c;于是WebShell便应运而生。Webshell中的WEB就是web服务&#xff0c;shell就是管理攻击者与操作系统之间的交互。Webshell被称为攻击者通过Web服务器端口对Web服务器有一定的操作权…

javaWebssh运动会管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh运动会管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,M…

Beyond Compare ubuntu 安装

文章目录 参考 具体方法请参考【1】、【2】&#xff0c;亲测有效。 参考 【1】deepin深度系统 BeyondCompare 4.3.4破解教程 【2】Beyond-Compare 4 -linux 破解

Java医药WMS进销存系统

技术架构&#xff1a; jdk8 IntelliJ IDEA maven Mysql5.7 有需要的可以私信我。 系统功能与介绍&#xff1a; 医药进销存系统&#xff0c;主要分两种角色&#xff1a;员工、客户。本系统具有进销存系统的通用性&#xff0c;可以修改为其它进销存系统&#xff0c;如家电进…