responses.parse 同时传了 text_format 和 text.format,为什么还没请求就报 TypeError
responses.parse 不接受 text_format 与 text.format 两个格式入口同时存在。Pydantic 解析保留 text_format,手写 schema 改用 create,并检查封装是否重新填回冲突字段。
responses.parse 同时传了 text_format 和 text.format,为什么还没请求就报 TypeError
同一个调用里既传 Pydantic 类型,又复制了手写 schema:
TypeError: Cannot mix and match text.format with text_format
这里要修的是调用参数组合。responses.parse() 会根据 text_format 生成输出格式;若 text 字典里同时出现 format,SDK 无法接受两个格式入口,就在发送请求之前抛错。
openai 1.109.1 的官方源码包含这一显式检查,以下示例以该版本接口为基线。本文不推断它最早在哪个发行版本加入;请先记录项目实际安装的 openai.__version__。Responses 客户端源码
想拿到 Pydantic 对象,就只保留 text_format
下面使用一个最小抽取对象。模型名和密钥从环境变量读取;运行会发送真实请求并可能计费。
import os
from pydantic import BaseModel
from openai import OpenAI
class Ticket(BaseModel):
subject: str
with OpenAI(api_key=os.environ["OPENAI_API_KEY"]) as client:
response = client.responses.parse(
model=os.environ["OPENAI_MODEL"],
input="工单标题:导出任务超时",
text_format=Ticket,
)
if response.status != "completed":
raise RuntimeError("响应未完成,不能写入业务结果")
ticket = response.output_parsed
if ticket is None:
raise RuntimeError("没有可用的结构化结果,请检查拒绝等分支")
assert isinstance(ticket, Ticket)
print(ticket.subject)
删的是冲突的 text.format。如果 text 中还有模型支持的其他配置,不必把整个配置对象全删掉。封装函数最好把输出类型作为唯一来源,别让调用者同时从另一个字典传入格式。
想自己管理 JSON Schema,就走 create 并校验
手写格式放进 Responses 的 text.format。下面只构造参数,不联网:
text_config = {
"format": {
"type": "json_schema",
"name": "ticket",
"strict": True,
"schema": {
"type": "object",
"properties": {"subject": {"type": "string"}},
"required": ["subject"],
"additionalProperties": False,
},
},
}
在现有代码里将它作为 client.responses.create(..., text=text_config) 的参数,不再传 text_format。收到结果后,先判断状态和拒绝,再校验相应的输出文本;可以用 Ticket.model_validate_json(...) 做类型校验。模型支持的 schema 子集仍以接口文档为准。结构化输出指南
不要把 Chat Completions 的 response_format 原样搬过来。这里的格式对象直接放在 text.format,不是再包一层同名的 Chat Completions 字段。两个端点的参数结构不一样,复制配置时需要连同调用入口一起看。
参数明明删了,怎么还在报
最容易漏掉的是二次合并:调用处移除了 schema,公共封装又从默认配置里填回来了。检查真正传给 SDK 的最终参数,但只记录字段名和类型,别把完整输入、密钥或用户内容写进日志。
可以在自己的封装边界加一个小检查:
def check_format_entry(kwargs):
text = kwargs.get("text") or {}
if "text_format" in kwargs and "format" in text:
raise ValueError("只允许一个输出格式入口")
check_format_entry({"text_format": Ticket})
check_format_entry({"text": text_config})
这个应用侧检查约定“未使用的参数直接省略”。不要给 text_format 填 None 作为关闭开关;明确不使用时,从 kwargs 删除它,避免把无效值继续传入 SDK。
验收时分别检查类型入口、手写入口和双入口三种情况。前两种应进入各自的正确调用流程;双入口应在本地被拒绝。仅消除 TypeError 还不够,结构化结果必须经过完成状态、拒绝分支和字段校验后才能进入业务。


