快速结论:当你在 LlamaIndex 0.14.22 及之后版本中使用 Refine 或 CompactAndRefine 并开启 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_SUMMARIZE 或 SIMPLE_SUMMARIZE 响应模式,这两者会直接返回 LLM 的流、不受影响;或者将 LlamaIndex 回退到 0.14.21。
注意事项:回退到 0.14.21 只是规避手段,并非官方修复,且可能错过后续版本的其它改动;对无法修改 response mode 的 CondensePlusContextChatEngine 用户,讨论中给出的临时路径是绕过 synthesizer、直接对 LLM 流式调用并带上检索到的 context。上述绕过方式来自 Issue 讨论,并非已合并的修复。
问题场景
用户在 LlamaIndex 中使用流式响应合成时触发该问题:CompactAndRefine 或 Refine 在 streaming=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 及更早正常。
- 确认是否使用了
CompactAndRefine或Refine,并且streaming=True。 - 如果使用
CondensePlusContextChatEngine,检查是否间接走了get_response_synthesizer()(其默认构建CompactAndRefine)。 - 确认流式消费侧是否依赖每个 chunk 的边界空格(末位空格可能被 strip 掉)。
- Issue 复现为纯 Python fake LLM,不需要 CUDA、显卡或 API key;如果问题仅出现在带
output_cls的结构化路径,则属于另一类行为,需单独确认。
解决步骤
- 先用 Issue 提供的 fake LLM 复现脚本确认现象:设置 12 个 delta,打印
chunks received,若为 1 则命中该问题。 - 如果不能等待修复,回退到
0.14.21(最后正常版本)以恢复逐 token 流式。 - 可优先尝试:在你自己可控的调用点把 response mode 换成
TREE_SUMMARIZE或SIMPLE_SUMMARIZE,两者直接返回 LLM 流,不受该 bug 影响。 - 对无法修改 response mode 的
CondensePlusContextChatEngine用户,讨论中的临时方案是绕过 synthesizer,直接对 LLM 做流式调用并自行带上检索到的 context。 - 关注修复 PR 进展:#21758、#22750、#22754、#22788,均采用在非结构化分支绕过 structured drain 的思路;合并后再升级验证。
验证方法
运行 Issue 中的复现脚本,检查输出是否为 chunks received: 12(每个 delta 一个 chunk),并确认 chunk 拼接结果与完整答案一致、末位空格未被 strip() 影响。对于 SSE 端点,验证一次请求返回的事件数量是否恢复到逐 token 级别。若升级到包含修复的版本,重复以上步骤确认。
参考来源
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


![[Bug] DFlash2 spec decode + xgrammar: deterministic "Failed to advance FSM" on json_object grammar (same draft token every time)](https://www.chat-gpts.plus/wp-content/uploads/2026/09/53777-75f62c55-768x403.jpg)