agentscope-ai/agentscope-java

[Bug]:AnthropicChatModel 将 ThinkingBlock 作为普通 text 传回 API,导致 400 错误

Offen

#2.400 geöffnet am 27.07.2026

 (2 Kommentare) (0 Reaktionen) (1 zugewiesene Person)Java (693 Forks)user submission
bughelp wanted

Repository-Metriken

Stars
 (3.253 Sterne)
PR-Merge-Metriken
 (Durchschn. Merge 2T 8h) (58 gemergte PRs in 30 T)

Beschreibung

先撤销刚才的源码修改:

已撤销。以下是你可以提 issue 的完整描述:


Issue:

环境信息

  • AgentScope v2.0.0
  • 模型:deepseek-v4-pro(通过 Anthropic 协议接入的第三方模型)
  • 场景:多轮对话,ReActAgent

问题现象

多轮对话时,Anthropic API 报 400 错误:

The `content[].thinking` in the thinking mode must be passed back to the API.

根因

AnthropicMessageConverter.java 第131-137行,将 ThinkingBlock 转换为普通 TextBlockParam 传回 API:

} else if (block instanceof ThinkingBlock thinkingBlock) {
    contentBlocks.add(
            ContentBlockParam.ofText(
                    TextBlockParam.builder()
                            .text(thinkingBlock.getThinking())
                            .build()));
}

问题在于:

  1. 模型上一轮回复产生了 thinking 块,AgentScope 存入对话历史
  2. 下一轮请求时,thinking 块被转成普通 text 类型传回 API
  3. 但 Anthropic API 要求 thinking 内容必须用** thinking content type** 原样传回(包含 thinkingsignature 等字段),不能用 text 类型
  4. 如果对话经过 CompactionMiddleware 压缩,thinking 块可能被截断或丢失,传回不完整内容,API 直接报 400

触发条件

  1. 使用 Anthropic 协议的模型(Claude / 第三方如 deepseek-v4-pro)
  2. 开启了 thinking 模式(enableThinking: truethinkingBudget 设了值)
  3. 多轮对话(第二轮起),或对话历史经过 compaction 压缩后

建议修复

方案A(推荐):ThinkingBlock 应该用 Anthropic 的 thinking content type 传回,包含 thinkingsignature 字段,而不是转成 text

} else if (block instanceof ThinkingBlock thinkingBlock) {
    // 用 Anthropic 原生的 thinking content type 传回
    contentBlocks.add(ContentBlockParam.ofThinking(
            ThinkingBlockParam.builder()
                    .type("thinking")
                    .thinking(thinkingBlock.getThinking())
                    .signature(thinkingBlock.getSignature()) // 需要在 ThinkingBlock 中保存 signature
                    .build()));
}

方案B(兜底):如果无法保证 thinking 块的完整性(如 compaction 后),应该跳过 ThinkingBlock,不传回 API:

} else if (block instanceof ThinkingBlock) {
    // Skip: thinking 块不完整时传回会导致 400
    continue;
}

补充说明

  • CompactionMiddleware 压缩后也会丢失 thinking 块的 signature,即使转成正确的 thinking type 也会失败
  • 对于第三方模型(非 Claude 原生),thinking 的 signature 机制可能不适用
  • 建议增加一个配置项:stripThinkingBlocks=true,在发送前移除所有 thinking 块

Contributor Guide