代码片段
# 创建响应合成器
response_synthesizer = get_response_synthesizer(
response_mode="tree_summarize",
)
# 3. 组合成查询引擎
query_engine = RetrieverQueryEngine(
retriever=retriever,
response_synthesizer=response_synthesizer,
)
在 LlamaIndex 中,response_mode 是控制响应合成器如何将检索到的上下文节点与用户查询结合起来生成最终答案的关键参数。
不同的 response_mode 决定了大模型(LLM)调用的次数、Token 的消耗量、响应的延迟以及最终答案的颗粒度。
以下是 LlamaIndex 中常用的 response_mode 类型及其作用、特征和适用场景的详细解析:
1. refine (精炼模式 / 逐块迭代)
-
作用:逐个遍历检索到的文本块,迭代地更新和精炼答案。
-
特征:
- 首先使用第一个文本块和用户查询生成初始答案。
- 然后将初始答案、下一个文本块和用户查询一起交给 LLM,让模型判断是否需要根据新信息修改答案。
- 重复此过程直到所有文本块处理完毕。
- 优点:能够综合所有检索到的细节,不会遗漏长文本中的信息。
- 缺点:LLM 调用次数等于检索到的文本块数量,延迟高,Token 消耗大;且在迭代过程中容易出现“遗忘”早期信息或过度精炼导致偏题的情况。
-
适用场景:
- 答案需要综合多个文本块中的细节(例如:“总结这本财报中提到的所有风险因素”)。
- 检索到的文本块较多,且信息分散在不同的块中。
2. tree_summarize (树状摘要模式)
-
作用:将文本块分组摘要,自底向上合并,最终生成一个高度概括的答案。
-
特征:
- 将文本块分批喂给 LLM 生成中间摘要。
- 再将这些中间摘要分批喂给 LLM 生成更高层级的摘要,直到合并为一个最终答案。
- 优点:极大地突破了 LLM 上下文窗口的限制,能处理海量检索结果;生成的答案通常非常连贯、高度概括。
- 缺点:LLM 调用次数多(呈树状结构),延迟高,Token 消耗极大;在逐层压缩的过程中,容易丢失具体的细节、数字或专有名词。
-
适用场景:
- 需要对大量文本进行宏观总结(例如:“概括这本500页书的核心思想”)。
- 不需要精确引用细节,只需要整体概览的场景。
3. compact (紧凑模式 —— 默认模式)
-
作用:尽可能在一次 LLM 调用中处理所有检索到的上下文,如果超出上下文窗口则分段处理。
-
特征:
- 它是
refine的一种优化版本。首先将尽可能多的文本块拼接在一起,塞进一个 Prompt 中。 - 如果所有文本块能一次性塞进 LLM 的上下文窗口,则只调用一次 LLM。
- 如果塞不下,则将其分割成多段,退化为
refine模式逐段精炼。 - 优点:在大多数常规情况下,它能在 Token 消耗和答案完整性之间取得最佳平衡。
- 缺点:如果退化为分段处理,依然存在
refine模式的部分缺点。
- 它是
-
适用场景:
- 最常用的默认选项,适用于绝大多数常规 RAG 问答场景。
- 不确定检索结果数据量大小,希望框架自动优化处理的情况。
4. simple_summarize (简单摘要模式)
-
作用:强制将所有检索到的文本块截断,以适应单次 LLM 调用的上下文窗口。
-
特征:
- 如果文本总量超过窗口大小,直接暴力截断多余的文本。
- 只进行一次 LLM 调用。
- 优点:速度极快,成本极低(只调用一次 LLM)。
- 缺点:会丢失大量信息(被截断的部分完全被忽略)。
-
适用场景:
- 对响应速度要求极高,且对答案完整性要求不高的场景。
- 只需要快速浏览检索结果的大致方向(例如:快速验证检索是否准确)。
5. no_text (仅检索模式)
-
作用:不调用 LLM 生成答案,直接返回检索到的原始文本块。
-
特征:
- 返回的对象类型不是字符串,而是包含节点信息的列表。
- 零 LLM 调用,零 Token 消耗,零延迟。
-
适用场景:
- 只需要获取相关文档片段,不需要大模型总结的场景。
- 需要将检索结果交给下游其他系统或自定义逻辑处理的场景。
- 评估和调试检索器的准确率。
6. accumulate (累积拼接模式) 音标:[əˈkjuːmjəleɪt]
-
作用:分别对每个文本块独立生成答案,然后将所有答案拼接在一起返回。
-
特征:
- 对每个文本块执行一次独立的问答,不进行交叉参考或精炼。
- 返回的答案是由多段独立回答拼接而成的长文本。
- 优点:保留了每个文本块的独立语境,不会发生信息混淆。
- 缺点:最终答案可能存在大量重复或矛盾的信息;LLM 调用次数等于文本块数量。
-
适用场景:
- 需要对比不同文本块对同一问题的看法(例如:“不同年份的财报对该风险的描述分别是什么?”)。
- 希望明确知道每个答案来源于哪个具体的文本块。
7. compact_accumulate (紧凑累积模式)
-
作用:结合了
compact的上下文压缩策略和accumulate的独立回答策略。 -
特征:
- 尽量将多个文本块打包进单次 LLM 调用中生成独立答案,超出窗口则分段。
- 相比
accumulate,减少了 LM 调用次数。
-
适用场景:
- 与
accumulate类似,但检索到的文本块较短、数量较多,希望节省 Token 和调用次数时。
- 与
💡 总结与选型指南
| response_mode | LLM调用次数 | Token成本 | 信息保留度 | 响应速度 | 最佳适用场景 |
|---|---|---|---|---|---|
| compact (默认) | 少 ~ 中 | 低 ~ 中 | 高 | 快 ~ 中 | 通用首选,常规问答与总结 |
| refine | 高 (等于块数) | 高 | 极高(细节) | 慢 | 需要综合所有细节,不容许遗漏 |
| tree_summarize | 高 (树状) | 极高 | 中(宏观) | 慢 | 处理海量文本,只需宏观概括 |
| simple_summarize | 1 | 极低 | 低(截断) | 极快 | 极速响应,不在乎信息丢失 |
| no_text | 0 | 0 | 原始数据 | 极快 | 只要原始数据,不需LLM总结 |
| accumulate | 高 (等于块数) | 高 | 高(独立) | 慢 | 需要分块独立回答/对比分析 |
开发建议:在构建 RAG 应用时,通常从默认的 compact 开始。如果发现答案遗漏了后面的细节,尝试切换到 refine;如果发现答案过于冗长且只需要大意,尝试 tree_summarize;如果只是想验证检索效果,用 no_text。