Skip to content

响应合成器#

概念#

响应合成器(Response Synthesizer)是通过用户查询和给定文本块集合,利用大语言模型(LLM)生成响应的组件。其输出是一个Response对象。

实现方式多种多样,从简单的文本块迭代到复杂的树状结构构建。核心目标是简化基于数据使用LLM生成响应的流程。

在查询引擎中,响应合成器在检索器获取节点后执行,且在所有节点后处理器运行完毕后生效。

Tip

不清楚响应合成器在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")

Tip

学习如何构建索引,请参阅索引构建

配置响应模式#

响应合成器通常通过response_mode参数指定。LlamaIndex已实现多种响应模式:

  • refine:通过顺序处理每个检索到的文本块来创建并优化答案。每个节点/文本块都会触发独立的LLM调用。

细节: 首个文本块使用text_qa_template提示词进行查询。随后将答案与下一个文本块(及原始问题)结合,使用refine_template提示词进行二次查询。该过程循环直至处理完所有文本块。

若文本块超出上下文窗口限制(考虑提示词大小),则使用TokenTextSplitter进行分割(允许文本块间存在重叠),新增块将作为原始集合的一部分继续参与refine_template查询。

适用于需要详细答案的场景。

  • compact(默认模式):类似refine,但会预先压缩(连接)文本块,减少LLM调用次数。

细节: 将检索到的文本块尽可能多地拼接至上下文窗口(考虑text_qa_templaterefine_template的最大提示词尺寸)。若文本过长,则使用TokenTextSplitter分割为多个部分(允许部分重叠)。

每个文本部分视为独立"块"并发送至refine合成器。简言之,这是减少LLM调用次数的优化版refine

  • tree_summarize:使用summary_template提示词递归查询LLM,直到最终生成单一答案。

细节: 尽可能拼接文本块至上下文窗口限制(使用summary_template提示词),必要时进行分割(使用带重叠的TokenTextSplitter)。随后查询每个生成的块/分割(不进行_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 的问答系统特别有用,这类系统需要从外部向量存储中检索文本块来响应用户查询。

如果您使用的是支持函数调用的 OpenAI 模型,此选项将尤为实用。其他不具备原生函数调用支持的 LLM 提供商或模型在生成该功能依赖的结构化响应时可能可靠性较低。

使用自定义提示模板(含附加变量)#

您可能需要自定义响应合成器中使用的提示模板,并在查询时添加额外变量。

这些附加变量可以通过 get_response**kwargs 参数指定。

例如:

from llama_index.core import PromptTemplate
from llama_index.core.response_synthesizers import TreeSummarize

# 注意:这里我们添加了一个额外的 tone_name 变量
qa_prompt_tmpl = (
    "上下文信息如下。\n"
    "---------------------\n"
    "{context_str}\n"
    "---------------------\n"
    "请仅根据上下文信息(不使用先验知识)"
    "回答查询。\n"
    "并请使用{tone_name}的语气风格作答。\n"
    "查询:{query_str}\n"
    "回答:"
)
qa_prompt = PromptTemplate(qa_prompt_tmpl)

# 初始化响应合成器
summarizer = TreeSummarize(verbose=True, summary_template=qa_prompt)

# 获取响应
response = summarizer.get_response(
    "who is Paul Graham?", [text], tone_name="莎士比亚戏剧"
)

模块#

更多详细信息请参阅完整的模块指南