[Bug]: Refine/CompactAndRefine streaming collapsed to a single chunk since 0.14.22 (#21374)

当你在 LlamaIndex 0.14.22 及之后版本中使用 Refine 或 CompactAndRefine 并开启 streaming=True 时,流式输出会退化成一次性返回单个 chunk(完整答案在生成结束后才吐出),核心报错表现为:[Bug]: Refine/CompactAndRe

快速结论:当你在 LlamaIndex 0.14.22 及之后版本中使用 RefineCompactAndRefine 并开启 streaming=True 时,流式输出会退化成一次性返回单个 chunk(完整答案在生成结束后才吐出),核心报错表现为:[Bug]: Refine/CompactAndRefine streaming collapsed to a single chunk since 0.14.22 (#21374)。优先排查是否使用了 CompactAndRefine 作为 response synthesizer(包括 CondensePlusContextChatEngine 强制内置的那条路径)。

适用环境:LlamaIndex Core;已确认受影响版本为 0.14.22、0.14.23、0.14.24;最后正常版本为 0.14.21。Issue 中的复现脚本使用纯 Python fake LLM,未涉及 CUDA、显卡或外部 API。

最快修复方案:暂无确认的一步修复方案。截至 Issue 讨论时,多个修复 PR(#21758、#22750、#22754、#22788)均未合并。可优先尝试的绕过方式:在你自己的调用点改用 TREE_SUMMARIZESIMPLE_SUMMARIZE 响应模式,这两者会直接返回 LLM 的流、不受影响;或者将 LlamaIndex 回退到 0.14.21。

注意事项:回退到 0.14.21 只是规避手段,并非官方修复,且可能错过后续版本的其它改动;对无法修改 response mode 的 CondensePlusContextChatEngine 用户,讨论中给出的临时路径是绕过 synthesizer、直接对 LLM 流式调用并带上检索到的 context。上述绕过方式来自 Issue 讨论,并非已合并的修复。

问题场景

用户在 LlamaIndex 中使用流式响应合成时触发该问题:CompactAndRefineRefinestreaming=True 下调用 asynthesize()(同步路径 stream_call 行为相同),响应生成器不再逐 token 产出,而是等完整生成结束后一次性返回整个答案。CondensePlusContextChatEngine.astream_chat() 也会受影响,因为 llama_index/core/chat_engine/utils.py 中的 get_response_synthesizer() 硬编码构建了一个 CompactAndRefine,导致任何使用它的 chat engine 静默失去流式能力。典型表现:SSE 端点原本发出数百个 token 事件,现在只发出一个,且无报错。

报错原文

[Bug]: Refine/CompactAndRefine streaming collapsed to a single chunk since 0.14.22 (#21374)

LLM deltas fed:  12
chunks received: 1
chunks:          ['The torque spec is 4.2 Nm for panel screws. Use']

Expected (0.14.21 behaviour): 12 chunks, one per delta.

原因分析

该回归由 #21374(feat(core): Multimodal synthesis,commit 38b5290a5)引入。它新增了 DefaultRefineProgram.stream_call / astream_call,并移除了 _agive_response_single / _arefine_response_single 原本直接返回的 response = await self._llm.astream(...)

llama_index/core/response_synthesizers/refine.py 中,astream_call 的非 output_cls 分支里存在一个 drain loop:代码先把 token 累积到 answer,等到结构化流处理完成后再一次性产出,而结构化流(stream_structured_predict)本身不会产出部分 JSON 字段,这个行为被错误地套用到了纯文本分支上,形成两层缓冲,最终只 yield 一个 chunk。讨论中还提到这与 #22749、#22183 同源。此外,末尾空格也被 answer.strip() 去掉,导致拼接 chunk 的调用方丢失边界空白。

环境排查

  • 确认 LlamaIndex Core 版本:0.14.22 / 0.14.23 / 0.14.24 均受影响,0.14.21 及更早正常。
  • 确认是否使用了 CompactAndRefineRefine,并且 streaming=True
  • 如果使用 CondensePlusContextChatEngine,检查是否间接走了 get_response_synthesizer()(其默认构建 CompactAndRefine)。
  • 确认流式消费侧是否依赖每个 chunk 的边界空格(末位空格可能被 strip 掉)。
  • Issue 复现为纯 Python fake LLM,不需要 CUDA、显卡或 API key;如果问题仅出现在带 output_cls 的结构化路径,则属于另一类行为,需单独确认。

解决步骤

  1. 先用 Issue 提供的 fake LLM 复现脚本确认现象:设置 12 个 delta,打印 chunks received,若为 1 则命中该问题。
  2. 如果不能等待修复,回退到 0.14.21(最后正常版本)以恢复逐 token 流式。
  3. 可优先尝试:在你自己可控的调用点把 response mode 换成 TREE_SUMMARIZESIMPLE_SUMMARIZE,两者直接返回 LLM 流,不受该 bug 影响。
  4. 对无法修改 response mode 的 CondensePlusContextChatEngine 用户,讨论中的临时方案是绕过 synthesizer,直接对 LLM 做流式调用并自行带上检索到的 context。
  5. 关注修复 PR 进展:#21758、#22750、#22754、#22788,均采用在非结构化分支绕过 structured drain 的思路;合并后再升级验证。

验证方法

运行 Issue 中的复现脚本,检查输出是否为 chunks received: 12(每个 delta 一个 chunk),并确认 chunk 拼接结果与完整答案一致、末位空格未被 strip() 影响。对于 SSE 端点,验证一次请求返回的事件数量是否恢复到逐 token 级别。若升级到包含修复的版本,重复以上步骤确认。

参考来源

run-llama/llama_index #22831

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 24473

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注