[Bug]: /v1/messages adapter drops reasoning_content → thinking blocks for OpenAI-compatible chat-completions backends (streaming)

当 LiteLLM 通过 /v1/messages 代理 OpenAI 兼容后端(如 vLLM、SGLang)并使用流式传输时,模型返回的 reasoning_content (推理链)在转译为 Anthropic 格式的 thinking 块时被静默丢弃。优先排查原始 SSE 流中是否包含 rea

快速结论:当 LiteLLM 通过 /v1/messages 代理 OpenAI 兼容后端(如 vLLM、SGLang)并使用流式传输时,模型返回的 reasoning_content(推理链)在转译为 Anthropic 格式的 thinking 块时被静默丢弃。优先排查原始 SSE 流中是否包含 reasoning_content 字段,以及 LiteLLM 版本是否低于包含修复的版本(PR #25852)。

适用环境:LiteLLM 作为代理;后端为 vLLM / SGLang 等使用推理解析器(如 DeepSeek-R1、Qwen3-reasoning、gpt-oss 带推理)的 OpenAI 兼容 Chat Completions 端点;客户端使用 Anthropic 格式流式请求(如 Claude Code、Anthropic SDK .stream())。

最快修复方案:暂无确认的一步修复方案。可优先尝试将 LiteLLM 升级到包含 PR #25852 中修复的版本(该 PR 针对流式起始块类型错误),或者手动应用该 PR 对 AnthropicStreamWrapper.__next__ 的更改——在首次发射 content_block_start 之前 peek 第一个 chunk,确保块类型匹配实际内容(thinking vs text)。

注意事项:PR #25852 仅解决了流式起始块类型错误,但底层转译器仍需完整支持回退至 reasoning_content。若后端为 Responses API 路径(而非 Chat Completions),则此问题通常不存在。

问题场景

用户通过 LiteLLM 的 /v1/messages 接口调用一个 OpenAI 兼容的后端(如 vLLM、SGLang 部署的推理模型),这些后端在 Chat Completions 响应中会返回 reasoning_content 字段(包含模型推理链)。当使用流式模式(Anthropic SDK 默认行为)时,客户端接收到的 SSE 事件中缺少 type: "thinking" 的块,仅包含 type: "text" 及其对应的 text_delta,导致推理链完全丢失。

报错原文

[Bug]: /v1/messages adapter drops reasoning_content → thinking blocks for OpenAI-compatible chat-completions backends (streaming)
Streaming response contains only content_block_start { type: "text" } and text_delta events. Zero thinking events.

原因分析

LiteLLM 的 Anthropic 格式转译器(litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py)在非流式和流式两种路径中,均只检查 thinking_blocks 字段来构建 thinking 内容块:

  • 非流式 _translate_openai_content_to_anthropic(约 816~903 行)判断 hasattr(choice.message, "thinking_blocks")
  • 流式 _translate_streaming_openai_chunk_to_anthropic(约 1024~1038 行)判断 hasattr(choice.delta, "thinking_blocks")

然而,对于 vLLM / SGLang 等后端,LiteLLM 的 OpenAI 响应解析器(gpt_transformation.py 574~575 行)会将 reasoning_content 正确捕获到 Message.reasoning_content 中,但 thinking_blocks 被显式设为 None。因此 Anthropic 转译器永远无法进入构建 thinking 块的逻辑,导致数据丢失。

此外,流式包装器 AnthropicStreamWrapper.__next__ 在读取第一个 chunk 之前就无条件发射 content_block_start {"type": "text"},使得后续即使检测到 reasoning_content 也无法修正块类型。

环境排查

celebrityanime
celebrityanime
文章: 15757

发表回复

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