TextGenerate: thinking output is empty for Qwen3.5

在 ComfyUI 的 TextGenerate 节点里用 Qwen3.5 文本编码器并开启 thinking=true 时,如果 prompt 模板没有主动补上 \n ,模型要么不推理,要么推理内容出现在 generated_text 顶部而 thinking 输出为空。优先检查 p

快速结论:在 ComfyUI 的 TextGenerate 节点里用 Qwen3.5 文本编码器并开启 thinking=true 时,如果 prompt 模板没有主动补上 <think>\n,模型要么不推理,要么推理内容出现在 generated_text 顶部而 thinking 输出为空。优先检查 prompt 组装和 <think> 拆分逻辑。

适用环境:Issue 确认的环境为 ComfyUI 自带节点(已排除自定义节点影响),模型为 models/text_encoders/ 下的 Qwen3.5 文本编码器(实测 Qwen3.5-9B,bf16 safetensors,同架构的 Qwen-Image-2.1-PE-I2I 微调也可复现),TextGenerate 设置 thinking=true、max_length=10240、mtp 关闭。Issue 未提供操作系统、Python、CUDA、PyTorch、显卡版本信息。

最快修复方案:暂无确认的一步修复方案。Issue 中提到的模板修复 PR #15957 仍处于 open 且 mergeable_state: dirty 状态,不能直接作为已验证的一步修复手段。

注意事项:模板修复(#15957)落地后,若拆分逻辑没有同步调整,仍会出现 thinking 空而推理混入 generated_text 的问题;两处需要一并修复。相关 PR 已与当前主干产生冲突,直接合入可能失败。Issue 中其他线索(#16469、#13641)属于不同代码路径,修好其中一处不会自动修复另外的问题。

问题场景

用户在 ComfyUI 中加载 Qwen3.5 文本编码器(CLIPLoader),再连接 TextGenerate 节点,开启 thinking=true,并搭配要求模型先推理的 prompt/system prompt 运行。期望模型在 thinking 输出口返回推理过程,generated_text 只返回最终答案;实际行为有两种:当前主干上模型完全不推理,直接作答;只修复 prompt 模板后,模型推理正确但没有输出起始的 <think>,节点拆分条件不成立,推理内容被并入 generated_text,thinking 输出保持为空。

报错原文

TextGenerate: thinking output is empty for Qwen3.5

原因分析

Issue 给出的根因有两层:

1. prompt 从未打开 think 块。在 comfy/text_encoders/qwen35.py 对应逻辑中,只有 thinking=False 时才追加 <think>\n</think>\n;当 thinking=True 时什么也不追加,assistant 轮次停在裸的 <|im_start|>assistant\n,与 Qwen3.5 训练时看到的格式不一致,模型因此不推理。

2. 拆分条件不匹配。即使 prompt 已正确预置 <think>\n,节点的拆分判断仍要求“生成文本”以字面量 <think> 开头;但开标签在 prompt 里而非生成结果里,于是已经正确闭合的推理块被丢弃并合并回 generated_text。

可能原因层面,Issue 还列出同源但不同层的线索:#15957 修的是 Qwen3.5 prompt 组装(open,冲突);#16469 修的是 TextGenerateLTX2Prompt 的文本清理(open,基于已合并的 #16442 之前的 re.sub 形式,且返回值与节点两个输出不匹配);#13641 是另一个方向的问题,即 thinking=false 时模型仍推理且 <think> 块进入输出,走的是 z_image.ZImageTokenizer 路径,没有 thinking 处理逻辑,不属于同一缺陷。三者的共同上游现象是 Qwen3.5 会闭合 </think> 却不曾发出开标签,但落点不同,不能相互替代。

环境排查

  • 确认是否禁用了所有自定义节点后仍复现,以排除第三方节点干扰。
  • 确认 models/text_encoders/ 中放置的是 Qwen3.5 文本编码器,且 CLIPLoader 选中的是该文件。
  • 确认 TextGenerate 节点参数:thinking=true、max_length=10240、mtp 关闭。
  • 确认 sampling_mode 已开启并采用 Qwen3.5 模型卡中的 thinking 采样配置(temperature 1.0、top_p 0.95、top_k 20、min_p 0.0、presence_penalty 1.5、repetition_penalty 1.0),避免 instruct 默认参数干扰判断。
  • 确认 system_prompt 输入(force_input)是否来自其他节点,并检查其内容是否要求先输出 <think> 块。
  • 检查 clip.tokenize(..., thinking=thinking, ...) 调用链,Issue 表明 thinking=true 只从 comfy_extras/nodes_textgen.py 这一处进入 Qwen35ImageTokenizer。
  • Issue 未给出 Python、CUDA、PyTorch、显卡版本,无法据此做版本比对。

解决步骤

  1. 先做对照测试:关闭自定义节点,用 Qwen3.5-9B 与提示词 1+2+3+4+...+9= 复现,并同时读取 thinking 和 generated_text 两个输出口。
  2. 若当前主干下模型不推理,检查 comfy/text_encoders/qwen35.py 中 thinking=True 分支是否缺少 <think>\n 预置;可优先尝试参考 #15957 的模板修复思路,但该 PR 处于 open 且与主干冲突,需人工适配。
  3. 若模型推理正确但 thinking 为空,检查节点的推理块拆分条件是否要求生成文本以字面量 <think> 开头;可优先尝试将拆分依据改为识别结尾的 </think> 并进行前后切分,然后分别写入两个输出。
  4. 注意不要依赖 #16469 或 #13641 作为本问题的同批修复:#16469 针对 LTX2 路径且基于旧版 re.sub,#13641 是 ZImageTokenizer 下 thinking=false 仍推理的另一类问题。
  5. 若暂不修改代码,可把 thinking 输出为空视为已知限制,自行从 generated_text 中人工分离推理段与最终答案,但这只是规避,不是修复。

验证方法

用需要多步推理的 prompt 重新运行,确认模型输出确实包含以 <think> 开始、</think> 结束的推理块;检查 thinking 输出口返回完整推理内容,而 generated_text 只包含最终答案,不再混入推理段。同时确认 thinking=false 时行为未受影响。

参考来源

Comfy-Org/ComfyUI #17079

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29340

发表回复

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