Skip to content
LlamaIndex 文档版本 跟随上游 源快照 6e927555 更新于 2026-10-15

概念

响应合成器(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")

提示

如何构建索引,见索引(Indexing)

配置响应模式

响应合成器通常通过 response_mode 这个关键字参数来指定。

LlamaIndex 已经实现了若干种响应合成器:

  • refine:依次遍历每个检索到的文本块来先生成再精修回答。每个 Node/检索块都会单独调用一次 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 查询(这里没有 精修 查询!),得到相应数量的回答。

    如果只有一个回答(也就是只有一个块),那它就是最终回答。

    如果有多个回答,它们会作为块被递归送回 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 问答系统,这一点尤其有用。

如果你用的是支持函数调用的 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"
)

模块

更多细节见完整的模块指南。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。