响应合成
响应合成器
概念
响应合成 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")
提示
要了解如何建立索引,请参阅索引
配置响应模式
响应合成器通常通过 kwarg 设置指定response_mode。
LlamaIndex 中已经实现了几个响应合成器:
- refine:通过依次浏览每个检索到的文本块来创建和完善答案。这会为每个节点/检索到的块进行单独的 LLM 调用。
- 详细信息:第一个块用于使用 text_qa_template提示的查询。然后答案和下一个块(以及原始问题)用于另一个带有refine_template提示的查询。依此类推,直到所有块都已解析。
如果某个块太大而无法放入窗口(考虑提示大小),则使用 进行拆分TokenTextSplitter (允许块之间有一些文本重叠),并且将(新的)附加块视为原始块集合的块(因此也使用 进行查询refine_template)。
希望能得到更详细的答案。
compact(默认):类似于refine但预先压缩(连接)块,从而减少 LLM 调用。 详细信息:填充尽可能多的文本(从检索到的块中连接/打包),使其适合上下文窗口(考虑text_qa_template和之间的最大提示大小refine_template)。如果文本太长而无法容纳在一个提示中,则会根据需要将其拆分为尽可能多的部分(使用TokenTextSplitter和,从而允许文本块之间有一些重叠)。
每个文本部分都被视为一个“块”并被发送到refine合成器。
简而言之,它类似于refine,但是 LLM 调用较少。
tree_summarizesummary_template:使用提示根据需要多次查询 LLM ,以便查询所有连接的块,从而产生尽可能多的答案,这些答案本身在tree_summarizeLLM 调用中递归用作块,依此类推,直到只剩下一个块,因此只有一个最终答案。 详细信息:使用提示尽可能多地连接块以适应上下文窗口summary_template,并在需要时拆分它们(再次使用TokenTextSplitter和一些文本重叠)。然后,查询每个结果块/拆分 summary_template(没有细化查询!)并获得尽可能多的答案。
如果只有一个答案(因为只有一个块),那么它就是最终答案。
如果有多个答案,这些答案本身将被视为块并递归发送到tree_summarize流程(连接/拆分以适应/查询)。
有利于总结目的。
simple_summarize:截断所有文本块以适合单个 LLM 提示。适合快速总结,但可能会因截断而丢失细节。 no_text:仅运行检索器来获取本应发送到 LLM 的节点,而不实际发送它们。然后可以通过检查来检查response.source_nodes。 context_only:返回所有文本块的连接字符串。 accumulate:给定一组文本块和查询,将查询应用于每个文本块,同时将响应累积到数组中。返回所有响应的连接字符串。当您需要针对每个文本块分别运行相同的查询时,这种方法非常有用。 compact_accumulate:与累积相同,但将“压缩”类似于的每个 LLM 提示 compact,并对每个文本块运行相同的查询。
自定义响应合成器
每个响应合成器都继承自 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
后,我们的优化模块能够过滤掉与所提问题无关的任何输入节点。这对于基于 RAG 的问答系统尤其有用,因为该系统需要从外部向量存储中检索给定用户查询的文本块。
如果您使用支持函数调用的 OpenAI 模型,则此选项特别有用。其他 LLM 提供程序或不支持本机函数调用的模型在生成此功能所依赖的结构化响应时可能不太可靠。
使用自定义提示模板(带有附加变量)
您可能希望自定义我们的响应合成器中使用的提示,并在查询时添加其他变量。
**kwargs
您可以在 for
中指定这些附加变量 get_response
。
例如,
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"
)
模块
请参阅完整的模块指南以了解更多详细信息。