Cherry Studio 的 Function Calling 工具调用怎么配置,模型才会真正执行本地工具?
要让模型在 Cherry Studio 里真正执行本地工具,必须同时满足三个条件:所选模型通道把 tools 参数原样转发,并返回结构化的 tool_calls;助手设置里挂载了带完整 JSON Schema 描述的工具;当前对话已开启工具调用开关。只支持纯文本补全的通道不具备这项能力,工具描述含糊或结果没有按 tool_call_id 回传时,模型会表现为不调用或反复调用。
在 Cherry Studio 中让模型真正执行本地工具,需要同时满足三个条件:所选模型通道支持 tools 参数并返回结构化 tool_calls、助手设置里挂载了带 JSON Schema 描述的工具、当前对话开启了工具调用开关;只支持纯文本补全的通道不具备这项能力。三者缺一,表现都一样:模型只回一段自然语言,看上去像配置没生效。真正难的是判断先检查哪一环,因为这三层的失败现象几乎一模一样。
Function Calling 的能力在模型侧,不在 Cherry Studio 侧。Cherry Studio 只做四件事:把已挂载的工具定义序列化进请求、解析响应里的 tool_calls、按调用参数执行本地工具、把执行结果写回上下文再发起下一轮。它本身不判断该不该调用工具,也不补全模型漏掉的参数。所以排查顺序应当是模型通道、工具定义、客户端聚合、结果回传,从后往前改提示词,基本是白费功夫。
判断一个模型通道能不能用工具调用,不能看模型名字,要看请求体里 tools 数组有没有被转发、响应里有没有 tool_calls 结构。可行的验证做法是新建一个空白助手,只挂一个无副作用、参数极简的工具,比如回显一段文本或读取当前时间,然后发一句指令明确的请求,观察原始响应。如果模型只给自然语言而不产生调用,先换通道再怀疑配置。部分聚合接口为了兼容旧客户端会直接丢弃 tools 字段,或者把调用意图写进 content 文本里而不返回结构化结构,这类通道只能当纯聊天用,不要在它上面调试 Schema。
工具定义的关键在 description,不在 name。JSON Schema 里要写清这个工具在什么场景下使用、每个参数是什么含义、哪些必填、取值范围与格式,模型正是靠这段文字决定是否选中它、怎么填参数。description 写成「查询数据」这类空泛描述,模型要么不调用,要么把不相干的参数硬塞进来。把 enum 收紧、把 required 收窄、能不给的参数就不给,能显著减少参数错误。工具名保持动词加对象的短结构,便于模型区分相似能力。
一个可用的工具定义,描述部分应当同时说明「什么时候用」和「什么时候不要用」。例如订单查询工具的描述写成「根据订单号查询订单状态与物流节点,仅在用户已提供订单号或明确要求查询订单时使用,不要用于创建、修改或取消订单」,参数只保留一个必填的订单号字符串。这样模型在闲聊时不会误触发,在用户给了单号时命中率也高。参数中涉及日期、金额、枚举状态的,把格式和取值范围写进描述,比事后纠正便宜得多。
Cherry Studio 的工具接入有两条路径:MCP 服务器适合复用已有能力,自定义工具适合把单个 HTTP 接口暴露给模型。MCP 配置要填启动命令或服务地址,本地进程走 stdio,远程走 SSE 或 streamable HTTP,命令、路径、工作目录或环境变量写错时,典型表现是连接显示成功但工具列表为空。配置前先在终端里手工跑一遍启动命令,确认进程能起来并正常输出协议消息。自定义工具则要手写 name、description 和 parameters,保存后在助手设置里勾选启用,两条路径可以同时存在。
工具不是挂得越多越好,单个助手只挂当前任务强相关的少量工具,选择准确率更稳。工具池过大时模型容易在两个相似工具之间摇摆,或者调用一个之后再调用另一个做重复动作,白烧 token。可按场景拆分助手,检索类、文件类、接口类各用一个助手,避免把所有工具塞进同一轮上下文。tool_choice 可以强制指定某个函数或禁止调用,但它会让模型失去自主判断,只在流程确定的单步场景里使用,不要当常规配置。
流式模式下 tool_calls 是分片到达的,arguments 常被拆成多段字符串,客户端必须按 index 聚合后再做 JSON 解析。解析失败通常不是模型不会调用,而是拼接时丢了片段,或模型在 JSON 外多写了一段说明文字,也可能是参数值里带了未转义的换行。保留原始片段日志、对 arguments 做完整性校验,解析失败时把具体错误信息回传给模型让它重发一次,比直接抛给用户更有效。
工具执行完必须用 tool 角色、带上对应的 tool_call_id 回传结果,缺这个 id 模型无法把结果和调用配对,表现为重复调用同一个工具或干脆忽略返回值。同一轮里出现多个 tool_calls 时,要逐个执行、逐个回传,顺序与 id 一一对应。结果内容要精简,只回传模型判断所需的字段,整段页面源码或大体积 JSON 会挤占上下文,导致后续轮次遗忘任务目标,也直接推高单轮成本。
一次用户请求里模型可能连续调用多轮工具,客户端必须设置最大轮次上限,超过就停止并把已完成的部分告知用户,否则会出现来回调用同一工具的死循环。工具返回失败时也要给出固定结构,写清失败原因与是否可重试,让模型知道该换参数还是该停下来问用户。带副作用的写操作要加幂等键,避免模型因超时重试而重复执行同一动作。
排查「配置了但不生效」按四层看:请求层有没有 tools 数组、响应层有没有 tool_calls、执行层工具是否被真正触发、回传层结果有没有进入上下文。多数问题停在前两层,原因分别是通道不转发和工具描述太泛。逐层看日志比反复改提示词快得多,也比换模型更省时间,因为换模型往往只是把问题从第一层挪到第二层。
工具会真实执行带副作用的操作,不能让模型直连生产写接口。优先给只读工具,写操作加参数白名单、超时和幂等键,删除、支付、对外发消息这类动作保留人工确认。工具返回的错误信息也要脱敏,避免把内部地址和凭据带进上下文。有两类场景不适合用自由工具调用:需要强确定性的多步流程应当用工作流编排,而不是让模型每轮自行选择工具;纯文本模型通道也不适用,只能靠提示词模拟。成本上,工具定义每轮都随请求发送,执行结果也计入上下文,工具越多、返回越长,单轮 token 消耗越高,长会话要定期裁剪历史。