这个坑值得记一笔。把业务方法名直接当函数名,里面带了下划线和中文后缀,接口返回 400,原文 tools[0].function.name does not match pattern,本地 mock 完全正常。
刚开始盯着「注册工具时没做校验,到了调用才报错」,折腾了半个多小时,排掉了。
排查方向其实有限,先把可能性排一排。函数名只允许字母数字下划线和短横线,长度有上限;OpenAI 与 Anthropic 对 name 的正则不完全一致;工具名重复,后注册的覆盖了前一个。
上来先用正则校验注册表里的工具名
python -c "import re;print([n for n in ['get_price','查价'] if not re.match(r'^[a-zA-Z0-9_-]{1,64}$',n)])"
再往下把中文名映射成英文别名再注册
python -c "m={'查价':'get_price'};print(list(m.values()))"
接着检查是否有重名工具
python -c "import json;n=[t['function']['name'] for t in json.load(open('tools.json'))];print(len(n),len(set(n)))"
剩下的就是用改名后的工具发一次调用验证
curl -s https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"查价"}],"tools":[{"type":"function","function":{"name":"get_price","parameters":{"type":"object","properties":{}}}}]}'
怎么算真的好了,看的是同一批现象。注册阶段就能拦下非法名,请求返回 200 且 tool_calls 里的 name 与注册表一致。
工具名是协议字段不是展示文案,中文名再直观也要映射成 ASCII 再发出去。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
