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,一经查实,立即删除!

相关文章

基于极限学习机的变压器故障分类,基于ELM的变压器故障预测

目录 背影 极限学习机 基于极限学习机的变压器故障分类,基于ELM的变压器故障预测 主要参数 MATLAB代码 效果图 结果分析 展望 完整代码下载链接:基于极限学习机的变压器故障分类,基于ELM的变压器故障预测(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.net/d…

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;小程序之类的页面 调调接口完成页面的渲…

Django笔记(二):模板templates

首 Django模板层是为动态生成html服务的&#xff0c;非本文重点。前后端分离的设计更为常见&#xff0c;尽量少的涉及Django模板层内容。本文记录Django如何找到一个html文件。 模板文件 在创建一个Django项目project后&#xff0c;目录下会生成一个同名目录和manage.py。创…

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;让你能够轻松驾驭这个强大的工具。 插件运行效…

==(双等)与 equals的区别

/* * 与equals()的区别 * 1.是关系运算符&#xff0c;equals()是0bject类中定义的方法 * 2.基本数据类型:使用比较值&#xff0c;无法使用equals() * 3.引用数据类型:使用比较内存地址;如果没有重写equals() * 仍然调用的是Object父类的equals()方法&#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 语…

【ARM 嵌入式 编译系列 2.3 -- GCC 编译参数学习 -Wa,-mimplicit-it=thumb 使用介绍】

请阅读【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 文章目录 问题背景-wa,-mimplicit-itthumb 介绍-wa 选项-mimplicit-itthumb 选项使用 -wa,-mimplicit-itthumb 问题背景 在移植 RT-Thread 时&#xff0c;使用Make 进行编译&#xff0c;结果遇到了下面问题&#xff1a;…

【正点原子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; 汽车维修管理、车辆接待、维修项目登记、维修领料、质检完工、消费结算 配件管理、财务管理、基础数据管理…

自存angular 复制功能 使用angular material design Clipboard cdk

import { Clipboard } from "angular/cdk/clipboard"; 实例化 constructor(private clipboard: Clipboard) {} 使用 参考angular clipboard cdk html&#xff1a; <button mat-button class"withdraw-btn" (click)"copyCode()"><mat-…

Vue3+Ts:使用i18n实现国际化与全局动态下拉框框切换语言

Vue3Ts&#xff1a;使用i18n实现国际化与全局动态下拉框框切换语言 一、下载依赖&#xff1a;二、创建ts文件并配置main.ts三&#xff0c;如何使用1.在<template>中使用2.在setup中使用 四、全局下拉框动态切换 一、下载依赖&#xff1a; npm install vue-i18nnex二、创…

二进制表示(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…