登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

Responses API 的 tool_choice 怎么强制工具调用:required、指定工具与回退验收

来源:17golang原创

时间:2026-08-26 05:48:46 484浏览 收藏

做一个能查订单状态的 AI 助手时,最容易被忽略的不是工具函数怎么写,而是模型到底有没有真的调用它。把 tool_choice 留在默认的 auto,模型可能直接用自然语言回答;改成 required 后,又要处理“调用了哪个工具、参数能不能解析、工具失败后怎么给用户可用结果”这几层验收。

要点速览
  • auto 允许模型自行选择回答或调用工具,required 则要求至少发起一次工具调用。
  • 需要锁定某个自定义工具时,使用带 typename 的对象,比只写 required 更明确。
  • 验收不能只看文本里有没有“已查询”,要检查响应项类型、工具名、call_id、参数 JSON 和工具输出是否一一对应。
  • 强制调用解决的是路由确定性,不会替业务保证工具成功;超时、空结果和参数校验失败仍要有明确回退。
Responses API 的 auto、required 和指定工具三种工具路由选择关系
先根据任务边界选择工具路由模式,再对返回的工具调用项做验收。

先把三种 tool_choice 语义分开

Responses API 的 tool_choice 可以理解为一层“调用意图约束”。它不负责执行你的函数,也不替你判断数据库是否可用,只影响模型能不能跳过工具,以及在允许多个工具时如何收窄选择范围。

写法模型可以做什么适合场景
auto自行决定直接回答,或调用一个或多个可用工具工具只是补充信息,简单问候不必查数据
required必须调用一个或多个工具价格、库存、订单状态等必须以系统数据为准
{type: "function", name: "get_order_status"}强制选择指定的自定义工具当前回合只能走一个确定的业务查询入口

这里不要把 required 当成“保证答案正确”。它只把模型从“可以不调用”推进到“必须产生工具调用”,工具实现仍然需要自己做权限、参数和错误处理。

用最小请求锁定订单查询工具

假设服务端暴露一个 get_order_status 工具,输入只有订单号。请求可以先保持紧凑,避免把多个无关工具混在验证样本里:

const response = await client.responses.create({
  model: "gpt-5",
  input: "帮我查询订单 A-20260826-001 的配送状态",
  tools: [{
    type: "function",
    name: "get_order_status",
    description: "查询订单当前配送状态",
    parameters: {
      type: "object",
      properties: {
        order_id: { type: "string" }
      },
      required: ["order_id"],
      additionalProperties: false
    },
    strict: true
  }],
  tool_choice: {
    type: "function",
    name: "get_order_status"
  }
});

示例中的工具名、参数名和订单号只是本文的测试数据。生产代码里还要由服务端重新确认当前用户是否有权查看这个订单,不能把模型生成的 order_id 直接当作授权凭证。

把调用阶段拆成四个可检查的状态

一段稳定的工具链至少要经过“模型请求、工具调用、工具输出、最终回答”四个状态。模型返回工具调用项后,服务端先解析并校验参数,再执行真实函数;只有拿到工具结果,才把对应输出继续交给模型生成自然语言答复。

const toolCall = response.output.find(
  item => item.type === "function_call" && item.name === "get_order_status"
);

if (!toolCall) {
  throw new Error("required tool call missing");
}

const args = JSON.parse(toolCall.arguments);
if (typeof args.order_id !== "string" || !args.order_id) {
  throw new Error("invalid order_id");
}

const result = await getOrderStatusForUser(args.order_id, user.id);
const followup = await client.responses.create({
  model: "gpt-5",
  previous_response_id: response.id,
  input: [{
    type: "function_call_output",
    call_id: toolCall.call_id,
    output: JSON.stringify(result)
  }]
});

关键检查点是 call_id。它把本次工具调用和后续的 function_call_output 配对起来;不要用数组下标替代,也不要把上一轮调用的 ID 缓存在全局变量里。

Responses API 工具调用从 function_call 到 function_call_output 再到最终答复的验收链路
每一步都留下可核对的响应项和关联 ID,工具失败时才有足够证据进入回退分支。

required 和指定工具应该怎么选

工具只是补充信息时用 auto

例如用户问“你能做什么”,或者问题本身不需要订单数据,auto 让模型直接回答更自然。它的代价是不能把“必须查实时数据”的业务要求寄托在模型自行判断上。

必须查系统数据时用 required

当一个回合允许查询库存、订单和物流多个工具,但禁止模型凭空编造结果,可以用 required。此时仍要检查实际返回的工具名,因为“调用了某个工具”不等于“调用了你期望的那个工具”。

单一业务入口时指定工具名

如果当前页面就是订单详情,只允许调用 get_order_status,直接指定工具更容易测试,也能减少模型在多个相似工具间误选的机会。等业务任务真的允许多个并行查询,再考虑放宽为 required

失败回退要和“没有调用”分开处理

工程上最麻烦的情况通常有三种:返回项里没有目标工具、参数 JSON 无法解析、工具执行后返回超时或业务错误。它们不能全部归类成“模型没听话”,因为后两种发生在模型已经正确发起调用之后。

现象应记录的证据建议回退
没有 function_calltool_choice、response.id、完整 output 类型停止拼接业务结论,返回稍后重试或转人工提示
参数解析/校验失败工具名、原始 arguments、校验错误不要执行函数,要求模型按同一 call_id 修正或终止本次请求
工具超时/业务失败call_id、超时毫秒数、后端错误码明确说明实时查询失败,不用旧缓存冒充当前状态

特别是订单、支付、库存这类数据,宁可返回“暂时查不到”,也不要让模型依据工具调用失败前的上下文继续生成确定语气的结论。

上线前做一组最小验收

  1. 用正常订单号请求,确认返回项中出现目标工具,并且参数只有允许的字段。
  2. 用不存在或无权限订单号请求,确认后端拒绝逻辑先于自然语言生成。
  3. 模拟工具超时,确认页面显示查询失败而不是旧状态或猜测状态。
  4. 记录 response.idcall_id、工具名、参数校验结果和后端结果,方便按一次会话复查。

验收时可以把响应项序列化进结构化日志,但要对订单号、用户标识和工具输出做脱敏。日志的目标是复现路由和状态,不是复制整份业务数据。

相关问题

required 能保证一定调用指定工具吗?

不能。它只要求至少调用工具;如果要锁定具体自定义工具,应使用带工具类型和名称的选择对象,并在响应里再次检查工具名。

为什么工具调用成功了,最终回答仍然不可信?

工具调用只说明模型生成了调用项并由服务端执行。权限、数据新鲜度、后端错误和输出内容校验仍然属于应用代码的责任。

能不能只检查 response.output_text

不建议。工具调用阶段的关键信息在结构化输出项里,单看文本可能漏掉工具缺失、参数异常或工具失败等情况。

把 tool_choice 当成路由约束,而不是业务保证

auto 适合可选工具,required 适合必须查数据但允许多个入口的回合,指定工具对象适合单一业务路径。真正上线时,再把响应项、参数、权限、工具结果和回退提示串成一条可观察链路,才能确认用户看到的状态确实来自一次有效查询。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>