Day 13 / 共 20 天 · 第 3 周 检索与查询

响应合成 Synthesizer(流水线第 ⑥ 步)

检索到的片段可能很多、可能塞不下 LLM——怎么把它们"攒"成一个连贯答案?这就是响应合成。今天讲三种合成模式,它们决定答案质量、调 LLM 次数(成本)和速度。

📍 你在整条链的位置
⑤ 检索 后处理 D14 ⑥ 合成答案 Synthesizer ✅ Response
L01

合成的难题

🤔 检索回来 10 个片段,一次塞不进提示词怎么办? top_k=10、每块 1000 token = 上万 token,加上下文限制——不能无脑全塞。而且要"综合"多个片段得出连贯答案,不是简单拼接。
💡 Synthesizer = 用不同策略把 N 个片段"攒"成一个答案 有的逐个精炼、有的压缩填满、有的树形汇总。合成模式直接影响:答案质量、LLM 调用次数(钱)、延迟。选对模式很重要。
L02

四种主要模式

response_synthesizers/type.py:4-51ResponseMode,每个模式一个文件:

模式怎么攒LLM 调用
REFINE逐个片段精炼答案N 次(多)
COMPACT(默认)压缩填满上下文再精炼较少
TREE_SUMMARIZE树形两两汇总并行、适合大量
SIMPLE_SUMMARIZE全拼一起(塞不下就截断)1 次(可能丢信息)
读法:factory.pyget_response_synthesizer 按 mode 造对应合成器(Day 12 默认 COMPACT)。下面拆最重要的三个。
L03

refine:滚雪球式精炼

response_synthesizers/refine.py

📝 refine 过程(假设 3 个片段) 1. 片段1 + 问题 → LLM → 初版答案 A1
2. 片段2 + A1 + 问题 → LLM →"在 A1 基础上结合片段2 精炼"→ A2
3. 片段3 + A2 → LLM → A3(最终)
每个片段调一次 LLM,答案层层完善。
优点全、缺点慢 每个片段都被完整看到(不因塞不下被截断),答案精细。但 N 个片段 = N 次 LLM 调用(慢、贵)。适合片段多、要精确综合的场景。
L04

compact:refine 的省钱版(默认)

response_synthesizers/compact_and_refine.py:先把多个片段"塞满"一个提示词(尽量填满上下文),塞不下的再走 refine。

📝 10 个片段,compact vs refinerefine:10 个片段 = 10 次 LLM 调用
compact:若每次能塞 3 个 → 打包成 3+3+4 → 只 3 次调用(省 7 次)
💡 默认模式,平衡"信息完整"和"少调 LLM" 先"打包"能塞进一次的片段(少调 LLM),塞不下的剩余再 refine。大多数场景用它就好。
L05

tree_summarize:树形汇总

response_synthesizers/tree_summarize.py:片段两两/成组汇总成中间摘要,再汇总,层层向上到最终答案。

片段1 片段2 片段3 片段4 摘要 1+2 摘要 3+4 最终答案 像淘汰赛:每层并行汇总层层归并到顶
tree_summarize:片段分组汇总 → 中间摘要再汇总 → 最终答案。每层可并行,适合大量片段。
适合"总结大量内容" 问"总结整份文档"用它(层级归并、每层并行、比 refine 快)。缺点:中间汇总可能丢细节。问"报销的具体条款"用 compact(要精确细节)。
L06

PromptHelper:自动装箱

💡 算"一次能塞多少片段" indices/prompt_helper.pyPromptHelper:根据 LLM 上下文窗口、留给答案的空间,算出每次能装多少 Node 文本、要分几批。
读法:compact 的"尽量塞满"、refine 的"每次一个"都靠它计算边界。它防止"塞爆上下文"报错——自动分批。不同 LLM 上下文大小不同(GPT-4o 128k vs 老模型 4k),它动态适配。这是 RAG 工程化的关键细节。
L07

流式与结构化

💡 streaming=True + 结构化输出 流式:答案边生成边返回(打字机效果,改善体验)。结构化output_cls 让 LLM 返回 Pydantic 对象而非纯文本(如 {"answer":..., "confidence":...})。
读法:流式让用户"立刻看到答案在打字"(像 ChatGPT);结构化让 RAG 结果能接入下游程序。都是生产 RAG 的体验/集成能力。
L08

今日小结 + 动手

🧠 今天你应该能回答

  • 为什么需要"合成"而不是简单拼接片段?
  • refine / compact / tree_summarize 各怎么工作、各适合什么?
  • 为什么 compact 是默认(省 LLM 调用)?
  • PromptHelper 解决什么"装箱"问题?

✋ 动手

cd /Users/bitmart/work/codes/github/llama_index/llama-index-core/llama_index/core
sed -n '1,55p' response_synthesizers/type.py
ls response_synthesizers/
grep -n "def get_response_synthesizer\|ResponseMode" response_synthesizers/factory.py | head
明天预告 · Day 14:检索到的 Node 在合成前先"精修"——后处理(重排/过滤/上下文窗口)+ 提示词模板。rerank 是提升 RAG 准确率最有效的技巧之一。
← Day 12 Day 14 · 后处理 →