标准的 RAG 通常会将文档拆分成块,对其进行嵌入,然后检索与用户问题语义相似度高的块。但这会带来几个问题:(1) 文档块可能包含无关内容,从而降低检索效果;(2) 用户问题可能措辞不当,不利于检索;(3) 可能需要从用户问题生成结构化查询(例如,用于带元数据过滤的向量存储或 SQL 数据库进行查询)。
LangChain 提供了许多 高级检索方法 来帮助解决这些挑战。(1) 多表示索引:创建一个适合检索的文档表示(例如摘要)(在上周的 博文 中使用 Multi Vector Retriever 阅读此内容)。(2) 查询转换:在本文中,我们将回顾几种转换人类问题以改进检索的方法。(3) 查询构建:将人类问题转换为特定的查询语法或语言,这将在未来的文章中介绍。
如果您想到标准的 RAG 流程,其通用流程是获取用户问题并直接将其传递给嵌入模型。然后将该嵌入与存储在向量存储中的文档进行比较,并返回最相似的 k 个文档。

查询转换处理的是在传递给嵌入模型之前对用户问题进行转换。
以下是利用这一点的几种论文和检索方法的变体。它们都使用 LLM 来生成一个新的(或多个新的)查询,主要区别在于它们用于生成查询的提示。
Rewrite-Retrieve-Read
这篇论文使用 LLM 来重写用户查询,而不是直接使用原始用户查询进行检索。
因为原始查询不一定总是最适合 LLM 进行检索,尤其是在现实世界中……我们首先提示 LLM 重写查询,然后进行检索增强阅读。

使用的提示相对简单(在 Hub 上此处)

链接
Step back prompting
这篇论文使用 LLM 来生成一个“回溯”问题。这可以与检索一起使用,也可以不与检索一起使用。在使用检索时,将同时使用“回溯”问题和原始问题进行检索,然后将两个结果都用于为语言模型响应提供依据。

此处是使用的提示

链接
后续问题
查询转换最基本和最核心的应用是在对话链中处理后续问题。处理后续问题时,基本上有三种选择:
- 仅嵌入后续问题。这意味着,如果后续问题建立在先前的对话之上或引用了先前的对话,那么它将丢失该问题。例如,如果我先问“在意大利我可以做什么?”,然后问“那里有什么样的食物?”——如果我只嵌入“那里有什么样的食物?”,我将无法知道“那里”指的是哪里。
- 嵌入整个对话(或最后
k条消息)。这样做的问题是,如果后续问题与之前的对话完全无关,它可能会返回完全不相关的结果,从而在生成过程中造成干扰。 - 使用 LLM 进行查询转换!
在最后一个选项中,您将迄今为止的整个对话(包括后续问题)传递给 LLM,并要求它生成一个搜索词。这就是我们在 WebLangChain 中所做的,也是大多数基于聊天的检索应用程序可能做的事情。
那么问题来了:我应该使用什么提示将整个对话转换为搜索查询?这就是需要进行大量提示工程的地方。以下是我们为 WebLangChain 使用的提示(它将“查询生成”部分表述为构建一个独立的查询)。在 Hub 上此处可以找到它。

Multi Query Retrieval
在此策略中,LLM 用于生成多个搜索查询。然后可以并行执行这些搜索查询,并将检索到的结果一起传入。当单个问题可能依赖于多个子问题时,这非常有用。
例如,考虑以下问题:
红袜队和爱国者队谁最近赢得了总冠军?
这实际上需要两个子问题:
- “红袜队上一次赢得总冠军是什么时候?”
- “爱国者队上一次赢得总冠军是什么时候?”
链接
RAG-Fusion
一篇最近的文章建立在 Multi-Query Retrieval 的想法之上。然而,它们没有传入所有文档,而是使用倒数排名融合来重新排序文档。

链接
结论
如您所见,有许多不同的方法可以进行查询转换。同样,这不是一个新话题——但新的是利用 LLM 来实现这一点。这些方法之间的差异在于所使用的提示。编写提示非常容易——几乎和想到它们一样容易。这就引出了一个问题——您将想出什么样的查询转换?请告诉我们!