openclaw - 💡(How to fix) Fix [Bug] 流式消息组装导致 thinking/text 归类不一致(空消息或思考链冒充正文) [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#55520Fetched 2026-04-08 01:38:35
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

OpenClaw 在处理流式消息时,content 和 reasoning_content 的归类逻辑存在状态机或竞态缺陷,导致最终消息的 thinking 与 text 归类在不同运行中不一致,进而出现两种错误表现:

  1. 空消息(幽灵框):thinking 有内容,text 缺失
  2. 思考链冒充正文:thinking 为空,text 装进了本应是 thinking 的内容

Root Cause

OpenClaw 的流式消息组装在 handling content / reasoning_content 时存在状态机或竞态缺陷,导致最终消息的 thinking 与 text 归类在不同运行中不一致,进而出现"空消息"或"思考链冒充正文"的双向错位。

关键证据:两条"镜像样本"展示了完全相反的错误模式,来自不同供应商、不同接口,但都在 stopReason: "stop" 的正常结束路径下完成。这说明问题不在超时、断流或 provider 单点异常,而是 OpenClaw 的流式 chunk 归类逻辑不稳定。

Code Example

{
  "type": "message",
  "id": "8cce2b73",
  "message": {
    "role": "assistant",
    "content": [
      {
        "type": "thinking",
        "thinking": "用户指出了一个关键问题!让我仔细看看这条消息的内容:...(1641 字符的完整分析内容)...",
        "thinkingSignature": "reasoning_content"
      }
    ],
    "model": "glm-5",
    "stopReason": "stop"
  }
}

---

{
  "type": "message",
  "id": "fd715a33",
  "message": {
    "role": "assistant",
    "content": [
      {
        "type": "thinking",
        "thinking": "\n",
        "thinkingSignature": "reasoning_content"
      },
      {
        "type": "text",
        "text": "\n我启动了日志监控。如果用户切了 URL 后代理挂了,备用 URL 是:\n
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Summary

OpenClaw 在处理流式消息时,content 和 reasoning_content 的归类逻辑存在状态机或竞态缺陷,导致最终消息的 thinking 与 text 归类在不同运行中不一致,进而出现两种错误表现:

  1. 空消息(幽灵框):thinking 有内容,text 缺失
  2. 思考链冒充正文:thinking 为空,text 装进了本应是 thinking 的内容

Root Cause

OpenClaw 的流式消息组装在 handling content / reasoning_content 时存在状态机或竞态缺陷,导致最终消息的 thinking 与 text 归类在不同运行中不一致,进而出现"空消息"或"思考链冒充正文"的双向错位。

关键证据:两条"镜像样本"展示了完全相反的错误模式,来自不同供应商、不同接口,但都在 stopReason: "stop" 的正常结束路径下完成。这说明问题不在超时、断流或 provider 单点异常,而是 OpenClaw 的流式 chunk 归类逻辑不稳定。

Evidence 1: 空消息(幽灵框)

时间:2026-03-27 02:52:24 UTC 模型:百炼 glm-5 供应商:bailian stopReason"stop"(正常结束)

{
  "type": "message",
  "id": "8cce2b73",
  "message": {
    "role": "assistant",
    "content": [
      {
        "type": "thinking",
        "thinking": "用户指出了一个关键问题!让我仔细看看这条消息的内容:...(1641 字符的完整分析内容)...",
        "thinkingSignature": "reasoning_content"
      }
    ],
    "model": "glm-5",
    "stopReason": "stop"
  }
}

问题:content 数组只有 1 个元素(thinking),没有 text。thinking 包含了应该显示给用户的完整回复内容。

Evidence 2: 思考链冒充正文

时间:2026-03-27 01:20:04 UTC 模型:ZAI glm-4.5-air 供应商:zai stopReason"stop"(正常结束)

{
  "type": "message",
  "id": "fd715a33",
  "message": {
    "role": "assistant",
    "content": [
      {
        "type": "thinking",
        "thinking": "\n",
        "thinkingSignature": "reasoning_content"
      },
      {
        "type": "text",
        "text": "\n我启动了日志监控。如果用户切了 URL 后代理挂了,备用 URL 是:\n```\nhttps://coding.dashscope.aliyuncs.com/v1\n```\n\n现在我在监控日志,看看代理能不能收到请求。如果代理挂了,我会立即告诉用户切换回官方 API。"
      }
    ],
    "model": "glm-4.5-air",
    "stopReason": "stop"
  }
}

问题:text 字段包含的是模型的"内心独白"("我启动了日志监控..."),而不是正式给用户的回复。thinking 只有换行符。thinking 和 text 应该对调。

Key Observations

消息供应商thinkingtext问题类型
Evidence 1百炼 glm-5✅ 完整内容❌ 缺失空消息
Evidence 2ZAI glm-4.5-air❌ 只有换行✅ 内心独白思考链冒充正文

关键点

  • 不同供应商、不同模型、不同接口
  • 都是 stopReason: "stop" 正常结束
  • 错误模式完全相反(镜像样本)
  • 不是超时、不是断流、不是 provider 单点异常

Expected behavior

  1. reasoning_content 有内容但 content 为空时,应该 fallback 将 reasoning_content 显示为正文,而不是显示空消息
  2. 流式 chunk 归类逻辑应该稳定一致,不应该出现"有时候进 thinking,有时候进 text"的问题

Suggested Fix

  1. 短期修复:当 content 为空但 reasoning_content 不为空时,fallback 显示 reasoning_content(参考 NVIDIA/NemoClaw #247 的建议)

  2. 长期修复:审查流式消息组装的状态机逻辑,确保 content 和 reasoning_content 的归类稳定一致

Related Issues

  • NVIDIA/NemoClaw #247 - OpenClaw discards Ollama reasoning field — model output silently lost
  • NVIDIA/NemoClaw #246 - Ollama reasoning models return empty content
  • openclaw/openclaw #27806 - OpenClaw expects content but Ollama reasoning models sends empty field

Environment

  • OpenClaw version: 2026.3.24
  • Operating system: macOS (Darwin 25.3.0 arm64)
  • Providers affected: bailian, zai (likely all providers with reasoning support)

extent analysis

Fix Plan

To address the issue of inconsistent message classification in OpenClaw, we will implement a short-term fix and a long-term fix.

Short-term Fix

  1. Fallback to reasoning_content: When content is empty but reasoning_content is not, display reasoning_content as the main text.
  2. Code Example:
if not content and reasoning_content:
    # Fallback to reasoning_content
    content = [{"type": "text", "text": reasoning_content}]

Long-term Fix

  1. Review State Machine Logic: Examine the state machine logic for assembling stream messages to ensure consistent classification of content and reasoning_content.
  2. Code Example:
def assemble_message(message):
    # Initialize content and reasoning_content
    content = []
    reasoning_content = ""

    # Process stream chunks
    for chunk in chunks:
        if chunk.type == "thinking":
            reasoning_content += chunk.thinking
        elif chunk.type == "text":
            content.append({"type": "text", "text": chunk.text})

    # Ensure consistent classification
    if not content and reasoning_content:
        content = [{"type": "text", "text": reasoning_content}]
    elif content and not reasoning_content:
        # Handle case where content is present but reasoning_content is empty
        pass

    return {"content": content, "reasoning_content": reasoning_content}

Verification

To verify the fix, test the following scenarios:

  • Empty content with non-empty reasoning_content
  • Non-empty content with empty reasoning_content
  • Both content and reasoning_content are empty
  • Both content and reasoning_content are non-empty

Extra Tips

  • Ensure that the fallback logic is only applied when content is truly empty, and not when it contains empty strings or whitespace.
  • Consider adding logging or monitoring to detect and report instances where the fallback logic is triggered, to help identify and fix underlying issues.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

  1. reasoning_content 有内容但 content 为空时,应该 fallback 将 reasoning_content 显示为正文,而不是显示空消息
  2. 流式 chunk 归类逻辑应该稳定一致,不应该出现"有时候进 thinking,有时候进 text"的问题

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING