ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LlamaIndex Response Modes 全解析:从 refine 到 tree_summarize 的响应合成机制与选型实战

LlamaIndex Response Modes 全解析:从 refine 到 tree_summarize 的响应合成机制与选型实战 LlamaIndex Response Modes 全解析从 refine 到 tree_summarize 的响应合成机制与选型实战【免费下载链接】llama_indexLlamaIndex is the leading document agent and OCR platform项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index本指南以 LlamaIndex 官方文档 Response Modes 为骨架系统梳理检索增强生成RAG管线中「响应合成Response Synthesis」环节的九种响应模式refine、compact、tree_summarize、simple_summarize、no_text、accumulate、compact_accumulate、generation与context_only。读完本文你将掌握每种模式的内部运行机制、上下文窗口的利用策略、LLM 调用次数差异、适用场景与取舍并能在QueryEngine与get_response_synthesizer中正确配置response_mode。一、什么是 Response Mode查询引擎的最后一步在 LlamaIndex 中一次查询通常经历两条路径检索retrieval→ 合成synthesis。检索器从索引中召回与查询相关的节点Node而 Response Synthesizer 负责把这些检索到的文本块text chunk与用户查询组合成最终答案。response_mode正是决定「如何把 N 个文本块变成一段回答」的核心参数——它直接控制 LLM 调用次数、上下文利用效率与回答质量。从源码看ResponseMode是一个字符串枚举定义于 type.pyclass ResponseMode(str, Enum): REFINE refine COMPACT compact SIMPLE_SUMMARIZE simple_summarize TREE_SUMMARIZE tree_summarize GENERATION generation NO_TEXT no_text CONTEXT_ONLY context_only ACCUMULATE accumulate COMPACT_ACCUMULATE compact_accumulate模式本身并不直接执行合成而是通过工厂函数get_response_synthesizer见 factory.py映射到对应的合成器类例如ResponseMode.REFINE → Refine、ResponseMode.COMPACT → CompactAndRefine、ResponseMode.TREE_SUMMARIZE → TreeSummarize等。这些合成器类都继承自BaseSynthesizerbase.py对外统一暴露synthesize(query, nodes)与异步版本asynthesize内部再把节点文本提取为text_chunks交给具体的get_response实现。注BaseSynthesizer.synthesize在节点为空时直接返回空响应base.py#L245-L265但Generation模式重写了该方法——无论是否有节点都会调用 LLM详见后文。二、refine逐个文本块「创建并精炼」答案refine是逐块迭代式的回答生成方式其思想是「先答后改」依次遍历每个检索到的文本块不断用新块精炼已有答案。每次精炼都会产生一次独立的 LLM 调用因此调用次数等于文本块数量。工作细节第一个文本块与原始查询一起使用text_qa_template提示词生成初始答案随后已有答案 下一个文本块 原始查询使用refine_template提示词进行精炼如此循环直到所有文本块处理完毕若某个文本块过大、无法与提示词一同放入上下文窗口会通过TokenTextSplitter将其拆分块与块之间允许一定重叠拆分产生的新块会被追加进原块集合同样用refine_template查询。这段逻辑在 refine.py 的_run_refine_loop中有着完整的实现证据chunks_deque deque( [ tc for chunk in chunks for tc in prompt_helper.repack( max_prompt, [chunk], llmself._llm, paddingself._response_padding_size ) ] ) response prev_response while chunks_deque: chunk chunks_deque.popleft() if response is None: prompt_template qa_template.partial_format(query_strquery_str) prompt_kwargs make_qa_prompt_kwargs(chunk) # 首块走 text_qa_template else: prompt_template refine_template.partial_format( query_strquery_str, existing_answerresponse ) # 后续块走 refine_template ...值得注意的细节循环开始前max_prompt get_biggest_prompt([qa_template, refine_template])即取两个提示词中较大者作为容量基准DEFAULT_RESPONSE_PADDING_SIZE 500refine.py#L49为答案预留 token 空间由于每次精炼时existing_answer都在变长代码会对新块重新 repackrefine.py#L466-L478若拆出多个块则推入 deque 前端继续处理Refine还支持structured_answer_filtering通过StructuredRefineResponse含query_satisfied与answer两个字段过滤无关来源实现流式场景下的提前终止。适用场景需要细节丰富、逐步推理的答案。缺点明显——每个块都要调用一次 LLM成本与延迟最高。三、compact默认模式先压缩再精炼compact是 LlamaIndex 的默认响应模式。以 retriever_query_engine.py 中的RetrieverQueryEngine为例其构造参数声明为response_mode: ResponseMode ResponseMode.COMPACTcitation_query_engine.py 同样默认ResponseMode.COMPACT。工厂函数 factory.py 的默认值也是ResponseMode.COMPACT。与 refine 的关系compact在语义上与refine完全一致差别只在于前置压缩先把检索到的所有文本块尽量拼接、填满上下文窗口容量取text_qa_template与refine_template中较大的提示词上限若拼接后的文本仍然过长则用TokenTextSplitter拆成尽量少的若干部分允许重叠每个部分视为一个「块」送入refine合成器处理。从类继承关系看CompactAndRefine直接继承自Refinecompact_and_refine.py#L13其核心就是重写get_response在调用父类 refine 循环前先执行_make_compact_text_chunksdef _make_compact_text_chunks(self, query_str, text_chunks): text_qa_template self._text_qa_template.partial_format(query_strquery_str) refine_template self._refine_template.partial_format(query_strquery_str) max_prompt get_biggest_prompt([text_qa_template, refine_template]) return self._prompt_helper.repack( max_prompt, text_chunks, llmself._llm, paddingself._response_padding_size )结果LLM 调用次数从「块数」降为「压缩后的块数」通常大幅减少同时保留 refine 的逐步精炼质量。这是绝大多数 RAG 查询场景质量与成本均衡的推荐默认选择。四、tree_summarize自底向上的树形摘要tree_summarize面向多文档 / 长文本的全局总结场景。它不采用「精炼」思路而是用summary_template提示词反复查询 LLM直到只剩一个答案工作机制把所有拼接后的文本块尽量填满上下文窗口容量基于summary_template必要时用TokenTextSplitter拆分允许重叠对每个块/拆分分别用summary_template查询——注意这里没有 refine 步骤得到同样数量的答案若只有一个答案即为最终答案若有多个答案则把这些答案自身视为新的文本块递归执行「拼接/拆分适配/查询」流程直到合并为一个最终答案。源码 tree_summarize.py 的get_response完整印证了这一递归过程text_chunks self._prompt_helper.repack(summary_template, text_chunkstext_chunks, llmself._llm) if len(text_chunks) 1: response self._llm.predict(summary_template, context_strtext_chunks[0], ...) return response else: summaries [self._llm.predict(summary_template, context_strchunk, ...) for chunk in text_chunks] return self.get_response(query_strquery_str, text_chunkssummaries, ...) # 递归类注释tree_summarize.py#L20-L31将其概括为像建树一样自底向上递归合并摘要leaves → root。关键参数use_async同步路径中是否用异步并发方式并行调用多个 chunk 的摘要请求默认Falsesummary_template/chat_summary_template分别对应文本模式与多模态消息模式的摘要提示词默认取DEFAULT_TREE_SUMMARIZE_PROMPT_SEL与CHAT_CONTENT_TREE_SUMMARIZE_PROMPTfactory.py#L65-L71。适用场景对整批文档做全局总结、长文档归纳。相比simple_summarize它不会因截断而丢失细节代价是多次 LLM 调用调用次数与树的层数相关。五、simple_summarize单次调用快速但有截断风险simple_summarize是最快的摘要模式把所有文本块拼接成一段文本直接放进一个LLM 提示词中完成总结。优点只有一次 LLM 调用非常适合快速摘要缺点若拼接后的文本超过上下文窗口会被PromptHelper.truncate直接截断可能丢失尾部细节更严重的是若整体超出窗口太多单次调用可能直接失败。从 simple_summarize.py 的实现可以看到它对所有块做\n.join(text_chunks)拼接后用self._prompt_helper.truncate(prompttext_qa_template, text_chunks[single_text_chunk], llmself._llm)截断到可容纳范围再交给self._llm.predict(text_qa_template, context_strtruncated_chunks)。适用场景文本总量明显小于上下文窗口的快速总结、原型验证。type.py中的枚举注释也明确警告This will fail if the merged text chunk exceeds the context window sizetype.py#L25-L29。六、accumulate 与 compact_accumulate逐块独立作答这两个模式解决的是「需要对每个文本块分别应用同一查询」的需求——例如逐文档抽取结构化信息、逐章节问答。accumulate对每个文本块独立应用查询使用text_qa_template把各块响应累积进一个数组最终返回所有响应的拼接字符串默认分隔符为\n---------------------\n每条响应以Response {index 1}: {item}的形式编号见 accumulate.py#L67-L74适合「同一查询分别作用于每个文本块」的场景。实现细节accumulate.py#L150-L172tasks [ self._give_responses(query_str, text_chunk, use_asyncself._use_async, **response_kwargs) for text_chunk in text_chunks ] outputs self.flatten_list(tasks) return self._format_response(outputs, separator)注意两点accumulate不支持流式输出——if self._streaming: raise ValueError(Unable to stream in Accumulate response mode)accumulate.py#L157-L158compact_accumulate同样如此use_async为True时同步入口会通过run_async_tasks并发执行各块查询以降低延迟。compact_accumulate与accumulate行为一致但会像compact一样先压缩提示词先以text_qa_template为容量基准对文本块执行repackcompact_and_accumulate.py#L43-L55再对压缩后的每个块执行 accumulate 查询。类继承关系为CompactAndAccumulate(Accumulate)compact_and_accumulate.py#L10。结果相比accumulateLLM 调用次数更少尤其当单块很小而块数很多时收益明显。七、no_text、context_only 与 generation三个特殊模式no_text只检索不合成no_text模式只运行检索器把本应发给 LLM 的节点取回来但不真正调用 LLM 合成答案。返回的response文本为空字符串真正有价值的信息在response.source_nodes中——你可以通过遍历source_nodes检查实际被召回、本应送入 LLM 的节点内容。源码 no_text.py 的get_response直接return 而合成器基类会把这些节点挂到响应的source_nodes上。适用场景调试检索质量、评估 RAG 检索阶段、构建「仅检索」pipeline、在真正调用 LLM 之前预览上下文内容。context_only仅拼接上下文context_only不做任何 LLM 调用只是把各文本块用\n\n连接后原样返回context_only.py#L18-L24。从源码结构看它适合下游自行处理上下文、或把「检索 拼接」结果交给外部 LLM 管道的场景。generation忽略上下文纯 LLM 生成generation模式完全忽略检索到的文本块仅用查询本身调用 LLM 生成回答generation.py#L64-L83def get_response(self, query_str, text_chunks, **response_kwargs): del text_chunks # 文本块被直接丢弃 return self._llm.predict(self._input_prompt, query_strquery_str, **response_kwargs)它使用simple_templateDEFAULT_SIMPLE_INPUT_PROMPT作为输入提示词。与其它模式最大的不同是Generation重写了synthesize绕开基类「空节点早退」逻辑即使没有检索到节点也必定调用 LLMgeneration.py#L148-L208保证在任何节点输入下都有输出。适用场景无需 RAG 上下文的纯生成任务、Agent 场景下的自由回答、或对检索质量没有把握时的兜底。八、实战如何配置与切换 response_mode方式一通过 QueryEngine 直接指定最常见的用法是在构建查询引擎时传入response_mode字符串或枚举均可因为ResponseMode继承自strfrom llama_index.core.query_engine import RetrieverQueryEngine query_engine RetrieverQueryEngine( retrieverretriever, response_modetree_summarize, # 或 ResponseMode.TREE_SUMMARIZE ) response query_engine.query(请总结以上所有文档的核心观点)方式二通过 get_response_synthesizer 显式构建需要精细控制提示词、流式、结构化输出时可先构建合成器再传入查询引擎from llama_index.core.response_synthesizers import get_response_synthesizer from llama_index.core.query_engine import RetrieverQueryEngine synthesizer get_response_synthesizer( response_modecompact, # 默认即为 compact streamingFalse, text_qa_templatemy_qa_template, # 自定义 text_qa 提示词 refine_templatemy_refine_template, ) query_engine RetrieverQueryEngine(retrieverretriever, response_synthesizersynthesizer)get_response_synthesizer的完整签名factory.py#L38-L60包含llm、prompt_helper、text_qa_template、refine_template、summary_template、simple_template、response_mode、streaming、use_async、structured_answer_filtering、output_cls、program_factory、verbose、multimodal等参数。未显式传入的llm、callback_manager、prompt_helper会回退到全局Settingsfactory.py#L73-L88其中PromptHelper会根据llm.metadata自动构建。方式三多模态 / 消息模式所有合成器同时提供get_response文本 chunks与get_response_from_messagesChatMessagechunks两套接口当multimodalTrue时BaseSynthesizer.synthesize会走消息路径base.py#L274-L295把节点的get_content_blocks内容封装成ChatMessage传入对应使用chat_content_qa_template、chat_content_refine_template、chat_summary_template等对话式提示词。响应对象与 source_nodes合成结果由_prepare_response_outputbase.py#L184-L229封装字符串 →Response生成器 →StreamingResponse结构化 LLM →PydanticResponse。无论哪种模式检索到的节点都会附加到响应的source_nodes上因此no_text模式也可以统一用response.source_nodes检查检索结果。九、模式速查与选型建议模式LLM 调用次数上下文利用典型场景备注refine 文本块数逐块需要逐步推理的细节问答成本最高compact≈ 压缩后块数尽量填满窗口通用问答默认refine 的优化版tree_summarize随树层数增长递归填满窗口多文档全局总结自底向上递归simple_summarize1 次超限即截断快速摘要可能丢失细节/失败accumulate 块数逐块独立同一查询作用于每块不支持流式compact_accumulate≈ 压缩后块数先压缩再逐块accumulate 的优化版不支持流式no_text0 次不调用调试检索、仅检索管线答案在 source_nodescontext_only0 次原样拼接上下文透传无 LLMgeneration1 次忽略上下文纯生成、Agent 兜底空节点也调用 LLM选型建议通用生产问答compact默认质量与成本均衡多文档总结归纳tree_summarize追求极致速度、文本可控simple_summarize需要逐文档结构化输出accumulate/compact_accumulate后者更省调用检索质量排查与评测no_text不需要上下文的自由生成generation。十、深入阅读响应模式的枚举定义type.py合成器工厂与默认提示词装配factory.pyrefine / compact 的实现与精炼循环refine.py、compact_and_refine.py树形摘要与逐块累积tree_summarize.py、accumulate.py、compact_and_accumulate.py特殊模式no_text.py、context_only.py、generation.py合成器基类与响应封装base.py查询引擎中的默认配置retriever_query_engine.py、citation_query_engine.py各模式的单元测试llama-index-core/tests/response_synthesizers/下的test_refine.py、test_tree_summarize.py、test_accumulate.py、test_compact_and_refine.py等可作为理解每种模式预期行为的补充参考。【免费下载链接】llama_indexLlamaIndex is the leading document agent and OCR platform项目地址: https://gitcode.com/GitHub_Trending/ll/llama_index创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表