在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

工具调用

工具调用(function calling)让语言模型通过应用使用外部代码。应用发送会话和工具 schema,模型可以返回结构化工具请求,指定名称与参数。应用执行函数、把结果加入消息,再调用模型取得后续回答。本课使用由客户端执行的工具。

可以把模型看作通过信件协作的顾问。应用寄去问题、所需历史和服务目录,模型回一份答案或工单。收到 get_weather 工单后,仍需应用去执行,再把结果寄回。产生调用描述与执行函数是两步。

工具调用如何工作

模型、应用、工具三方中,应用连接两端:通过 API 联系模型,通过执行器调用函数,例如 def get_weather(city): ...。本例没有模型直接访问本地函数的通道。提供者托管的服务端工具属于另一种安排。

循环如下,代码为教学伪代码:

def ask(question: str) -> str:
    messages = [{"role": "user", "content": question}]
    while True:
        resp = claude.create(messages=messages, tools=TOOL_SCHEMAS,
                             tool_choice=CHOICE)
        messages.append(assistant(resp.content))
        if resp.stop_reason != "tool_use":
            return text_of(resp)
        results = []
        for call in tool_uses_of(resp):
            try:
                results.append(TOOLS[call.name](**call.input))
            except Exception as e:
                results.append(f"error: {e}")
        messages.append(tool_results(results))

TOOL_SCHEMAS 是说明,不是实现。它包含名称、自然语言描述、参数约束。模型结合描述、schema 和其他上下文选择工具,因此描述应说明用途与限制。

本例的 stop_reason: "end_turn" 表示返回答案,"tool_use" 表示该响应包含待执行请求。这个客户端工具流程在此结束模型响应,后续由应用执行。真实实现还需区分 max_tokens 等其他停止原因,不能把所有非 tool_use 都当完整成功。

TOOLS[call.name] 按名称查找实现。新增工具可以扩展 schema 与处理器表,不必给通用循环增加同名分支,但仍需实现、验证和权限规则,不只是写一行就得到完整能力。

工具结果放在 tool_result 块中,经 user-role 消息发送。它是外界提供的输入,不是模型已经执行的证明。下一请求携带用户问题、assistant 的 tool_use 和匹配结果。本课的 Messages API 由客户端管理历史;其他 API 或宿主可以代管会话,不是 HTTP 本身禁止保存状态。

ReAct 循环 在这个机制上组织 Thought → Action → Observation;本课展开其中的工具分发。

工具调用逐步演示

默认问题为 What's the weather in Tokyo right now?,提供 get_weather(city)。天气来自固定表,不是实时天气。

  1. 准备。 messages 有一条天气问题,TOOL_SCHEMAS 有 get_weather 定义。
  2. 请求 1。 组装一条消息和工具定义。
  3. 往返 1。 录制模型选择用工具获取天气;训练知识不足以提供当前天气。
  4. 返回工单。 内容摘录为 {"name": "get_weather", "input": {"city": "Tokyo"}},停止原因 tool_use。这里只省略了完整块的 type、id 等字段;尚无函数执行。
  5. 保存请求。 assistant 的 tool_use 加入历史。
  6. 检查停止原因。 if resp.stop_reason != "tool_use" 为假,不提前返回,继续到工具分发。
  7. 解析。 应用提取 name、input,得到 get_weather(city="Tokyo")。应在执行前验证和授权。
  8. 执行。 应用进程调用函数,这一步不需要模型继续运行。
  9. 返回工具结果。 固定表返回 18°C · rain。
  10. 加入结果。 user-role 的 tool_result 对应请求 ID。历史现在是问题、工单、结果。
  11. 请求 2。 三条消息加工具定义一起发送。
  12. 往返 2。 同一端点、同一结构,载荷比此前大。
  13. 返回答案。 录制回答称东京现在 18°C、有雨,并建议带伞,stop_reason: "end_turn"。温度来自函数结果,不是模型回忆。
  14. 保存并结束。 条件为真,执行 return text_of(resp)。
  15. 计数。 本次一项工具工作需要 2 次模型 API 调用、1 次工具执行。

为什么本例需要两次往返

