概述
查询引擎是一个通用接口,允许您对数据提出问题。 查询引擎接受自然语言查询,并返回丰富的响应。它通常(但并非总是)通过检索器构建在一个或多个索引上。您可以组合多个查询引擎来实现更高级的功能。
注意:如果您想与数据进行对话(多次来回而不是单次问答),请查看ChatEngine相关内容。
使用范式
常规使用
query_engine = index.as_query_engine()
response = query_engine.query("Who is Paul Graham.")
流式输出
流式输出时当大模型有内容时就先输出,然后连续输出,这样可以提升用户体验。
query_engine = index.as_query_engine(streaming=True)
streaming_response = query_engine.query("Who is Paul Graham.")
streaming_response.print_response_stream()
使用流程
开始使用
从索引构建查询引擎:
query_engine = index.as_query_engine()
对您的数据提出问题
response = query_engine.query("Who is Paul Graham?")
配置查询引擎
高层API
您可以通过 1 行代码直接从索引构建和配置查询引擎:
query_engine = index.as_query_engine(response_mode="tree_summarize",verbose=True,
)
响应模式(response_mode)在后面章节说明。
低层次组合API
如果您需要更精细的控制,可以使用层次组合API。具体来说,您将显式构造一个 QueryEngine 对象,而不是调用 index.as_query_engine(...)。
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()
响应模式(response_mode)说明
目前,支持以下选项:
-
refine(完善)响应
通过顺序浏览每个检索到的文本块来创建和完善回答。这会对每个节点/检索到的块(Node/retrieved chunk)进行单独的LLM调用。
详细过程如下:第一个块在使用 text_qa_template 提示词的查询中使用。然后,回答和下一个块(以及原始问题)将在另一个具有refine_template提示词的查询中使用。依此类推,直到解析完所有块。
如果块太大而无法容纳在窗口中(考虑提示词大小),则使用 TokenTextSplitter 对其进行分割(允许块之间有一些文本重叠),(新的)附加块被视为原始块集合的块(因此也可以使用refine_template进行查询)。
该选项,适合更详细的答案。
-
compact
(紧凑)响应
compact响应模式类似于refine,但会预先压缩(拼接)块,从而减少 LLM 调用。
详细过程如下:填充尽可能多的文本(对检索到的数据块进行 拼接/打包),使其适合上下文窗口(考虑text_qa_template和refine_template 的最大提示词size的值)。如果文本太长而无法容纳在一个提示中,则会根据需要将其拆分为多个部分(使用 TokenTextSplitter,从而允许文本块之间存在一些重叠)。
每个文本部分都被视为一个chunk(块),并被发送到refine合成器。 简而言之,它从原理上基本上和refine相同,但 LLM 调用较少。
-
tree_summarize 响应模式
根据需要多次使用summary_template提示词模板来查询LLM,以便查询所有串联的块,从而产生尽可能多的答案,这些回答本身在使用tree_summarize模板来调用LLM时,递归地被作一个数据块来使用,依此类推,直到只剩下一个块,因此只有一个最终答案。
详细过程如下:使用summary_template提示词模板尽可能多地拼接数据块以适应上下文窗口,并在需要时分割它们(再次使用TokenTextSplitter和一些文本重叠)。然后,根据summary_template查询每个生成的块/分割(没有细化查询!)并获得尽可能多的答案。
如果只有一个答案(因为只有一大块),那么它就是最终答案。
如果有多个答案,这些本身将被视为块并递归发送到 tree_summarize 进程(连接/拆分以适合/查询)。
总的来说,该选项,适合总结目的。
-
simple_summarize:模式截断所有文本块以适合单个 LLM 提示。适合快速总结,但可能会因截断而丢失细节。
-
no_text:仅运行检索器来获取本应发送到 LLM 的节点,而不实际发送它们。然后可以通过检查response.source_nodes来检查。
-
accumulate:给定一组文本块和查询,将查询应用于每个文本块,同时将响应累积到数组中。返回所有响应的串联字符串。适合当您需要对每个文本块单独运行相同的查询时。
-
compact_accumulate:与accumulate 相同,但会像compact 一样“压缩”每个LLM 提示,并对每个文本块运行相同的查询。
小结
本文说明了查询引擎(QueryEngine)的使用范式,并说明了不同响应模式的实现逻辑。