在现代自然语言处理(NLP)领域,检索增强生成(RAG)系统因其能够结合外部知识库和大语言模型的强大生成能力,成为了提升信息检索质量的主流解决方案之一。然而,传统的 RAG 流程存在诸多挑战,尤其是在查询处理阶段,这可能直接影响检索的准确性和效率。为了解决这些问题,Self-querying prompting(自查询提示)应运而生,作为一种优化 RAG 系统查询过程的技术,显著提升了从向量数据库中检索相关信息的精度与质量。
一、背景
在理解 Self-querying prompting 之前,我们首先需要了解传统的 RAG 系统是如何工作的,以及为什么这一技术变得如此重要。
1. 什么是 RAG 系统?
检索增强生成(RAG, Retrieval-Augmented Generation)是一种结合了检索和生成的混合式 NLP 系统。RAG 的优势在于它可以利用外部知识库来帮助大模型回答更复杂的问题。例如,当用户输入问题时,RAG 系统会首先通过检索模块(通常基于向量搜索的方式)从庞大的知识库中获取最相关的文档片段(chunks),然后将这些片段整合到生成模型的输入中,帮助生成模型给出更准确、更符合上下文的回答。

这种方法尤其适合解决知识密集型任务,比如技术支持、客户服务、信息查询等场景。然而,传统的 RAG 流程中直接使用用户的原始查询进行检索可能导致以下问题:
- 查询不具体:用户输入的查询可能过于宽泛或模糊,导致检索结果不够精准。
- 冗余信息:查询中可能含有与检索任务无关的多余信息,干扰检索效果。
- 缺少上下文:部分查询缺乏必要的上下文信息,使得检索效果不佳。
这些问题会导致模型生成的回答不够准确或不够相关。因此,如何优化查询,提升 RAG 系统的检索效率成为了关键。
2. 为什么需要 Self-querying prompting?
传统的查询优化方法通常依赖于用户手动调整查询内容,这对于不熟悉系统运作的用户来说并不友好。Self-querying prompting 的出现解决了这一难题,它通过自动优化查询的方式,使得 RAG 系统能够更智能、更高效地获取到准确的相关信息。
二、Self-querying prompting 的步骤与原理
Self-querying prompting 是通过一系列步骤来优化查询的,每一个步骤都与提高检索结果的精度和效率息息相关。下面我们逐一探讨每个步骤的具体细节及其背后的工作原理。

