响应合成器#
概念#
响应合成器(Response Synthesizer
)是使用用户查询和给定文本块集从大型语言模型(LLM)生成响应的组件。响应合成器的输出是一个 Response
对象。
生成响应的方法有很多种形式,从简单地迭代文本块到复杂地构建树。核心思想是简化使用 LLM 处理数据并生成响应的过程。
在查询引擎中使用时,响应合成器会在从检索器检索到节点后,以及运行任何节点后处理器后使用。
提示
对响应合成器在 RAG 工作流中的位置感到困惑?请阅读高级概念
使用模式#
独立使用响应合成器
from llama_index.core.data_structs import Node
from llama_index.core.response_synthesizers import ResponseMode
from llama_index.core import get_response_synthesizer
response_synthesizer = get_response_synthesizer(
response_mode=ResponseMode.COMPACT
)
response = response_synthesizer.synthesize(
"query text", nodes=[Node(text="text"), ...]
)
或者在创建索引后在查询引擎中使用
query_engine = index.as_query_engine(response_synthesizer=response_synthesizer)
response = query_engine.query("query_text")
您可以在下方找到所有可用响应合成器、模式以及如何构建自己的响应合成器的更多详细信息。
使用模式#
开始使用#
使用 response_mode
为查询引擎配置响应合成器
from llama_index.core.data_structs import Node
from llama_index.core.schema import NodeWithScore
from llama_index.core import get_response_synthesizer
response_synthesizer = get_response_synthesizer(response_mode="compact")
response = response_synthesizer.synthesize(
"query text", nodes=[NodeWithScore(node=Node(text="text"), score=1.0), ...]
)
或者,更常见的是,在创建索引后在查询引擎中使用
query_engine = index.as_query_engine(response_synthesizer=response_synthesizer)
response = query_engine.query("query_text")
提示
要了解如何构建索引,请参阅索引
配置响应模式#
响应合成器通常通过 response_mode
kwarg 设置来指定。
LlamaIndex 中已实现了多种响应合成器
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
来进行检查。context_only
:返回所有文本块的连接字符串。accumulate
:给定一组文本块和查询,将查询应用于每个文本块,同时将响应累积到一个数组中。返回所有响应的连接字符串。适用于需要针对每个文本块单独运行相同查询的情况。compact_accumulate
:与 accumulate 相同,但会像compact
一样“压缩”每个 LLM 提示,并对每个文本块运行相同的查询。
自定义响应合成器#
每个响应合成器都继承自 llama_index.response_synthesizers.base.BaseSynthesizer
。基本 API 非常简单,这使得创建自己的响应合成器变得容易。
也许您想自定义 tree_summarize
中每一步使用的模板,或者也许有新的研究论文详细介绍了一种生成查询响应的新方法,您可以创建自己的响应合成器并将其插入任何查询引擎或独立使用。
下面我们展示了 __init__()
函数以及每个响应合成器必须实现的两个抽象方法。基本要求是处理查询和文本块,并返回字符串(或字符串生成器)响应。
from llama_index.core import Settings
class BaseSynthesizer(ABC):
"""Response builder class."""
def __init__(
self,
llm: Optional[LLM] = None,
streaming: bool = False,
) -> None:
"""Init params."""
self._llm = llm or Settings.llm
self._callback_manager = Settings.callback_manager
self._streaming = streaming
@abstractmethod
def get_response(
self,
query_str: str,
text_chunks: Sequence[str],
**response_kwargs: Any,
) -> RESPONSE_TEXT_TYPE:
"""Get response."""
...
@abstractmethod
async def aget_response(
self,
query_str: str,
text_chunks: Sequence[str],
**response_kwargs: Any,
) -> RESPONSE_TEXT_TYPE:
"""Get response."""
...
使用结构化答案过滤#
在使用 "refine"
或 "compact"
响应合成模块时,您可能会发现尝试使用 structured_answer_filtering
选项会很有益。
from llama_index.core import get_response_synthesizer
response_synthesizer = get_response_synthesizer(structured_answer_filtering=True)
将 structured_answer_filtering
设置为 True
后,我们的 refine 模块能够过滤掉与所提问题无关的任何输入节点。这对于涉及从外部向量存储检索文本块以回答给定用户查询的基于 RAG 的问答系统特别有用。
如果您使用的是支持函数调用(function calling)的 OpenAI 模型,此选项特别有用。不支持原生函数调用的其他 LLM 提供商或模型在生成此功能所依赖的结构化响应方面可能不太可靠。
使用自定义提示模板(带附加变量)#
您可能想要自定义我们的响应合成器中使用的提示,并在查询时添加附加变量。
您可以在 get_response
的 **kwargs
中指定这些附加变量。
例如,
from llama_index.core import PromptTemplate
from llama_index.core.response_synthesizers import TreeSummarize
# NOTE: we add an extra tone_name variable here
qa_prompt_tmpl = (
"Context information is below.\n"
"---------------------\n"
"{context_str}\n"
"---------------------\n"
"Given the context information and not prior knowledge, "
"answer the query.\n"
"Please also write the answer in the tone of {tone_name}.\n"
"Query: {query_str}\n"
"Answer: "
)
qa_prompt = PromptTemplate(qa_prompt_tmpl)
# initialize response synthesizer
summarizer = TreeSummarize(verbose=True, summary_template=qa_prompt)
# get response
response = summarizer.get_response(
"who is Paul Graham?", [text], tone_name="a Shakespeare play"
)
模块#
有关更多详细信息,请参阅完整的模块指南。