报错是这么冒出来的。Claude 3.7 用 tool_choice 指定 record 工具想强制结构化输出,返回 200 但 stop_reason 是 tool_use,content 里 input 是空对象,业务侧取字段直接 KeyError,改提示词也没用。
中间走过弯路,把「工具描述与字段描述互相矛盾」当成主因,改完现象没变。
原因不止一个,得分开看。schema 里没有 required,模型可以合法返回空对象。另一种情况是max_tokens 偏小,参数还没写完就被截断。
另外,thinking 预算占用了输出额度。
第一件事是看 stop_reason 与 usage 判断是否被截断
python -c "import json;d=json.load(open('resp.json'));print(d['stop_reason'],d['usage'])"
给 schema 补 required 与字段说明
python -c "import json;s=json.load(open('tool.json'));s['input_schema']['required']=['title','amount'];json.dump(s,open('tool2.json','w'))"
再往下把 max_tokens 提到 2048 再试
python -c "import json;d=json.load(open('req.json'));d['max_tokens']=2048;json.dump(d,open('req2.json','w'))"
空对象时走一次带示例的重试
python retry_with_example.py --case empty_input --out retry.json
这类改动我都写进变更记录,过两周再出问题时能对上号。
我习惯把每一步的执行时间和结果记在一边,后面复盘省事。
别只看报错消失,验证要多做一步。input 里稳定出现 title 与 amount,stop_reason 为 tool_use 且没有再出现空对象。
强制工具不等于强制填字段,required 和足够的输出预算缺一不可,两者都补上才稳。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
