工具调用
Anthropic Messages 接口的工具调用协议与 OpenAI tools 协议不同:
| 维度 | OpenAI Chat Completions | Anthropic 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_id | role: "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_result,tool_use_id必须与上一步tool_use.id完全相同。 - 多个工具结果可以放在同一个 user 消息的
content数组里。
实践建议
- 工具描述要简明:模型靠
description和input_schema决定何时调用。 - 不要在
input_schema里塞业务密钥或内部 ID,会随请求出网。 - 多轮工具调用时,每次
tool_use都按顺序回填对应tool_use_id,遗漏会让上下文丢失。 - 默认建议不传
tool_choice(auto),强制选工具仅在确实知道必须走某工具时使用。 - 流式响应中,
input是通过多个input_json_delta增量传输的,不要在第一个content_block_start时就 parseinput(那时候它是空对象{})。