来源:互联网 更新时间:2026-07-31 14:02
在信息检索的世界里,查询扩展技术正引领着一场效率革命。那么,这块“拼图”具体怎么运作?LangChain和Llama-Index又是如何落地的?本文将带读者深入了解这一技术的核心——多查询检索,以及它在这两个主流框架中的实现差异。

先说几个核心判断:当你的查询太宽泛或太模糊时,传统检索容易“跑偏”,而多查询检索通过生成多个角度的问题,能显著提升召回率。这背后,其实是对“语义鸿沟”的一种巧妙弥补。
什么是查询扩展?简单来说,它是一种信息检索技术,通过在原始查询上叠加相关或同义的词汇,来优化搜索结果。这种方法能丰富查询的语义,提升检索系统的准确性和相关性。
在多查询检索中,查询扩展正是其核心策略。它会生成多个相关的查询请求,从而拓宽搜索范围,帮助用户更全面地获取所需信息。对于复杂查询,这种技术尤为有效——比如你想找“AI在医疗领域的应用”,它会自动衍生出“机器学习诊断”、“深度学习影像识别”等变体,大大降低遗漏风险。
当系统接收到一个查询请求后,并不会急着直接去数据库里捞信息,而是先通过高级语言模型“脑补”出一个与原查询相近的新查询。这个新查询随后用于在Llama-Index中检索相关文档,从而获取与原查询高度相关的信息。整个过程增强了上下文理解,确保结果更精准、更符合用户的实际需求。
为了精确生成查询,流程包括向大型语言模型(LLM)并行发出两次请求:初次使用gpt3模型,之后可能提升至gpt4或其他高级模型,以获取更丰富的查询结果。这种分层调用,本质上是一种“先粗筛、再精调”的策略。
loader = UnstructuredPDFLoader(FILE_NAME)
docs = loader.load()
text_splitter = SentenceTransformersTokenTextSplitter()
texts = text_splitter.split_documents(docs)
emb = OpenAIEmbeddings(openai_api_key=openai.api_key)
vec_db = Chroma.from_documents(documents=texts, embedding=emb)
lc_model = ChatOpenAI(openai_api_key=openai.api_key, temperature=1.5)
base_retriever = vec_db.as_retriever(k=K)
final_retriever = MultiQueryRetriever.from_llm(base_retriever, lc_model)
tmpl = """
You are an assistant to answer a question from user with a context.
Context:
{context}
Question:
{question}
The response should be presented as a list of key points, after creating the title of the content,
formatted in HTML with appropriate markup for clarity and organization.
"""
prompt = ChatPromptTemplate.from_template(tmpl)
chain = {"question": RunnablePassthrough(), "context": final_retriever}
| prompt
| lc_model
| StrOutputParser()
result = chain.invoke("Waht is the doc talking about?")
LangChain的实现相对简单,很大程度上是因为MultiQueryRetriever这个类已经帮我们封装好了细节。它的核心机制很简单:配备一个基础检索器,然后自动生成最多三个定制化的查询。整个过程安全、封装,开发者只管调用就行。
Llama-Index的实现就稍微“硬核”一些了——因为它要求我们不仅要手动创建“生成的查询”,还得自行实现这些查询的检索流程。面对多个查询的需求,这里采用了必要的协程机制来确保过程的顺利进行。
vector_index: BaseIndex = VectorStoreIndex.from_documents(
docs,
service_context=service_context,
show_progress=True,
)
base_retriever = vector_index.as_retriever(similarity_top_k=K)
class MultiQueriesRetriever(BaseRetriever):
def __init__(self, base_retriever: BaseRetriever, model:OpenAI):
self.template = PromptTemplate("""You are an AI language model assistant. Your task is to generate Five
different versions of the given user question to retrieve relevant documents from a vector
database. By generating multiple perspectives on the user question, your goal is to
help the user overcome some of the limitations of the distance-based similarity search.
Provide these alternative questions seperated by newlines.
Original question: {question}""")
self._retrievers = [base_retriever]
self.base_retriever = base_retriever
self.model = model
def gen_queries(self, query) -> List[str]:
gen_queries_model = OpenAI(model="gpt-3-turbo", temperature=1.5)
prompt = self.template.format(question=query)
res = self.model.complete(prompt)
return res.text.split("n")
async def run_gen_queries(self,generated_queries: List[str]) -> List[NodeWithScore]:
tasks = list(map(lambda q: self.base_retriever.aretrieve(q), generated_queries))
res = await tqdm.gather(*tasks)
return res[0]
def _retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
return list()
async def _aretrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
query = query_bundle.query_str
generated_queries = self.gen_queries(query)
query_res = await self.run_gen_queries(generated_queries)
return query_res
mr = MultiQueriesRetriever(base_retriever, li_model)
final_res = await RetrieverQueryEngine(mr).aquery(query_text)
关键一步是继承BaseRetriever类,将其功能与基础检索器相融合,以便根据生成的查询来检索相应信息。由于这些生成的查询是通过协程机制来实现的,因此需要对_aretrieve方法进行重写。这段代码的核心逻辑是:先生成多个问题,再并行检索,最后汇总结果。如果你熟悉Python的异步编程,这种模式会非常自然。
Llama-Index还提供了一个叫SubQuestionQueryEngine的类,它基本上能满足我们对复杂查询的需求。有趣的是,这个类走的不是“生成相似查询”的路子,而是把复杂查询分解成多个子问题。来看具体用法:
query_engine_tools = [
QueryEngineTool(
query_engine=vector_query_engine,
metadata=ToolMetadata(
name="pg_essay",
description="Paul Graham essay on What I Worked On",
),
),
]
query_engine = SubQuestionQueryEngine.from_defaults(
query_engine_tools=query_engine_tools,
use_async=True,
)
response = query_engine.query(
"How was Paul Grahams life different before, during, and after YC?"
)
SubQuestionQueryEngine的工作原理是将复杂的原始查询拆分成多个子问题,每个子问题都针对特定的数据源。这些子问题的答案不仅提供了必要的上下文信息,还为构建最终答案做出了贡献。每个子问题专门设计用来从相应的数据源中抽取关键信息,综合这些答案,就能得到对原始查询的完整回应。
此外,SubQuestionQueryEngine能够将一个复杂的查询细化为多个子问题,并为每个子问题指定相应的查询引擎进行处理。一旦所有子问题都得到解答,这些答案将被汇总并传递给响应合成器,以生成最终的答案。这个过程中,引擎会根据SubQuestion中的tool_name属性,决定使用哪个QueryEngineTool来处理每个子问题。
摩托车活塞环性能如何
ThinkBook系列最新价格全解析:2026年选购避坑与实时询价指南
Ondo将于今日上线股票永续合约
暗黑4S14野蛮人终局BD攻略
区块链OTC交易所有哪几家比较正规?
Binance新增15种bStocks代币化证券为杠杆抵押资产
货拉拉如何查看历史订单 货拉拉往期行程轨迹查询【功能教学】
Meme币DOGS今晚上线!开局就解锁91%代币是否带来风险?
晶核艾尔莎角色盘点 晶核艾尔莎强度分析与实战表现
剑侠世界3雪峰论剑怎么打-剑侠世界3雪峰论剑打法介绍
五千元以下的笔记本几乎消失!经销商:至少一年看不到涨价尽头
Intel喜讯连连:18A工艺良率提升到85%、CPU将涨价15%
今日小鸡庄园答案2026.7.2
美债股纳斯达克首盘暴跌38%且加密代理交易解体,AVAX价格何去何从?
男生头像配网名可爱(精选100个)
赵云与阿斗神兵符使用教程 神兵符怎么使用
国家养老服务消费补贴上线京东
余姚的路虎4s店在哪个位置
英伟达机器人团队在京沪深招人,聚焦具身智能等四大领域
一站式PDF转Markdown解决方案PDF3MD
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc