返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

使用LangChain和Llama-Index实现多重检索RAG

[复制链接]
链载Ai 显示全部楼层 发表于 前天 09:30 |阅读模式 打印 上一主题 下一主题

介绍查询扩展技术,阐释其在LangChain和Llama-Index中的实现及对提高检索效率的贡献。

在信息检索的世界里,查询扩展技术正引领着一场效率革命。本文将带读者深入了解这一技术的核心——多查询检索,以及其是如何在LangChain和Llama-Index中得到应用的。

1 查询扩展

查询扩展是一种信息检索技术,通过在原始查询的基础上增加相关或同义的词汇和短语来优化搜索结果。这种方法能够丰富查询的语义,提高检索系统的准确性和相关性。

在查询扩展的众多策略中,多查询检索是其中的一种。它通过生成多个相关的查询请求,从而拓宽搜索范围,帮助用户更全面地获取所需信息。这种技术尤其适用于处理复杂的查询需求,能够有效提高信息检索的效率和质量。

2 机制

系统在接到查询请求后,会先通过高级语言模型生成一个与原查询相近的新查询。这个新查询随后用于在Llama-Index中检索相关文档,从而获取与原查询高度相关的信息,增强上下文理解,确保结果更精准、更符合用户的实际需求。

2次LLM交互:

为精确生成查询,流程包括向大型语言模型(LLM)并行发出两次请求:初次使用gpt3模型,之后可能提升至gpt4或其他高级模型,以获取更丰富的查询结果。

3 实现方法

3.1 LangChain

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="""
Youareanassistanttoansweraquestionfromuserwithacontext.

Context:
{context}

Question:
{question}

Theresponseshouldbepresentedasalistofkeypoints,aftercreatingthetitleofthecontent,
formattedinHTMLwithappropriatemarkupforclarityandorganization.
"""
prompt=ChatPromptTemplate.from_template(tmpl)
chain={"question":RunnablePassthrough(),"context":final_retriever}\
|prompt\
|lc_model\
|StrOutputParser()\

result=chain.invoke("Wahtisthedoctalkingabout?")

MultiQueryRetriever 通过提供一套完整的类库,简化了任务执行过程。其核心机制是配备一个基础检索器,能够自动产生最多三个定制化的查询。这一过程中,检索操作的安全性和封装性得到了保障。

3.2 Llama-Index

实现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)

classMultiQueriesRetriever(BaseRetriever):
def__init__(self,base_retriever:BaseRetriever,model:OpenAI):
self.template=PromptTemplate("""YouareanAIlanguagemodelassistant.YourtaskistogenerateFive
differentversionsofthegivenuserquestiontoretrieverelevantdocumentsfromavector
database.Bygeneratingmultipleperspectivesontheuserquestion,yourgoalistohelp
theuserovercomesomeofthelimitationsofthedistance-basedsimilaritysearch.
Providethesealternativequestionsseperatedbynewlines.
Originalquestion:{question}""")
self._retrievers=[base_retriever]
self.base_retriever=base_retriever
self.model=model

defgen_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)
returnres.text.split("\n")

asyncdefrun_gen_queries(self,generated_queriesist[str])->List[NodeWithScore]:
tasks=list(map(lambdaq:self.base_retriever.aretrieve(q),generated_queries))
res=awaittqdm.gather(*tasks)
returnres[0]

def_retrieve(self,query_bundleueryBundle)->List[NodeWithScore]:
returnlist()

asyncdef_aretrieve(self,query_bundleueryBundle)->List[NodeWithScore]:
query=query_bundle.query_str
generated_queries=self.gen_queries(query)
query_res=awaitself.run_gen_queries(generated_queries)
returnquery_res



mr=MultiQueriesRetriever(base_retriever,li_model)

final_res=awaitRetrieverQueryEngine(mr).aquery(query_text)

重要的是通过继承BaseRetriever类,将其功能与基础检索器相融合,以便根据生成的查询来检索相应的信息。由于这些生成的查询是通过协程机制来实现的,因此需要对_aretrieve方法进行重写。这部分内容就不再展开详细说明了。

3.3 子问题查询引擎

Llama-Index包含一个名为SubQuestionQueryEngine的类,它基本上能够满足我们的需求。这个类的特点是将复杂查询分解成多个子问题,而不是创建一个与原查询“相似”的新查询。根据文档说明,可以通过以下代码来使用这个类:

query_engine_tools=[
QueryEngineTool(
query_engine=vector_query_engine,
metadata=ToolMetadata(
name="pg_essay",
description="aulGrahamessayonWhatIWorkedOn",
),
),
]

query_engine=SubQuestionQueryEngine.from_defaults(
query_engine_tools=query_engine_tools,
use_async=True,
)

response=query_engine.query(
"HowwasPaulGrahamslifedifferentbefore,during,andafterYC?"
)

SubQuestionQueryEngine的工作原理是将复杂的原始查询拆分成多个子问题,每个子问题都针对特定的数据源。这些子问题的答案不仅提供了必要的上下文信息,还为构建最终答案做出了贡献。每个子问题专门设计用来从相应的数据源中抽取关键信息。综合这些子问题的答案,可以得到对原始查询的完整回应。

此外,SubQuestionQueryEngine能够将一个复杂的查询细化为多个子问题,并为每个子问题指定相应的查询引擎进行处理。一旦所有子问题都得到解答,这些答案将被汇总并传递给响应合成器,以生成最终的答案。SubQuestionQueryEngine根据SubQuestion中的tool_name属性来确定应该使用哪个QueryEngineTool来处理每个子问题。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