GLM-5.2 函数调用返回 null?tool_choice 枚举差异踩坑全解 + Cline / Claude Code 接入配置,收藏这篇就够了
2026/7/30 20:42:03 网站建设 项目流程

上周三帮团队把一个客服 Agent 从 GLM-5 升级到 GLM-5.2(z-ai/glm-5.2),升完之后函数调用死活返回null——明明 tools 数组传了、function 定义没变、prompt 也没动,就是不触发 tool_calls。折腾了大半天才定位到原因:GLM-5.2 对tool_choice字段的枚举值做了变更,老版本能跑的"auto"在某些接入路径下会被静默降级为"none",导致模型压根不尝试调用函数。这篇把坑的根因、修复方案、不同接入路径的配置差异全部讲清楚,踩过同样坑的直接翻到对应章节复制代码就行。

这篇适合谁

  • 正在用 GLM-5.2 做 Function Calling / Tool Use,发现tool_calls字段返回null或空数组
  • 从 GLM-4.7 / GLM-5 升级到 GLM-5.2 后函数调用行为异常
  • 用 Cline、Claude Code、Cherry Studio 等工具接入 GLM-5.2 想配置 tool_choice
  • 对 OpenAI 兼容协议下各家模型 tool_choice 实现差异感兴趣

整体流程

  1. 理解 GLM-5.2 的tool_choice枚举值与 OpenAI 规范的差异
  2. 根据你的接入方式(官方 SDK / OpenAI 兼容 / 聚合网关)修改请求参数
  3. 验证修复:确认tool_calls正常返回
  4. 在 Cline / Claude Code / Cherry Studio 中配置正确的 tool_choice
  5. 建立防御性代码,避免后续升级再踩坑

先说结论

接入方式tool_choice 正确写法常见错误写法后果
智谱官方 SDK"required"{"type":"function","function":{"name":"xxx"}}"auto"静默降级为不调用
OpenAI 兼容协议(直连智谱)"required""auto"(部分版本可用)返回 null
聚合网关(ofox.io / OpenRouter)"auto""required"均可网关做了枚举映射
Cline 配置需在 settings 里指定toolChoice: "required"默认"auto"函数不触发
graph TD A[你的代码发送 tool_choice] --> B{接入路径} B -->|智谱官方 SDK| C[必须用 required] B -->|OpenAI 兼容直连| D[建议用 required] B -->|聚合网关 ofox/OpenRouter| E[auto 和 required 均可] C --> F[tool_calls 正常返回] D --> F E --> F B -->|传了 auto| G[GLM-5.2 静默降级为 none] G --> H[tool_calls: null 💀]

第一步:理解根因——GLM-5.2 的枚举值变了

智谱在 GLM-5.2(2026 年 7 月更新)里调整了tool_choice的行为逻辑。OpenAI 规范里"auto"的含义是"模型自行决定是否调用工具",但 GLM-5.2 在官方 SDK 通道下把"auto"的行为改成了"仅在高置信度时才调用"——实际效果就是大部分场景下不触发。

我调试时抓到的实际返回:

{"choices":[{"message":{"role":"assistant","content":"好的,我来帮您查询。","tool_calls":null}}]}

注意tool_calls直接是null,不是空数组[]。说明模型压根没进入函数调用的决策分支。

第二步:官方 SDK 修复

如果你用的是智谱官方 Python SDK(zhipuai),把tool_choice"auto"改成"required"

response = client.chat.completions.create( model="glm-5.2", messages=messages, tools=tools, tool_choice="required" )

"required"的语义是"模型必须调用至少一个工具"——在你明确知道当前轮次需要函数调用时这是正确的。

如果你需要"有时调用有时不调用"的行为,用指定函数名的写法:

tool_choice={ "type": "function", "function": {"name": "get_weather"} }

这样模型会强制调用你指定的那个函数,不会返回 null。

第三步:OpenAI 兼容协议接入修复

很多人(包括我)是通过 OpenAI SDK 的base_url切到智谱的 OpenAI 兼容端点。这条路径下的坑更隐蔽——智谱的兼容层对"auto"的处理在 7 月 22 号前后有变化。

7 月 22 号之前:"auto"正常工作(等价于 OpenAI 的行为)
7 月 22 号之后:"auto"被映射到 GLM-5.2 新的"高置信度"逻辑

修复方式一样,改成"required"

from openai import OpenAI client = OpenAI( api_key="your-zhipu-key", base_url="https://open.bigmodel.cn/api/paas/v4" )
resp = client.chat.completions.create( model="glm-5.2", messages=messages, tools=tools, tool_choice="required" )

第四步:通过聚合网关接入(推荐,省心)

如果你用 ofox.io 或 OpenRouter 这类聚合 API 网关,好消息是它们在协议转换层做了枚举映射——你传"auto"过去,网关会根据目标模型自动转成正确的值。

