这个坑值得记一笔。用 gemini-2.0-flash 做结构化抽取,responseSchema 里用 anyOf 表达金额可能是数字也可能是字符串,接口回 400,原文是 Invalid JSON payload received. Unknown name anyOf,换成单一类型后正常。
刚开始盯着「从 pydantic 生成的 schema 直接塞入」,折腾了半个多小时,排掉了。
真正麻烦的地方在于,几个原因的现象几乎一样。responseSchema 只支持 OpenAPI 的子集;anyOf 与 oneOf 都不在支持列表里;嵌套数组的 items 里也有 anyOf。
第一件事是导出当前 schema 并找 anyOf
python -c "import json;s=json.load(open('schema.json'));print('anyOf' in json.dumps(s))"
随后合并成单一类型 金额统一用 number
python flatten_schema.py --in schema.json --out schema_fix.json --prefer number
发一次结构化请求确认
curl https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent -H "x-goog-api-key: $GEMINI_API_KEY" -H "Content-Type: application/json" -d @req.json
批量回放样本看解析率
python validate_out.py --schema schema_fix.json --in cases.jsonl
命令输出我都留了记录,免得改完记不清原来的值。
改之前先确认了最近有没有人动过配置,避免白查一遍。
别只看报错消失,验证要多做一步。请求返回 200,返回的 JSON 能直接反序列化,金额字段类型统一,解析成功率达到 100%。
这里还有个坑。类型放宽后模型可能把金额写成带币种的字符串,下游仍要做一次显式转换。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
