LlamaIndex中的查询引擎
概念
查询引擎是一个通用接口,允许你对数据提出问题。
查询引擎接收自然语言查询,并返回丰富的响应。它通常(但不总是)通过检索器构建在一个或多个索引之上。你可以组合多个查询引擎以实现更高级的功能。
提示
如果你想与数据进行对话(多次往返而不是单个问答),请查看聊天引擎。
使用模式
入门
从索引构建查询引擎:
query_engine = index.as_query_engine()
提示
要了解如何构建索引,请参见索引。
对数据提出问题:
response = query_engine.query("Who is Paul Graham?")
配置查询引擎
高级API
你可以直接从索引中构建和配置查询引擎,只需一行代码:
query_engine = index.as_query_engine(
response_mode="tree_summarize",
verbose=True,
)
注意:虽然高级API优化了易用性,但它并未暴露完整的可配置性。
查看响应模式以获取完整的响应模式列表及其功能。
低级组合API
如果你需要更细粒度的控制,可以使用低级组合API。具体来说,你可以显式构造一个QueryEngine对象,而不是调用index.as_query_engine(...)
。
注意:你可能需要查看API参考或示例笔记本。
from llama_index.core import VectorStoreIndex, get_response_synthesizer
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
# 构建索引
index = VectorStoreIndex.from_documents(documents)
# 配置检索器
retriever = VectorIndexRetriever(
index=index,
similarity_top_k=2,
)
# 配置响应合成器
response_synthesizer = get_response_synthesizer(
response_mode="tree_summarize",
)
# 组装查询引擎
query_engine = RetrieverQueryEngine(
retriever=retriever,
response_synthesizer=response_synthesizer,
)
# 查询
response = query_engine.query("What did the author do growing up?")
print(response)
流式处理
要启用流式处理,只需传递streaming=True
标志:
query_engine = index.as_query_engine(
streaming=True,
)
streaming_response = query_engine.query(
"What did the author do growing up?",
)
streaming_response.print_response_stream()
阅读完整的流式指南
查看端到端示例
定义自定义查询引擎
你还可以定义自定义查询引擎。只需子类化CustomQueryEngine
类,定义你想要的任何属性(类似于定义一个Pydantic类),并实现一个返回Response
对象或字符串的custom_query
函数。
from llama_index.core.query_engine import CustomQueryEngine
from llama_index.core.retrievers import BaseRetriever
from llama_index.core import get_response_synthesizer
from llama_index.core.response_synthesizers import BaseSynthesizer
class RAGQueryEngine(CustomQueryEngine):
"""RAG Query Engine."""
retriever: BaseRetriever
response_synthesizer: BaseSynthesizer
def custom_query(self, query_str: str):
nodes = self.retriever.retrieve(query_str)
response_obj = self.response_synthesizer.synthesize(query_str, nodes)
return response_obj
查看自定义查询引擎指南以获取更多详细信息。
响应模式
目前,我们支持以下选项:
-
refine:通过依次遍历每个检索到的文本块来创建和提炼答案。这会对每个节点/检索到的块进行单独的LLM调用。
详细信息:第一个块使用text_qa_template
提示进行查询。然后,答案和下一个块(以及原始问题)在另一个查询中使用refine_template
提示。依此类推,直到所有块都被解析。
如果一个块太大而无法适应窗口(考虑提示大小),则使用TokenTextSplitter
进行拆分(允许块之间有一些文本重叠),并且(新)附加块被视为原始块集合的块(因此也使用refine_template
进行查询)。
适用于更详细的答案。 -
compact(默认):类似于refine,但事先压缩(连接)块,从而减少LLM调用。
详细信息:尽可能多地填充文本(从检索到的块中连接/打包),使其适应上下文窗口(考虑text_qa_template
和refine_template
之间的最大提示大小)。如果文本太长而无法适应一个提示,则根据需要拆分为多个部分(使用TokenTextSplitter
,因此允许块之间有一些重叠)。
每个文本部分被视为一个“块”,并发送给refine合成器。
简而言之,它类似于refine,但LLM调用更少。 -
tree_summarize:使用
summary_template
提示查询LLM,次数根据需要多次,以便所有连接的块都被查询,从而得到多个答案,这些答案本身递归地用作tree_summarize
LLM调用的块,依此类推,直到只剩下一个块,因此只有一个最终答案。
详细信息:尽可能多地连接块,以适应上下文窗口使用summary_template
提示,并在需要时拆分它们(再次使用TokenTextSplitter
和一些文本重叠)。然后,对每个结果块/拆分使用summary_template
进行查询(没有refine查询!)并获取多个答案。
如果只有一个答案(因为只有一个块),那么它就是最终答案。
如果有多个答案,这些本身被视为块,并递归地发送给tree_summarize
过程(连接/拆分-适应/查询)。
适用于总结目的。 -
simple_summarize:将所有文本块截断以适应单个LLM提示。适用于快速总结目的,但由于截断可能会丢失细节。
-
no_text:仅运行检索器以获取本应发送给LLM的节点,而不实际发送它们。然后可以通过检查
response.source_nodes
进行检查。 -
accumulate:给定一组文本块和查询,将查询应用于每个文本块,同时将响应累积到一个数组中。返回所有响应的连接字符串。适用于需要对每个文本块单独运行相同查询的情况。
-
compact_accumulate:与accumulate相同,但会对每个LLM提示进行“压缩”,类似于compact,并对每个文本块运行相同的查询。
通过这些响应模式,你可以根据具体需求选择最适合的方式来处理查询和生成响应。
LlamaIndex中的流式响应
LlamaIndex支持在响应生成时进行流式传输。这允许你在完整响应完成之前开始打印或处理响应的开头部分。这可以显著减少查询的感知延迟。
设置
要启用流式传输,你需要使用支持流式传输的LLM。目前,流式传输由OpenAI、HuggingFaceLLM和大多数LangChain LLMs(通过LangChainLLM)支持。
注意:如果你选择的LLM不支持流式传输,将引发NotImplementedError
。
要使用高级API配置查询引擎以使用流式传输,请在构建查询引擎时设置streaming=True
。
query_engine = index.as_query_engine(streaming=True, similarity_top_k=1)
如果你使用低级API来组合查询引擎,请在构造响应合成器时传递streaming=True
:
from llama_index.core import get_response_synthesizer
synth = get_response_synthesizer(streaming=True, ...)
query_engine = RetrieverQueryEngine(response_synthesizer=synth, ...)
流式响应
在正确配置LLM和查询引擎后,调用query
现在返回一个StreamingResponse
对象。
streaming_response = query_engine.query(
"What did the author do growing up?",
)
响应在LLM调用开始时立即返回,而无需等待完整完成。
注意:在查询引擎进行多次LLM调用的情况下,只有最后一次LLM调用会被流式传输,响应在最后一次LLM调用开始时返回。
你可以从流式响应中获取生成器,并在令牌到达时进行迭代:
for text in streaming_response.response_gen:
# 在令牌到达时进行处理。
pass
或者,如果你只想在令牌到达时打印文本:
streaming_response.print_response_stream()
通过这些步骤,你可以利用LlamaIndex的流式传输功能,实时处理和显示LLM生成的响应,从而提升用户体验。