这个客户端工具协议在 tool_use 响应后把控制权交回应用。应用完成工具后,再提交结果,让模型继续。因此本例有两次模型调用加一次工具耗时,按顺序发生;不是所有 HTTP 协议或托管工具都受同一种流程限制。

每次请求包含所保留的历史与 schema,增加输入量,提示缓存可以降低重复部分的成本。错误恢复还会增加往返:服务只认 Springfield, Missouri,第一次却用 Springfield,本例因而从 2 次模型调用增至 3 次。

工具错误以 is_error: true 返回,也能成为模型的输入。录制错误场景里,错误文本列出合法名称,下一次请求原样采用 Springfield, Missouri。这说明本次恢复如何发生,不保证模型总能修正错误。

边界情况

  • 不需要工具。 问 What does HTTP stand for? 并附天气工具,auto 的录制响应直接 end_turn:1 次 API、0 次工具。提供工具不等于强制使用。
  • 工具抛异常。 应捕获并返回经过处理的 tool_result,保留 is_error: true 与对应 ID。避免把敏感堆栈原样暴露,也不要把失败吞掉。本例错误文本帮助模型改用正确键。
  • UI 的 tool_choice: "required"。 这是演示的统一标签,Anthropic 原生“必须使用任一工具”写作 {"type":"any"},不是这个字符串。强制选择在无需天气的 HTTP 问题上也产生工具请求,演示了一次无用执行。若每轮都强制,每轮都只能再调用工具,模型无法直接回答;本演示第一轮后改回 auto。依赖强制前先确认模型:Claude 最新模型(Opus 5.5、Sonnet 5.5、Fable 5.1)对 {"type":"any"} 与 {"type":"tool"} 返回 400 错误,Opus 5、Fable 5 和 OpenAI 的 "required" 仍会强制。在这些新模型上,用 auto 加调用指令,需要合规输入时加 strict: true。本课录制的是 claude-opus-5-5,所以强制轮是模拟的:录制脚本在提示词里告诉模型不允许纯文本回答。这比真实强制弱,三份录制样本中有一份仍直接用文本回答。按业务目的选择强制任意工具或指定工具,而非总是打开。
  • 批量工具请求。 东京与旧金山问题的录制响应一次返回两个 tool_use。应用执行两次,再把两个按 id 对应的 tool_result 放进同一条 user 消息,只需一次额外模型往返。批量请求不保证执行器并行;示例 for 循环按顺序调用。
  • 不存在的名称或无效参数。 运行时必须验证,拒绝无效调用并报告错误,不应直接执行模型给出的任意内容。
  • 无限循环。 while True 便于解释,生产应限制轮数、时间和预算,并明确报告未完成。

常见错误

  • 认为 API 已执行本地函数。 模型只提出请求,应用还要验证、授权、分发。
  • 丢掉请求历史或 ID。 后续结果必须对应 assistant 的 tool_use,顺序与 ID 要满足 API 契约。只发无对应请求的结果会出错。
  • 以为上轮由模型自行记住。 本客户端管理的流程应传回所需历史;只提供孤立结果,不提供问题,就缺少任务上下文。
  • 结果角色错误。 本课 Anthropic Messages 用 user 消息承载 tool_result。不同 API 用不同结构,不应混用字段。
  • 描述没有参数约束。 “获取天气”没有解释城市必须匹配服务列表。写清精确键,如 Springfield, Missouri,或在 schema 使用合法值 enum,可以避免本例模糊输入。

模型的简化

模型选择、参数和最终回答来自仓库记录的 claude-opus-5-5 运行,每个场景选择一份原文记录。required 格用提示词约束模拟强制,因为该模型拒绝强制 tool_choice。播放不调用实时模型。get_weather 从三城市表读取,但确实在本地执行,画面结果包括错误都由函数产生。

代码是伪代码,辅助函数必须保留调用 ID 和错误标记;完整实现还需处理其他 stop_reason、校验、授权和预算。CHOICE 占位写法省略了演示第一轮后 required → auto 的切换。多个工具类型、流式处理和提示缓存未展开。本课展示客户端工具的响应停止、结构化请求、执行、结果回传与历史重发,不能代表所有提供者接口的唯一形式。