简单RAG(检索增强生成)方法存在文档块包含无关内容、用户问题表达不佳以及需要生成结构化查询的问题。为了解决这些问题,LangChain提供了几种高级检索方法,其中包括:
1.多表示索引 :创建更适合检索的文档摘要,提高检索效果。
查询转换( Transformer) :将用户问题转化为更优化的检索形式。 3.查询构建 :将问题转化为特定查询语法。
众所周知,Transformer、Router、Aggregator、Injector、Executor是LangChain
的核心组件,这里我们将重点介绍Transformer——查询转换方法:
1.重写-检索-阅读 :通过LLM重写用户问题,再进行检索,以提高检索效果。 2.回退提示 :生成备用问题,并结合原问题进行检索,提升检索结果的准确性。 3.跟进问题 :使用LLM将对话中的跟进问题转化为独立的搜索查询。 4.多查询检索 :LLM生成多个相关查询,并行检索不同子问题的答案。 5.RAG-融合 :通过多查询检索并使用互惠排名融合来优化文档排序。
这些方法的核心在于LLM提示词的设计与使用,不同提示词生成的查询形式可以显著影响检索效果。
查询转换
简单的RAG通常将文档拆分为多个块,嵌入它们,并检索与用户问题语义相似度较高的块。但这会带来几个问题:
(1)文档块可能包含无关内容,降低检索效果;
(2)用户问题可能表述不佳,影响检索;
(3)需要从用户问题生成结构化查询(例如,用于带有元数据过滤的向量库查询或SQL数据库查询)。
LangChain 提供了许多高级检索方法[1],帮助解决这些挑战。
(1)多表示索引 :创建适合检索的文档表示(如摘要),可参考上周的博客文章,了解使用多向量检索器的更多信息。
(2)查询转换 :本文将介绍几种将人类问题转换为提高检索效果的方法。
(3)查询构建 :将人类问题转换为特定查询语法或语言,后续文章将详细介绍。
在一个简单的RAG管道中,一般流程是将用户问题直接传递给嵌入模型。该嵌入结果与存储在向量库中的文档进行比较,返回k
个最相似的结果。
查询转换是指在将用户问题传递给嵌入模型之前,对其进行转换。
虽然这并不是新现象(查询扩展[2]已经在搜索中使用多年),但利用LLMs(大型语言模型)进行查询转换则是新的。
以下是一些利用LLMs生成新查询(或多个新查询)的方法,主要区别在于生成这些查询所用的提示词。
重写-检索-阅读
这篇论文使用LLM来重写 用户查询,而不是直接用原始查询进行检索。
因为原始查询并不总是对LLM最优的检索方式,尤其是在现实场景中……我们首先提示LLM重写查询,然后进行检索增强的阅读。
使用的提示词相对简单,可以在Hub上找到这里[3]:
链接:
• 论文[4]
• LangChain 实现[5]
回退提示
这篇论文使用LLM生成一个“回退”问题。这可以结合检索使用,也可以不结合检索。结合检索时,既使用“回退”问题,也使用原始问题进行检索,然后将两者的结果用于生成语言模型的回答。
这里[6]是使用的提示词:
链接:
• 论文[7]
• LangChain 实现[8]
跟进问题
查询转换最基本的使用场景是对话链中处理跟进问题。在处理跟进问题时,通常有三个选项:
1.只嵌入跟进问题。这意味着如果跟进问题基于之前的对话,或引用之前的内容,它将丢失这些上下文。例如,我先问“在意大利我能做什么?”然后再问“那里有什么食物?”——如果只嵌入“那里有什么食物?”,那么就无法知道“那里”指的是哪里。
2.嵌入整个对话(或最后的k
条消息)。问题在于如果跟进问题与之前的对话无关,可能会返回完全无关的结果,干扰生成。
3.使用LLM进行查询转换!
在最后这个选项中,你将整个对话(包括跟进问题)传递给LLM,并请求其生成搜索词。这是我们在WebLangChain[9]中使用的方法,也是大多数基于聊天的检索应用程序可能使用的方法。
问题变成了:使用什么提示词将整个对话转换为搜索查询?这里需要大量的提示词工程。以下是我们在WebLangChain中使用的提示词(将“查询生成”部分表述为构建独立问题)。可以在Hub上查看这里[10]。
多查询检索
在这种策略中,LLM被用来生成多个搜索查询。然后可以并行执行这些搜索查询,并一起传递检索到的结果。这在一个问题依赖多个子问题时非常有用。
例如,考虑以下问题:
红袜队和爱国者队,谁最近赢得了冠军?
这实际上需要两个子问题:
•“红袜队最近一次赢得冠军是什么时候?” •“爱国者队最近一次赢得冠军是什么时候?”
链接:
• LangChain 实现[11]
RAG-融合
最近的一篇文章基于多查询检索的想法。然而,与其传递所有文档,它们使用互惠排名融合来重新排序文档。
链接:
• 博客文章[12]
• LangChain 实现[13]
示例
以java版langchain4j中的实现为例,压缩query转换(Compressing Query Transformer):
"Read and understand the conversation between the User and the AI. " +
"Then, analyze the new query from the User. " +
"Identify all relevant details, terms, and context from both the conversation and the new query. " +
"Reformulate this query into a clear, concise, and self-contained format suitable for information retrieval.\n" +
"\n" +
"Conversation:\n" +
"{{chatMemory}}\n" +
"\n" +
"User query: {{query}}\n" +
"\n" +
"It is very important that you provide only reformulated query and nothing else! " +
"Do not prepend a query with anything!"
拓展query转换(Expanding Query Transformer):
"Generate {{n}} different versions of a provided user query. " +
"Each version should be worded differently, using synonyms or alternative sentence structures, " +
"but they should all retain the original meaning. " +
"These versions will be used to retrieve relevant documents. " +
"It is very important to provide each query version on a separate line, " +
"without enumerations, hyphens, or any additional formatting!\n" +
"User query: {{query}}"
结论
如你所见,进行查询转换有很多种方式。再次强调,这并不是一个新话题——但使用LLMs来做这件事是新的。这些方法的差异在于使用的提示词。编写提示词非常容易——几乎和想到它们一样容易。这不禁让人思考:你会想出哪些查询转换方法?让我们知道!
声明
本文由山行整理自:https://blog.langchain.dev/query-transformations/项目和网络,如果对您有帮助,请帮忙点赞、关注、收藏,谢谢~
References
[1]
高级检索方法: https://python.langchain.com/docs/modules/data\_connection/retrievers/?ref=blog.langchain.dev
[2]
查询扩展: https://www.searchenginejournal.com/what-is-google-query-expansion-cases-and-examples/7924/?ref=blog.langchain.dev
[3]
这里: https://blog.langchain.dev/query-transformations/smith.langchain.com/hub/langchain-ai/rewrite
[4]
论文: https://arxiv.org/pdf/2305.14283.pdf?ref=blog.langchain.dev
[5]
LangChain 实现: https://github.com/langchain-ai/langchain/blob/master/cookbook/rewrite.ipynb?ref=blog.langchain.dev
[6]
这里: https://smith.langchain.com/hub/langchain-ai/stepback-answer?ref=blog.langchain.dev
[7]
论文: https://arxiv.org/pdf/2310.06117.pdf?ref=blog.langchain.dev
[8]
LangChain 实现: https://github.com/langchain-ai/langchain/blob/master/cookbook/stepback-qa.ipynb?ref=blog.langchain.dev
[9]
WebLangChain: https://blog.langchain.dev/weblangchain/
[10]
这里: https://smith.langchain.com/hub/langchain-ai/weblangchain-search-query?ref=blog.langchain.dev
[11]
LangChain 实现: https://python.langchain.com/docs/modules/data\_connection/retrievers/MultiQueryRetriever?ref=blog.langchain.dev
[12]
博客文章: https://towardsdatascience.com/forget-rag-the-future-is-rag-fusion-1147298d8ad1?ref=blog.langchain.dev
[13]
LangChain 实现: https://github.com/langchain-ai/langchain/blob/master/cookbook/rag\_fusion.ipynb?ref=blog.langchain.dev