Responses API: sending a client-authored assistant turn requires either a fake message id or a `# type: ignore`

当你在使用 OpenAI Python SDK 的 Responses API 回放自己构造(或从外部存储恢复)的 assistant 消息,尤其是包含多个 output_text 内容块时,类型检查器会要求你补上 id 和 status 字段,否则报错 sending a client-autho

快速结论:当你在使用 OpenAI Python SDK 的 Responses API 回放自己构造(或从外部存储恢复)的 assistant 消息,尤其是包含多个 output_text 内容块时,类型检查器会要求你补上 idstatus 字段,否则报错 sending a client-authored assistant turn requires either a fake message id or a # type: ignore。优先排查是否把 assistant turn 当成完整 OutputMessage 传入,以及是否启用了 pyright/mypy 等类型检查。

适用环境:Issue 中确认的信息包括:OpenAI Python SDK openai 2.48.0(正文验证)和 openai 2.49.0(评论验证)、类型检查器 pyright 1.1.411;示例使用的模型为 gpt-5。Issue 未提供操作系统、Python 版本、CUDA 或显卡信息,请勿据此推断。

最快修复方案:暂无确认的一步修复方案。Issue 最终被关闭并重定向到上游 openai/openai-openapi#565,因为修复需要落在 generated spec 一侧(放宽 OutputMessage.required 中的 idstatus),SDK 端的补丁会在下次同步时被覆盖。

注意事项:Issue 中提到的临时绕过手段(编造 id# type: ignore、把 content 写成字符串)都各有局限;编造 id 可能影响 prompt caching,字符串写法无法承载多个 output_text 块或 annotations。这些都不是已验证的官方修复。

问题场景

用户在 OpenAI Python SDK 中调用 client.responses.create(model=..., input=conversation),并把一段对话历史作为 input 传入。该历史中包含一条由客户端自行撰写或从存储回放的 assistant 消息,消息的内容是多个 output_text 块(例如从之前的 Responses API 输出中取回,或经过编辑后再发送)。在启用类型检查器(如 pyright)时,ResponseInputParam 无法接受这种写法,必须补上 idstatus

报错原文

Responses API: sending a client-authored assistant turn requires either a fake message id or a `# type: ignore`

类型不匹配的三种写法所对应的实际表现:

# 方式一:必须补上编造的 id 和 status
{"type": "message", "id": "msg_fake_msg_id", "status": "completed", "role": "assistant", "content": [...]}

# 方式二:省略 id/status 时,需要 # type: ignore
{"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "5", "annotations": []}]}  # type: ignore

# 方式三:把 output_text 换成 input_text 可通过类型检查,但服务端返回 400
{"error": {"message": "Invalid value: 'input_text'. Supported values are: 'output_text' and 'refusal'.",
           "type": "invalid_request_error", "param": "input[1].content[0]", "code": "invalid_value"}}

原因分析

可能原因是 OpenAI Python SDK 的请求类型复用了响应侧的 OutputMessage schema(由 openai-openapi 生成),而该 schema 把 idtyperolecontentstatus 全部列为 required。对于由 API 生成后再发回的消息,这些字段天然存在;但对于客户端自行撰写、从存储回放或编辑后的 assistant turn,idstatus 并不存在,于是就出现了类型层面与服务端实际接受行为不一致的冲突。

Issue 评论对比了同类 schema:FunctionToolCall 同样既由服务端返回、又由客户端在工具调用往返中重新发送,但 spec 中只把语义字段(call_idnamearguments)标记为 required,id/status 是可选的。因此评论认为更接近 OutputMessage 尚未获得同样的处理,而非有意约束 assistant 消息。最终维护者确认:这属于请求/响应 schema 分离问题,已在上游 openai/openai-openapi#565 跟踪。

环境排查

  • 确认 OpenAI Python SDK 版本(Issue 验证过 2.48.02.49.0)。
  • 确认类型检查器及版本(Issue 使用 pyright 1.1.411;mypy 行为未验证)。
  • 确认传入 input 的 assistant 消息是否使用了 {"type": "message", ...} 形式而非简化的 EasyInputMessageParam 字符串形式。
  • 确认 assistant 消息的 content 是否包含多个 output_text 块或 annotations —— 这类结构无法用字符串形式替代。
  • 确认模型名称(示例为 gpt-5);Issue 未提供操作系统、Python、CUDA、显卡等信息,无需额外排查。

解决步骤

  1. 先判断你的 assistant 回放消息是否需要携带多个 output_text 块或 annotations。如果不需要,可优先尝试评论中提到的字符串写法:{"role": "assistant", "content": "5"},它路由到 EasyInputMessageParam,无需 id/status,在 pyright 1.1.411 / openai 2.49.0 下验证通过。
  2. 如果需要保留多个 output_text 块,Issue 中原作者确认字符串写法无法覆盖该场景,需要等待上游修复。可优先尝试的临时方式是补上编造的 idstatus,但要注意这可能影响 prompt caching,且需要自己保证同一对话前缀生成稳定的合成 id。
  3. 不要通过把 output_text 改成 input_text 来绕过类型检查——Issue 验证这条路会在服务端返回 400 Invalid value: 'input_text'
  4. 不要 fork 修改 response_output_message_param.py:评论指出该 SDK 由 Stainless 从 openai-openapi 生成,本地补丁会在下一次 spec 同步时被回滚。
  5. 关注上游修复进展:维护者已将问题关闭并重定向到 openai/openai-openapi#565(请求/响应 schema 分离)。相关 spec 侧报告还包括 openai/openai-openapi#475(content union 不匹配)。评论建议的窄修复是:从 OutputMessage.required 中移除 idstatus,与 FunctionToolCall 对齐;该修复同时覆盖 status 部分,而此前提出的 #3015 仅放宽 id,不足以解决本问题。

验证方法

在类型检查器下运行你的构造代码:如果采用的临时写法不再需要 # type: ignore 或编造字段,并能在 client.responses.create(...) 下正常返回结果,即说明该写法在当前版本可用。若需要确认上游修复是否落地,请跟踪 openai/openai-openapi#565 的状态以及后续 SDK 版本中 OutputMessage.required 是否变更。

参考来源

openai/openai-python #3544

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 23659

发表回复

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