1. 信息抽取
信息抽取是 Self-querying prompting 的核心步骤之一。在这个阶段,系统利用大语言模型(如 GPT)对用户输入的原始查询进行分析和处理,从中提取出关键的属性和与检索任务相关的信息。
关键属性与非属性类信息:
关键属性(key attributes)是与查询直接相关的内容,通常包括用户的具体需求。例如,当用户查询一款商品时,关键属性可能包括价格、颜色、品牌等;而在查询电影或文章时,关键属性可能是导演、年份、评分等。
非属性类信息指的是那些可能帮助模型更好理解查询的背景信息。这些信息可能不直接属于查询的核心内容,但在上下文理解中扮演着重要角色。例如,用户可能会提供产品描述、使用场景等信息,帮助模型生成更符合预期的查询。
2. 生成过滤条件
在从查询中抽取关键信息后,接下来是生成过滤条件(filtered fields)。这些过滤条件可以被看作是检索系统的'预筛选器',它们帮助减少与用户查询无关的结果。
过滤条件通常基于元数据(metadata),如产品类别、价格区间、用户评分等。通过对这些条件的设定,向量数据库可以在执行查询之前,先排除掉那些不符合基本需求的文档片段,从而提高整体检索的精度。
例如,在查询一款'价格低于 20 美元的黑色皮革迷你裙'时,过滤条件可以包括:颜色为黑色、材质为皮革、价格在 20 美元以下。这些过滤条件会大大减少数据库中的无关文档,提高检索效率。
3. 生成新的查询
在有了过滤条件之后,系统基于抽取的关键信息和上下文信息生成一个新的、更精准的查询(user query)。这个查询往往比用户的原始输入更加简洁和明确,适合在向量数据库中进行搜索。
生成的新查询不仅具有更高的准确性,而且能够更好地体现用户的真实需求。例如,用户可能输入了很多额外的描述信息,而新查询会去掉这些冗余部分,只保留与检索任务相关的关键信息。
4. 执行检索
使用生成的过滤条件和优化后的查询,系统接下来在向量数据库中执行检索操作。向量数据库会返回一组与新查询最相似的文档片段。
向量检索是一种通过将文本转换为向量表示,并利用相似性度量(如余弦相似度)来搜索数据库的方法。与传统的基于关键词的搜索相比,向量检索可以更好地处理语义相似性,从而提高检索结果的相关性。
5. 排序和返回结果
在完成检索后,系统会对返回的文档片段进行排序,确保最相关的内容优先显示给用户。排序过程中,系统会根据查询中的关键信息和上下文线索,对检索到的文档进行优先级排序。
排序后的文档片段会整合到最终的 prompt 中,供大模型生成回答。通过这种方式,用户可以获得更符合预期的答案。
三、示例应用
为了更好地理解 Self-querying prompting 的实际应用,我们来看一个具体的示例。假设用户输入了以下查询:'I want a black leather mini skirt less than twenty dollars.'
步骤 1:信息抽取
- 关键属性:颜色(black)、材质(leather)、类型(mini skirt)、价格(less than twenty dollars)。
- 非属性类信息:产品描述(mini skirt)。
步骤 2:生成过滤条件
- 生成过滤条件:颜色(black)、材质(leather)、价格(< 20 美元)。
步骤 3:生成新的查询
- 生成的新查询:'black leather mini skirt'。
步骤 4:执行检索
- 使用过滤条件(颜色、材质、价格)和新的查询('black leather mini skirt')在向量数据库中进行搜索。
- 检索结果包含多个与查询匹配的文档片段。
步骤 5:排序和返回结果
对检索到的文档片段进行排序,确保价格在 20 美元以下且符合其他条件的文档片段优先返回。
将排序后的文档片段整合到最终的 prompt 中,供大模型生成回答。
四、Self-querying prompting 的优势
Self-querying prompting 为 RAG 系统带来了以下几方面的显著优势:
- 提高检索准确性:通过优化查询,系统能够更好地理解用户需求,确保检索结果更加精准。
- 减少冗余信息:过滤掉查询中多余的部分,避免不必要的信息干扰检索。
- 增强上下文理解:通过上下文信息生成更合适的查询,帮助大模型生成更具相关性的回答。
- 用户友好:无需用户手动优化查询,系统自动处理查询优化,提升了整体用户体验。
五、实现示例
以下是一个使用 LangChain 和 OpenAI API 实现 Self-querying prompting 的 Python 代码示例。该示例展示了如何配置元数据字段并初始化 SelfQueryRetriever。
import os
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv())
from langchain_openai import ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
from langchain.chains.query_constructor.base import AttributeInfo
from langchain.retrievers.self_query.base import SelfQueryRetriever
llm = ChatOpenAI()
docs = [
Document(
page_content="A bunch of scientists bring back dinosaurs and mayhem breaks loose",
metadata={"year": 1993, "rating": 7.7, "genre": "science fiction"},
),
Document(
page_content="Leo DiCaprio gets lost in a dream within a dream within a dream within ...",
metadata={"year": 2010, "director": "Christopher Nolan", "rating": 8.2},
),
Document(
page_content="A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea",
metadata={"year": 2006, "director": "Satoshi Kon", "rating": 8.6},
),
Document(
page_content="A bunch of normal-sized women are supremely wholesome and some men pine after them",
metadata={: , : , : },
),
Document(
page_content=,
metadata={: , : },
),
Document(
page_content=,
metadata={
: ,
: ,
: ,
: ,
},
),
]
vectorstore = Chroma.from_documents(docs, OpenAIEmbeddings())
metadata_field_info = [
AttributeInfo(
name=,
description=,
=,
),
AttributeInfo(
name=,
description=,
=,
),
AttributeInfo(
name=,
description=,
=,
),
AttributeInfo(name=, description=, =
),
]
document_content_description =
retriever = SelfQueryRetriever.from_llm(
llm,
vectorstore,
document_content_description,
metadata_field_info,
)
(retriever.invoke())
(retriever.invoke())
(retriever.invoke())
(retriever.invoke(
))
六、最佳实践与注意事项
在实际部署 Self-querying prompting 时,为了确保系统稳定运行并获得最佳效果,建议遵循以下最佳实践:
- 元数据设计:元数据的结构应清晰且规范。确保所有用于过滤的字段都有明确的类型定义(如字符串、整数、浮点数),这有助于 LLM 正确解析查询意图。
- 查询复杂度控制:虽然 Self-querying 能处理复杂查询,但过长的查询可能导致 LLM 在生成过滤条件时产生幻觉。建议对输入查询进行预处理,去除明显的噪声。
- 向量索引优化:确保向量数据库的索引参数经过调优,以平衡检索速度与精度。对于大规模数据集,可以考虑分层索引策略。
- 错误处理:在代码实现中应加入异常捕获机制,防止因 LLM 输出格式错误导致整个检索流程中断。
七、总结
Self-querying prompting 在优化 RAG 系统查询的过程中发挥了至关重要的作用。通过信息抽取、过滤条件生成、新查询生成等步骤,系统能够更加准确地理解和满足用户需求,从而提升检索效率和生成质量。在日益复杂的 NLP 应用场景中,这一技术为提高用户体验和系统性能提供了强有力的支持。随着大模型能力的进一步提升,Self-querying 有望成为构建企业级知识库应用的标准组件之一。