问题概述
通过 Anthropic Messages API(/v1/messages)调用推理模型时,思考过程(thinking block)完全不会回传到客户端。Claude Code / 任意 Anthropic SDK 只能看到最终正文,看不到模型推理内容。
注意:这不是模型不支持思考——通过 OpenAI 端点(/v1/chat/completions)调用同一模型可以正常收到推理内容(见下方证据)。问题出在本代理的 Anthropic 响应转换路径。
根因(两处)
1. 响应方向:Anthropic 流式转换丢弃推理事件(直接原因)
createAnthropicSseTranslator(proxy.mjs:1387)对上游的推理事件直接丢弃,从不生成 Anthropic 的 thinking block:
case 'reasoning-start': // :1383 也仅计事件,不产出 content block
break;
case 'reasoning-delta':
// Anthropic Messages API default mode doesn't expose thinking blocks
break; // ← 思考内容在此被丢弃
流式响应因此只输出 text / tool_use 两种 content block,永远没有 {type:"thinking"}。
2. 响应方向:非流式响应也不含 thinking block
buildAnthropicResponse(proxy.mjs:1138)只组装 text 与 tool_use 两类 content block:
const content = [];
if (fullText) content.push({ type: 'text', text: fullText });
if (toolCalls) { /* push tool_use */ }
没有任何 { type: 'thinking', thinking: ... } 的输出分支。
对照:OpenAI 端(/v1/chat/completions)已正确回传推理——流式 proxy.mjs:553 把 reasoning-delta 转成 reasoning_content,非流式 proxy.mjs:1010/:1076 累积后合并。这证实了上游确实会产出 reasoning 事件,Anthropic 端只是没有回传。
复现与证据
证据 A:本地 mock 上游端到端复现(代理指向返回 reasoning-delta 的 mock 上游)
上游返回含 reasoning-start / reasoning-delta / reasoning-end 的事件流,代理转成 Anthropic 响应后:
- 流式 仅收到
content_block_start(text) → content_block_delta(text_delta) → content_block_stop,无任何 thinking block。
- 非流式 返回
content:[{"type":"text","text":"..."}],同样无 thinking。
即:即使模型明确在思考并输出推理事件,Anthropic 端也全部丢掉了。
证据 B:真实 API key 验证(deepseek/deepseek-v4-pro,/v1/chat/completions,max_tokens=32)
真实调用返回了推理内容,证明模型确实会思考、且 OpenAI 端能正确回传:
"content": null,
"reasoning_content": "The user is asking \"1加1等于几?\" ...",
"finish_reason": "length"
(prompt_tokens:7577,其中 cached_tokens:7424 已被缓存,未额外消耗大量 token。)
两个证据相互印证:模型确实思考,但 Anthropic 端从不同步思考内容。
影响
- Claude Code 以及所有通过 Anthropic SDK 使用该代理的客户端,看不到模型的思考过程。
- 对依赖 visible thinking 的推理模型(如 deepseek-v4-pro 等带 reasoning 的模型)体验不完整。
建议修复
- 流式
createAnthropicSseTranslator:为 reasoning-start / reasoning-delta / reasoning-end 各事件增加 thinking block 输出——
reasoning-start → content_block_start { type:"thinking", thinking:"" }
reasoning-delta → content_block_delta { delta: { type:"thinking_delta", thinking } }
reasoning-end → content_block_stop
- 复用现有
nextBlockIndex 编号器,与 text/tool block 正确编排索引。
- 非流式
buildAnthropicResponse 及对应非流式解析处:累积推理内容,追加 { type:"thinking", thinking },并按 Anthropic 规范映射 stop_reason。
问题概述
通过 Anthropic Messages API(
/v1/messages)调用推理模型时,思考过程(thinking block)完全不会回传到客户端。Claude Code / 任意 Anthropic SDK 只能看到最终正文,看不到模型推理内容。根因(两处)
1. 响应方向:Anthropic 流式转换丢弃推理事件(直接原因)
createAnthropicSseTranslator(proxy.mjs:1387)对上游的推理事件直接丢弃,从不生成 Anthropic 的 thinking block:流式响应因此只输出
text/tool_use两种 content block,永远没有{type:"thinking"}。2. 响应方向:非流式响应也不含 thinking block
buildAnthropicResponse(proxy.mjs:1138)只组装text与tool_use两类 content block:没有任何
{ type: 'thinking', thinking: ... }的输出分支。对照:OpenAI 端(
/v1/chat/completions)已正确回传推理——流式proxy.mjs:553把reasoning-delta转成reasoning_content,非流式proxy.mjs:1010/:1076累积后合并。这证实了上游确实会产出 reasoning 事件,Anthropic 端只是没有回传。复现与证据
证据 A:本地 mock 上游端到端复现(代理指向返回 reasoning-delta 的 mock 上游)
上游返回含
reasoning-start / reasoning-delta / reasoning-end的事件流,代理转成 Anthropic 响应后:content_block_start(text)→content_block_delta(text_delta)→content_block_stop,无任何 thinking block。content:[{"type":"text","text":"..."}],同样无 thinking。即:即使模型明确在思考并输出推理事件,Anthropic 端也全部丢掉了。
证据 B:真实 API key 验证(
deepseek/deepseek-v4-pro,/v1/chat/completions,max_tokens=32)真实调用返回了推理内容,证明模型确实会思考、且 OpenAI 端能正确回传:
(
prompt_tokens:7577,其中cached_tokens:7424已被缓存,未额外消耗大量 token。)两个证据相互印证:模型确实思考,但 Anthropic 端从不同步思考内容。
影响
建议修复
createAnthropicSseTranslator:为reasoning-start/reasoning-delta/reasoning-end各事件增加 thinking block 输出——reasoning-start→content_block_start{ type:"thinking", thinking:"" }reasoning-delta→content_block_delta{ delta: { type:"thinking_delta", thinking } }reasoning-end→content_block_stopnextBlockIndex编号器,与 text/tool block 正确编排索引。buildAnthropicResponse及对应非流式解析处:累积推理内容,追加{ type:"thinking", thinking },并按 Anthropic 规范映射stop_reason。