先看现象。Agent 里定义了 create_ticket 工具,参数是 customer 对象里再套 contact。模型经常把 contact 直接平铺到最外层,schema 之所以放行是因为 additionalProperties 没关,等 pydantic 解析时才报 field required,错误只指到顶层,看不出缺的是哪一支。环境 langchain 0.3 加 pydantic 2.9。
真正麻烦的地方在于,几个原因的现象几乎一样。参数 schema 没关 additionalProperties,多出来的键被放过。还有一种是嵌套对象在工具描述里写得太含糊,模型按扁平结构理解。
不容易想到的是,解析时没开 strict,缺失字段被默认值悄悄补掉。
还有一种情况,校验失败的错误没回灌给模型,下一轮还在同样地错。
上来先看模型实际给出的参数原文
python -c "import json;print(json.dumps(json.load(open('tool_call.json')),ensure_ascii=False,indent=2))"
再往下把 additionalProperties 关掉后重新请求
curl -s https://gw.local/v1/chat/completions -H 'Content-Type: application/json' -d @body_strict.json | jq '.choices[0].message.tool_calls'
接着用严格模型解析并打印完整字段路径
python -c "from pydantic import BaseModel,ValidationError;print('strict parse')"
失败时把字段路径回灌给模型再跑一轮
python agent_retry.py --max-round 3 --strict
改完先别撤,确认这几项。同一批 100 次工具调用,解析失败从 17 次降到 1 次,失败日志里能看到 customer.contact 这样的完整路径。
提醒一点。校验要放在执行工具之前而不是之后,错误信息越具体模型自我修正越快;默认值会把缺字段的错掩盖成业务错。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
