[Bug]: OpenRouter streaming chunks report the requested router name instead of the model OpenRouter served

当请求经由 OpenRouter 路由模型(如 openrouter/auto )并以 stream=True 调用时,流式分块的 model 字段会被 LiteLLM 覆盖成请求的路由名(如 auto ),而非 OpenRouter 实际服务的模型。优先排查 CustomStreamWrapper

快速结论:当请求经由 OpenRouter 路由模型(如 openrouter/auto)并以 stream=True 调用时,流式分块的 model 字段会被 LiteLLM 覆盖成请求的路由名(如 auto),而非 OpenRouter 实际服务的模型。优先排查 CustomStreamWrapper.chunk_creator 中是否只对 Azure 系 provider 回读 chunk 模型。

适用环境:LiteLLM v1.93.2(issue 报告在 main 分支 932a0d615 上复现);部署方式为 pip / Python SDK,未使用 proxy;OPENROUTER_API_KEY 通过环境变量设置。Issue 未提及操作系统、Python、CUDA、PyTorch 或显卡信息。

最快修复方案:暂无确认的一步修复方案。Issue 讨论中的修复方向是让 stream wrapper 对 OpenRouter 像 Azure 一样从 chunk 回读实际服务的模型,并配合聚合与成本回调的回归测试;对应修复已在 PR #49498 合并,升级到包含该修复的 LiteLLM 版本可优先尝试。

注意事项:该合并修复只出现在 Issue 讨论中,未给出可验证的版本号,因此无法确认从哪个版本起生效;升级前请先核对 release notes。另外,若上游 chunk 缺少模型名,不应凭空构造一个可计价的模型标识,否则可能让计费/日志关联到不存在的价格项。

问题场景

用户在 Python SDK 中直接调用 litellm.completion(),使用 OpenRouter 的路由模型 openrouter/auto 并开启 stream=True,遍历返回的 chunk 读取 chunk.model。OpenRouter 返回的原始 SSE 分块中 "model" 字段是实际服务的模型(例如 deepseek/deepseek-v4.1-flash),但消费端拿到的却始终是路由名 auto。同样请求改用 stream=False 时,response.model 能正确返回服务的模型,说明问题只出现在流式路径。

报错原文

[Bug]: OpenRouter streaming chunks report the requested router name instead of the model OpenRouter served
Output: ['auto']
Raw OpenRouter chunks for the same stream carried "model": "deepseek/deepseek-v4.1-flash"
Expected: ['deepseek/deepseek-v4.1-flash']

原因分析

最可能的原因是 CustomStreamWrapper.chunk_creator(litellm/litellm_core_utils/streaming_handler.py 约 1365 行)在构造每个 chunk 的 ModelResponseStream 时会执行 model_response.model = self.model。代码虽然会为 LlmProviders.AZURE 和 AZURE_AI 重新读取 chunk 自带的模型名(以支持 Azure 模型路由),但 OpenRouter 不在该列表中,因此 OpenRouter 路由流被覆盖回请求的别名。由于 stream_chunk_builder 继承了这个错误名称,最终聚合响应和成本回调也会看到 auto,而该名称没有对应的价格条目,导致路由流无法按实际应答模型计价或记录日志。

环境排查

  • 确认 LiteLLM 版本:v1.93.2 可复现;issue 提到 current main 932a0d615 仍可复现。
  • 确认调用方式为 pip / Python SDK,且 OPENROUTER_API_KEY 已在环境变量中设置。
  • 确认请求使用了 OpenRouter 路由模型(如 openrouter/auto)且 stream=True。
  • 确认 streaming_handler.py 中回读 chunk 模型的分支是否包含 OpenRouter,或已升级到包含 PR #49498 的版本。
  • Issue 未提供操作系统、Python、CUDA、PyTorch、显卡信息,无需据此排查。

解决步骤

  1. 先按 issue 的最小复现脚本确认现象:设置 OPENROUTER_API_KEY,用 litellm.completion(model="openrouter/auto", messages=[{"role": "user", "content": "Say hi"}], max_tokens=16, stream=True) 请求,收集 chunk.model 并去重输出。
  2. 若输出仅为 ['auto'],同时用 stream=False 发送同样请求,确认 response.model 是否为 OpenRouter 实际服务的模型(例如 deepseek/deepseek-v4.1-flash)。
  3. 检查当前 LiteLLM 安装中 litellm/litellm_core_utils/streaming_handler.py 的 chunk_creator:确认其仅针对 LlmProviders.AZURE 与 AZURE_AI 回读 chunk 模型,而 OpenRouter 未覆盖。
  4. 可优先尝试升级到包含 PR #49498 修复的 LiteLLM 版本(该 PR 在 issue 讨论中标记为已合并,但未给出具体版本号,请先在 release notes 中确认)。
  5. 升级或修复后,增加回归验证:用同一份合成流分别经过 chunk 聚合与成本/日志回调,确认请求别名作为路由元数据保留,同时实际服务模型在流式 chunk 和聚合响应上都得以保留。
  6. 补充边界用例:上游 chunk 模型为空或缺失时,不应构造一个可计价的模型标识。

验证方法

重新运行 issue 中的复现脚本,print(sorted(seen)) 输出应为实际服务模型(如 ['deepseek/deepseek-v4.1-flash'])而非 ['auto'],并与同一请求 stream=False 时 response.model 的值一致。进一步用 stream_chunk_builder 聚合该流,检查聚合响应的 model 以及成本回调中记录的模型是否为服务模型,同时确认请求的路由别名仍可在路由元数据中取得。

参考来源

BerriAI/litellm #46095

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 31621

发表回复

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