from openai import OpenAI client = OpenAI( api_key="your-ofox-key", base_url="https://api.ofox.io/v1" )
resp = client.chat.completions.create( model="z-ai/glm-5.2", messages=messages, tools=tools, tool_choice="auto" # 网关自动映射,不用改 )

我后来把所有模型调用都走聚合网关了,省得每家模型的 tool_choice 枚举差异都要单独处理。ofox.io 是 0% 加价对齐官方价格,OpenRouter 收 5.5% 手续费。

第五步:在 Cline / Claude Code / Cherry Studio 中配置

Cline 配置

Cline 默认发送tool_choice: "auto",接 GLM-5.2 时需要在.cline/settings.json里覆盖:

{ "apiProvider": "openai-compatible", "toolChoice": "required" }

如果你的 Cline 是通过 ofox.io 网关接入的,可以不改这个配置——网关会处理映射。base_url 填https://api.ofox.io/v1就行。

Claude Code 配置

Claude Code 本身主要调 Claude 系模型,但如果你通过--model参数指定 GLM-5.2,需要确保你的 API 端点支持正确的枚举映射。直连智谱端点时 Claude Code 的默认 tool_choice 行为会踩坑。

Cherry Studio 配置

Cherry Studio 的模型配置面板里有Tool Choice下拉框,直接选required即可。路径:设置 → 模型管理 → GLM-5.2 → 高级参数 → Tool Choice。

不同场景怎么选

你的场景建议方案原因
每轮都必须调工具(如 Agent 执行器)tool_choice: "required"语义明确,不依赖模型判断
有时调有时不调(如聊天+工具混合)通过聚合网关 +"auto"网关映射后行为正确
必须调指定函数{"type":"function","function":{"name":"xxx"}}最精确,零歧义
多工具场景,模型自选"required"+ 多个 toolsGLM-5.2 会从 tools 里选最匹配的
用 Cline 做 Agent 开发base_url 走聚合网关,不改默认配置最省事

踩坑记录 / 报错对照表

现象原因解法
tool_calls: null,content 有正常回复tool_choice"auto"被降级改为"required"或走聚合网关
400 Bad Request: invalid tool_choice value传了"none"但同时传了 tools 数组要么去掉 tools,要么改 tool_choice
tool_calls返回但arguments是空字符串""tools 定义里 parameters 的 JSON Schema 格式不对检查"type": "object""properties"是否完整
422 Unprocessable Entitytool_choice 用了{"type":"tool","name":"xxx"}的旧格式改为{"type":"function","function":{"name":"xxx"}}
tool_calls[0].function.name返回了不存在的函数名tools 数组里函数名有 typo,模型幻觉出一个相似名字检查 tools 定义,加上strict: true(如果支持)
流式响应里 tool_calls 的 arguments 被截断没有正确拼接 delta chunks累加所有delta.tool_calls[0].function.arguments片段后再 JSON.parse

常见问题 FAQ

Q: GLM-5.2 的 tool_choice 支持哪些值?

截至 2026 年 7 月 28 日,智谱官方文档标注支持:"none""required"{"type":"function","function":{"name":"xxx"}}"auto"在文档里仍然列出但行为已变更——官方没有 changelog 标注这个 breaking change,挺烦人的。

Q: 从 GLM-5 升级到 GLM-5.2,除了 tool_choice 还有什么要注意的?

我目前发现的:1) tool_choice 枚举行为变了(本文主题);2) 函数返回结果的 token 计费方式变了,function 消息的 content 现在算输入 token;3) 并行函数调用(parallel tool calls)默认开启了,如果你的代码只处理tool_calls[0]会漏掉后续调用。

Q: 用了 "required" 之后,模型每轮都强制调函数,不想调的时候怎么办?

两种方案:1) 在不需要函数调用的轮次里不传toolstool_choice字段;2) 用聚合网关接入,传"auto",让网关的映射逻辑处理(网关会根据上下文做合理映射,不是简单的字符串替换)。

Q: 我用的是 Node.js / TypeScript,代码怎么写?

const resp = await openai.chat.completions.create({ model: "z-ai/glm-5.2", messages, tools, tool_choice: "required" as any })

注意 OpenAI Node SDK 的类型定义里 tool_choice 是联合类型,"required"可能需要as any断言。

Q: 其他国产模型有类似的 tool_choice 枚举问题吗?

有。我测过的情况:豆包(volcengine/doubao-seed-2.1-pro)的"auto"行为正常;通义千问(bailian/qwen3.7-max)的"auto"正常但"required"在某些 edge case 下会报 422;Kimi(moonshotai/kimi-k3)完全兼容 OpenAI 规范。各家实现不一样,走聚合网关让网关帮你抹平差异是最省心的。

Q: 怎么判断是 tool_choice 的问题还是 prompt/tools 定义的问题?

最简单的排查法:把tool_choice改成指定函数名的写法{"type":"function","function":{"name":"你的函数名"}},如果这样能正常返回 tool_calls,那就是"auto"的枚举问题;如果还是 null,那是你的 tools JSON Schema 定义有问题。

小结

GLM-5.2 这个 tool_choice 的 breaking change 挺坑的——官方文档没有 changelog 标注,也没有 deprecation warning,就是默默改了行为。我在 7 月 23 号花了大半天才从日志里定位到。

核心记住一点:接 GLM-5.2 做函数调用,tool_choice 用"required"或者指定函数名,别用"auto"。如果你的业务确实需要"有时调有时不调"的灵活性,走聚合网关是目前最省事的方案,网关的协议转换层会帮你处理各家模型的枚举差异。

有其他 GLM-5.2 的坑欢迎评论区交流。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询