Skip to content

工具调用

Anthropic Messages 接口的工具调用协议与 OpenAI tools 协议不同

维度OpenAI Chat CompletionsAnthropic Messages
工具定义tools[].function.{name, description, parameters}tools[].{name, description, input_schema}
模型调用工具message.tool_calls[].function.{name, arguments} (字符串)content[].{type:"tool_use", id, name, input} (对象)
工具结果消息role: "tool", tool_call_idrole: "user", content[].{type:"tool_result", tool_use_id, content}
工具选择tool_choice: "auto" / "none" / {name}tool_choice: {type:"auto"/"any"/"tool", name?}

推荐:使用流式调用工具

本网关的流式响应对 tool_use 协议完整支持,所有 SSE 事件(含 content_block_start / input_json_delta / content_block_stop / message_delta / message_stop)齐全。

非流式调用 tool_use 当前存在已知问题:响应 content 数组可能为空(usage 仍正确)。如必须用非流式 + 工具调用,请通过下方邮箱反馈。

调用工具时建议优先使用 stream: true

定义工具

json
{
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "stream": true,
  "tools": [
    {
      "name": "get_weather",
      "description": "Get the current weather for a city.",
      "input_schema": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string",
            "description": "City name in English"
          }
        },
        "required": ["city"]
      }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": "What is the weather in Tokyo right now?"
    }
  ]
}

字段对比 OpenAI:

  • name / description
  • parameters → 改名为 input_schema
  • 没有外层 function 包装

tool_choice 策略

取值含义
不传(默认)模型自行决定是否调用工具
{"type": "auto"}同上
{"type": "any"}必须调用任意一个工具(不调用文本就不输出)
{"type": "tool", "name": "get_weather"}强制调用指定工具
{"type": "none"}禁用工具

模型决定调用工具时的流式响应

text
event: message_start
data: {"type":"message_start","message":{"id":"msg_xxx",...,"usage":{"input_tokens":23}}}

event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"tool_use","id":"toolu_xxx","name":"get_weather","input":{}}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"{\""}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"city\":\"Toky"}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"input_json_delta","partial_json":"o\"}"}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"output_tokens":6}}

event: message_stop
data: {"type":"message_stop"}

客户端组装出:

json
{
  "id": "toolu_xxx",
  "name": "get_weather",
  "input": { "city": "Tokyo" }
}

注意 partial_json字符级别增量,需要按顺序拼接成完整 JSON 字符串后再 parse。

回填工具结果

执行业务函数(真的去查询天气)后,把结果作为 user 消息追加:

json
{
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "stream": true,
  "tools": [ ...同上... ],
  "messages": [
    { "role": "user", "content": "What is the weather in Tokyo right now?" },
    {
      "role": "assistant",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_xxx",
          "name": "get_weather",
          "input": { "city": "Tokyo" }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "tool_result",
          "tool_use_id": "toolu_xxx",
          "content": "{\"temp_c\":18,\"condition\":\"sunny\"}"
        }
      ]
    }
  ]
}

关键点:

  • 工具调用前后整段对话历史都要带回(模型无状态)。
  • assistant 的 content 必须包含完整的 tool_use 块(id 要一致)。
  • 工具结果用 role: "user",type 是 tool_resulttool_use_id 必须与上一步 tool_use.id 完全相同。
  • 多个工具结果可以放在同一个 user 消息的 content 数组里。

实践建议

  • 工具描述要简明:模型靠 descriptioninput_schema 决定何时调用。
  • 不要在 input_schema 里塞业务密钥或内部 ID,会随请求出网。
  • 多轮工具调用时,每次 tool_use 都按顺序回填对应 tool_use_id,遗漏会让上下文丢失。
  • 默认建议不传 tool_choice(auto),强制选工具仅在确实知道必须走某工具时使用。
  • 流式响应中,input 是通过多个 input_json_delta 增量传输的,不要在第一个 content_block_start 时就 parse input(那时候它是空对象 {})。