给 gpt-4o 定义一个查询工具,参数里用 oneOf 表达按订单号或按手机号二选一,strict 打开后请求回 400,原文是 Invalid schema for function 'query_order': In context=(), 'oneOf' is not permitted。

一开始怀疑是「嵌套层级里还混了 anyOf」,查了一圈,方向不对。

排查方向其实有限,先把可能性排一排。严格模式只支持有限的 JSON Schema 子集。也可能是oneOf 无法表达互斥必填 被直接拒绝。

少数情况下是工具 schema 从 OpenAPI 直接转过来 没做裁剪。

上来先把 schema 里的 oneOf 与 anyOf 找出来

python -c "import json;s=open('tool.json',encoding='utf-8').read();print('oneOf' in s,'anyOf' in s)"

再往下改成两个独立字段加业务校验

python fix_schema.py --in tool.json --out tool_fix.json --mode flat

然后用最小 schema 发一次调用

curl https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d @smoke.json

接着在代码里判断两个字段只填一个

python -c "a={'order_id':'1'};b={'phone':'13800000000'};print(bool(a)^bool(b))"

截短后的工具定义再跑一遍

python check_tools.py --in tool_fix.json

这类改动我都写进变更记录,过两周再出问题时能对上号。

别只看报错消失,验证要多做一步。请求返回 200,模型按字段填参,两个字段同时为空的调用在业务层被拦下并提示重试。

这里还有个坑。严格模式省的是解析失败,不是业务校验,互斥条件放在代码里判断比塞进 schema 更稳。这类问题最好一次改到位,反复小改反而容易把原因搅混。

作者 9823189