事情本身不复杂,线索都在日志里。把 pydantic 导出的 schema 直接塞进 response_format 的 json_schema 并打开 strict:true,请求 400,原文 Invalid schema for response_format,报错定位到某个 allOf 分支。
第一反应是「required 必须列出该层全部属性,可选字段只能靠 null 类型表达」,验证下来不成立。
这类报错背后常见的原因有几处,逐个排除就行。strict 只支持 JSON Schema 的一个子集,allOf、anyOf 这类组合关键字不认。另一种情况是每个 object 都要显式写 additionalProperties: false。
不容易想到的是,default 与 enum 同时出现在一个字段上会被判为不支持。
上来先用最小请求复现,把错误信息完整取出来
curl -s https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"x"}],"response_format":{"type":"json_schema","json_schema":{"name":"m","strict":true,"schema":{"type":"object","properties":{"a":{"allOf":[{"type":"string"}]}},"required":["a"],"additionalProperties":false}}}}' | jq '.error.message'
再往下把组合关键字改成扁平的类型声明
python -c "import json;print(json.dumps({'type':'object','properties':{'a':{'type':'string'}},'required':['a'],'additionalProperties':False}))"
然后检查导出的 schema 里还残留哪些组合关键字
python -c "import json;s=open('schema.json').read();print([k for k in ('allOf','anyOf','oneOf','$ref') if k in s])"
剩下的就是确认每个 object 都补了 additionalProperties
python -c "import json;s=json.load(open('schema.json'));print(s.get('additionalProperties'))"
怎么算真的好了,看的是同一批现象。同一请求返回 200 且输出能被 json.loads 解析,字段齐全、类型与 schema 对齐,日志里不再出现 Invalid schema。
补一句。pydantic 生成的 schema 追求表达力,strict 追求可预测,中间那层适配要自己写,直接把导出结果丢过去十有八九失败。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
