在# LangChain4j系列:Advanced RAG 核心组件源码分析与实践 文章中介绍了Advanced RAG 增强器组件,本文开始对查询转换器 QueryTransformer 的优化方案进行一一详细解密并实战。
更详细的内容大家参考如下:
TOC
- 什么是查询转换
- 为什么需要查询转换
- 查询转换的目标
- 查询转换的技术实现
什么是查询转换
“查询转换”是 RAG 技术中一项优化技术,将用户给定的一个查询转换为一个或者多个查询。
转换时机:在查询向量数据库或其它渠道查询之前进行转换,将使用转换之后的查询进行查询。
为什么需要转换
- 用户的问题 “模糊”,或者比较 “简短”
- 用户使用了非标准化提问方式(如:错别字、口语化)
- 用户提问可能缺少一定的上下文信息
查询转化的目标
修改或扩展原来的 Query 来提高检索质量,让大模型更理解用户的查询意图!!
查询转换技术实现
目前已知的一些查询转换的方式和技术;
- 查询压缩 (Query compression)
- 查询扩展 (Query expansion)
- 查询重写 (Query re-writing)
- 后退提示 (Step-back prompting)
- 假设文档嵌入 (HyDE)
查询压缩
-
查询压缩含义:
(一个查询 + 历史上下文)生成另外一个查询 -> 语义提炼、去除冗余 -> 降低检索成本,减少无关召回。
-
解决问题
- 冗余信息干扰
- 语义模糊
- 检索成本过高
- 历史会话整合
-
需注意问题
- 增加一定的延迟和成本,但可以显著提升 RAG 过程的质量。
- 在实施过程中需要特别关注一个问题,用于压缩的 LLM 不一定需要和用于对话的 LLM 相同。
- 当对话历史较长且后续查询与对话上下文相关时,此转换器非常有用。
-
实现参考
- Spring AI: CompressionQueryTransformer
- LangChain4J: CompressingQueryTransformer
两者的实现原理一样,都是基于 提示词 + 大模型
- Spring AI 提示词
Given the following conversation history and a follow-up query, your task is to synthesize a concise, standalone query that incorporates the context from the history. Ensure the standalone query is clear, specific, and maintains the user's intent. Conversation history: {history} Follow-up query: {query} Standalone query:中文提示词
给定以下对话历史和一个后续查询,你的任务是综合出一个简洁的、独立的查询,该查询要融入历史中的上下文。确保这个独立查询清晰、具体,并保持用户的意图。 对话历史:{history} 后续查询:{query} 独立查询:- LangChain4J 实现
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. Conversation: {{chatMemory}} User query: {{query}} It is very important that you provide only reformulated query and nothing else! \ Do not prepend a query with anything!中文提示词
阅读并理解用户与人工智能之间的对话。然后,分析用户的新查询。从对话和新查询中识别所有相关细节、术语和上下文。将此查询重新表述为清晰、简洁且自成一体的格式,以适合信息检索。 对话:{{chatMemory}} 用户查询:{{query}} 至关重要的是,你只需提供重新表述后的查询,其他内容一概不要!不要在查询前添加任何内容!
通过总结 Spring AI 和 LangChain4J 两个框架的实现,就是将用户的一个查询,结合会话上下文,将用户的查询和会话上下文(短期记忆或者长期记忆)改写为清晰、准确、相关性、自描述的新查询。
举个例子:
User: Tell me about John Doe
AI: John Doe was a ...
User: Where did he live?
以上为用户的两轮对话,当用户再次问到 Where did he live? 时,会有以下几种情况;
- 如果不传历史会话上下文信息,此时大模型并不知道这个 he 是谁。
- 如果传输上下文,不压缩,一并传给大模型,大模型通过上下文信息能够推断出 he 就是 John Doe,但是传输的无关信息比较多
- 如果传输上下文,压缩,然后传给大模型,经过压缩查询直接会改写 Where did John Doe live 查询。
因此经过压缩后,用户的查询会更清晰、准确且自描述。
查询扩展
- 查询扩展的含义:
一个查询 扩展为 多个查询 -> 加工、扩写、改写 -> 提升召回率
利用大语言模型为用户原始查询补充相关术语、重构表达或生成多角度变体,弥补用户提问与知识库中文档表述的 “词汇鸿沟”,进而提高检索的召回率和准确度,最终让生成的答案更准确全面。
-
解决问题
-
解决术语不匹配问题
用户提问通常使用通俗语言提问,而知识库多采用专业术语。比如:用户提问“如何笔记本电池更耐用”,文档可能“延长笔记本电脑电池寿命的方法”,直接检索易匹配失败。扩展后补充 “寿命”、“延长”等词时就能解决问题。
-
覆盖模糊与长尾需求
“好的编程工具” 这是一个模糊查询,扩展补充 “Python 编程工具”,“代码编辑工具” 等。
-
强化语义理解
覆盖同一概念的不同表表述,像 “新冠” 与 “COVID-19”,“汽车”与“轿车”、“车辆” 等。
-
-
实现方法
-
同义词与词典扩展
借助通用或者领域词典,同义词库,近义词。 如:汽车 -> "汽车、轿车、车辆"
-
语义与嵌入扩展
基于词嵌入或预训练捕捉深层语义关联,筛选语义相似术语,能挖掘非字面相关的词汇。 如:“太阳能” -> "太阳能 可再生能源 光伏电池"。
-
伪相关反馈扩展
先对原始查询做初步检索,提取排名靠前文档中的高频相关词,在用这些词汇扩展查询,适应性强。如:气候变化 -> 初步查询频繁提及 冰川融化,海平面上升
-
多查询变体扩展
通过模型生成多个不同角度的同义查询,从多维度覆盖用户需求。如:推荐装修风格 -〉哪些装修风格最受欢迎。推荐流行的家居装修风格
-
知识图谱扩展
依托领域知识图谱,基于实体间的关联关系扩展术语,能融入丰富的领域背景信息。如:特斯拉 -> 特斯拉 电动汽车 埃隆·马斯克 新能源汽车
-
从 Spring AI 以及 LangChain4J 实现来看,是通过基于大模型实现的多查询变体扩展,另外几种实现方法可以自行实现。
- Spring AI
You are an expert at information retrieval and search optimization.
Your task is to generate {number} different versions of the given query.
Each variant must cover different perspectives or aspects of the topic,
while maintaining the core intent of the original query. The goal is to
expand the search space and improve the chances of finding relevant information.
Do not explain your choices or add any other text.
Provide the query variants separated by newlines.
Original query: {query}
Query variants:
中文提示词
你是信息检索和搜索优化方面的专家。你的任务是生成 {number} 个不同版本的给定查询。
每个变体都必须涵盖该主题的不同角度或方面,同时保持原始查询的核心意图。目标是扩大搜索范围,提高找到相关信息的几率。
不要解释你的选择或添加任何其他文本。提供的查询变体之间用换行分隔。
原始查询:{query}
查询变体:
- LangChain4J
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!
User query: {{query}}
中文
生成 n 个不同版本的用户提供的查询。
每个版本的措辞都应不同,使用同义词或替代句式,但都要保留原意。
这些版本将用于检索相关文档。
务必将每个查询版本放在单独的一行,不要使用编号、连字符或任何额外格式!
用户查询:{{query}}
查询重写
学习中,逐步完善
Step-Back Prompting
学习中,逐步完善
HyDE
学习中,逐步完善