[Bug]: `/v1/responses` can replay `chatcmpl-*` message IDs into OpenAI Responses during cross-provider handoffs

该报错发生在跨提供商切换场景下(例如 Claude 通过 LiteLLM 桥接后切换到 OpenAI Responses 模型),旧消息中的 `chatcmpl-*` ID 被透传到 OpenAI 原生 Responses API,导致校验失败。优先排查 LiteLLM 的 Chat Complet

快速结论:该报错发生在跨提供商切换场景下(例如 Claude 通过 LiteLLM 桥接后切换到 OpenAI Responses 模型),旧消息中的 `chatcmpl-*` ID 被透传到 OpenAI 原生 Responses API,导致校验失败。优先排查 LiteLLM 的 Chat Completions 桥接转换逻辑(transformation.py)中输出消息项的 ID 是否未重写为 `msg_*` 格式。

适用环境:LiteLLM Proxy,涉及 Chat Completions 桥接路径与 OpenAI Responses API 之间的消息传递;Issue 中未确认特定操作系统、Python 或 CUDA 版本。

最快修复方案:暂无确认的一步修复方案。Issue 中提出在 `litellm/responses/litellm_completion_transformation/transformation.py` 的 `_extract_message_output_items` 方法中生成 `msg_*` 格式 ID,或者将原 `chatcmpl-*` ID 通过 base64 编码映射为 `msg_` 前缀格式,但此修复尚未合并到上游代码。

注意事项:该修复方案仅为 Issue 讨论中的建议,未经过官方验证或合并;若选择自行打补丁,需注意保持 ID 稳定性和重试兼容性,避免影响多轮对话历史重建。

问题场景

在单个 agent 工作流中,先通过 LiteLLM 调用 Claude/Anthropic(走 Chat Completions 桥接),再将同一会话历史切换到 OpenAI Responses 原生模型。会话历史中的前一 assistant 消息仍保留 `chatcmpl-*` 风格的 ID,当它作为 `input` 项转发给 OpenAI Responses 时被拒绝。

报错原文

[Bug]: `/v1/responses` can replay `chatcmpl-*` message IDs into OpenAI Responses during cross-provider handoffs

Invalid 'input[1].id': 'chatcmpl-dfa2da3a-1586-4ff7-b64e-f59c692a5d11'. Expected an ID that begins with 'msg'.

原因分析

根本原因在 LiteLLM 的 Chat Completions 桥接路径。当提供商没有原生 Responses 配置时,`litellm.responses()` 会走 `litellm_completion_transformation_handler.response_api_handler(…)` 桥接。

该桥接在构造 `ResponsesAPIResponse` 和 `GenericResponseOutputItem` 时,直接复用了 Chat Completions 响应的 `id`(即 `chatcmpl-*`),而没有重写为 OpenAI Responses 要求的 `msg_*` 前缀。当这些输出项被保存为会话历史,之后作为 `input` 发送给原生 OpenAI Responses API 时,OpenAI 校验每个输入项的 `id` 字段,发现前缀不符合要求即拒绝请求。

Issue 还指出,`_update_responses_api_response_id_with_model_id` 在 `streaming_iterator.py` 中会将顶层响应 ID 重新编码为 `resp_*` 格式,但不会更新 `output` 数组内消息项的 ID,导致校验失败。

环境排查

  • 确认 LiteLLM 版本是否包含 litellm/responses/litellm_completion_transformation/transformation.py 文件。
  • 确认提供商是否在 ProviderConfigManager._get_python_responses_api_config 中有原生 Responses 配置(OpenAI、Azure、xAI 等有,Anthropic 没有)。
  • 确认是实时内存中的历史消息透传,还是持久化后重新加载;后者如果存储层丢弃 id 字段,可能不触发该问题。

解决步骤

  1. 复现路径:使用 Claude 通过 LiteLLM 生成 assistant 消息,保留内存中的响应对象,再将该对象作为 input 发送给 OpenAI Responses 模型。
  2. 检查 LiteLLM 是否将 chatcmpl-* 直接用作输出消息项的 ID(可在变换后的 JSON 中查看 output[0].id 值)。
  3. 如果有自建能力,可优先尝试在 _extract_message_output_items 中生成 msg_ 前缀的 UUID ID,替换原来的 chatcmpl-*,例如:msg_{uuid4().hex}
  4. 或者尝试将 chatcmpl-* ID 通过 base64 编码映射为 msg_ 前缀格式,保持 ID 稳定且可追溯。
  5. 若无法自行修补,考虑在跨提供商切换时,由上层逻辑在转发前重置消息 id 字段,确保以 msg_ 开头。

验证方法

执行跨提供商切换流程(Claude → OpenAI Responses),确认不再出现 Expected an ID that begins with 'msg' 错误;同时检查转发目标接收到的 input[*].id 值均符合 msg_* 格式,多轮对话仍能正常关联。

参考来源

BerriAI/litellm #27333

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 19772

发表回复

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