注意
要了解“zero data retention”(零数据保留),即 ZDR 如何适用于此功能,请参阅 API 与数据保留。
本页逐步演示一个启用思考的完整两轮 tool use(工具使用)往返流程:Claude 进行思考、请求工具调用、接收结果并完成回答,且在每一步都正确处理 thinking blocks(思考块)。完整规则位于思考页面的思考与工具使用和保留思考块部分;本页展示这些规则在可运行代码中的应用。
本演示所应用的规则
每个链接都指向思考页面上的完整说明:
- 在手动模式下将工具选择限制为
auto或none:在手动扩展思考(thinking: {type: "enabled"})下,强制工具使用的tool_choice选项会返回错误。自适应思考支持强制工具使用,但 Claude Opus 5.5、Claude Sonnet 5.5、Claude Fable 5.1 和 Claude Mythos 5.1 除外,这些模型会返回 400 错误。在接受强制工具使用的情况下,它会跳过思考:响应以工具调用开始。 - 每个助手轮次保持一种思考配置:一个工具使用循环是一个助手轮次,因此只能在轮次之间更改配置。
- 完整且不加修改地传回思考块:当您返回工具结果时,助手消息中的思考块必须随之一起传回。
- 按接收到的原样回传助手消息:重建消息或过滤掉
redacted_thinking块会触发 400 错误。
示例使用自适应思考;在仅支持扩展思考的模型上,请替换为 thinking: {type: "enabled", budget_tokens: N}。往返规则完全相同。
逐步演示两轮工具使用往返流程
该示例定义了一个 get_weather 工具,让 Claude 思考并请求工具调用,然后返回工具结果,同时按接收到的原样回传助手轮次(包括思考块)。
-
发起第一个请求并提供可用工具
发送一个启用自适应思考并定义了工具的请求。除了
thinking参数之外,这是一个标准的工具使用请求:cURL
curl https://api.anthropic.com/v1/messages \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -d '{ "model": "claude-opus-5-5", "max_tokens": 16000, "thinking": {"type": "adaptive"}, "tools": [{ "name": "get_weather", "description": "Get current weather for a location", "input_schema": { "type": "object", "properties": { "location": {"type": "string", "description": "City name"} }, "required": ["location"] } }], "messages": [{"role": "user", "content": "What is the weather in Paris?"}] }'CLI
ant messages create <<'YAML' model: claude-opus-5-5 max_tokens: 16000 thinking: type: adaptive tools: - name: get_weather description: Get current weather for a location input_schema: type: object properties: location: type: string description: City name required: - location messages: - role: user content: "What's the weather in Paris?" YAMLPython
client = anthropic.Anthropic() weather_tool = { "name": "get_weather", "description": "Get current weather for a location", "input_schema": { "type": "object", "properties": {"location": {"type": "string", "description": "City name"}}, "required": ["location"], }, } # 第一次请求:Claude 返回思考内容和工具请求 response = client.messages.create( model="claude-opus-5-5", max_tokens=16000, thinking={"type": "adaptive"}, tools=[weather_tool], messages=[{"role": "user", "content": "What's the weather in Paris?"}], ) print(response)TypeScript
const client = new Anthropic(); const weatherTool: Anthropic.Tool = { name: "get_weather", description: "Get current weather for a location", input_schema: { type: "object", properties: { location: { type: "string", description: "City name" } }, required: ["location"] } }; // 第一个请求:Claude 返回思考内容和工具请求 const response = await client.messages.create({ model: "claude-opus-5-5", max_tokens: 16000, thinking: { type: "adaptive" }, tools: [weatherTool], messages: [{ role: "user", content: "What's the weather in Paris?" }] }); console.log(response);C#
AnthropicClient client = new(); var weatherTool = new ToolUnion(new Tool() { Name = "get_weather", Description = "Get current weather for a location", InputSchema = new InputSchema() { Properties = new Dictionary<string, JsonElement> { ["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "City name" }), }, Required = ["location"], }, }); var parameters = new MessageCreateParams { Model = Model.ClaudeOpus5_5, MaxTokens = 16000, Thinking = new ThinkingConfigAdaptive(), Tools = [weatherTool], Messages = [new UserMessageParam { Content = "What's the weather in Paris?" }] }; var message = await client.Messages.Create(parameters); Console.WriteLine(message);Go
client := anthropic.NewClient() weatherTool := anthropic.ToolUnionParam{ OfTool: &anthropic.ToolParam{ Name: "get_weather", Description: anthropic.String("Get current weather for a location"), InputSchema: anthropic.ToolInputSchemaParam{ Properties: map[string]any{ "location": map[string]any{ "type": "string", "description": "City name", }, }, Required: []string{"location"}, }, }, } response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ Model: anthropic.ModelClaudeOpus5_5, MaxTokens: 16000, Thinking: anthropic.ThinkingConfigParamUnion{ OfAdaptive: &anthropic.ThinkingConfigAdaptiveParam{}, }, Tools: []anthropic.ToolUnionParam{weatherTool}, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("What's the weather in Paris?")), }, }) if err != nil { log.Fatal(err) } fmt.Println(response)Java
import com.anthropic.models.messages.ThinkingConfigAdaptive; // ... AnthropicClient client = AnthropicOkHttpClient.fromEnv(); MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_OPUS_5_5) .maxTokens(16000L) .thinking(ThinkingConfigAdaptive.builder().build()) .addTool(Tool.builder() .name("get_weather") .description("Get current weather for a location") .inputSchema(Tool.InputSchema.builder() .properties(JsonValue.from(Map.of( "location", Map.of("type", "string", "description", "City name") ))) .required(List.of("location")) .build()) .build()) .addUserMessage("What's the weather in Paris?") .build(); Message response = client.messages().create(params); IO.println(response);PHP
$client = new Client(); $weatherTool = [ 'name' => 'get_weather', 'description' => 'Get current weather for a location', 'input_schema' => [ 'type' => 'object', 'properties' => [ 'location' => ['type' => 'string', 'description' => 'City name'] ], 'required' => ['location'] ] ]; $message = $client->messages->create( maxTokens: 16000, messages: [ ['role' => 'user', 'content' => "What's the weather in Paris?"] ], model: Model::CLAUDE_OPUS_5_5, thinking: ['type' => 'adaptive'], tools: [$weatherTool], ); echo $message;Ruby
client = Anthropic::Client.new weather_tool = { name: "get_weather", description: "Get current weather for a location", input_schema: { type: "object", properties: { location: { type: "string", description: "City name" } }, required: ["location"] } } message = client.messages.create( model: Anthropic::Model::CLAUDE_OPUS_5_5, max_tokens: 16000, thinking: { type: "adaptive" }, tools: [weather_tool], messages: [ { role: "user", content: "What's the weather in Paris?" } ] ) puts message -
捕获要回传的 content 数组
在包含思考的运行中,您应该会在响应内容中看到
thinking和tool_use块(对于较简单的请求,自适应模式可能会跳过思考块)。Claude 在工具调用之前写下的说明会以text块的形式返回,或者在会编写进度更新的模型上,以另一个thinking块的形式返回。请保持此 content 数组完整:下一步会原封不动地将其发回。注意
要看到类似此输出的思考文本,请在请求中添加
display: "summarized"。在 display 默认为 omitted 的模型上(包括 Claude Opus 5.5),thinking字段否则会以空字符串返回,仅填充signature。无论哪种情况,都请原样回传 content 数组;请参阅控制思考显示。Output
{ "content": [ { "type": "thinking", "thinking": "The user wants to know the current weather in Paris. I have access to a function `get_weather`...", "signature": "BDaL4VrbR2Oj0hO4XpJxT28J5T...." }, { "type": "tool_use", "id": "toolu_01CswdEQBMshySk6Y9DFKrfq", "name": "get_weather", "input": { "location": "Paris" } } ] } -
返回工具结果,并原样回传助手轮次
在您这一侧运行工具,然后发送第二个请求,向对话追加两条消息。第一条是按接收到的原样回传的助手内容,因此思考块与
tool_use块一起保持不变。第二条是携带tool_result的用户消息。每个示例都是一个独立的脚本:它重复第一个请求,然后立即使用刚刚收到的响应发送后续请求。
cURL
此工作流需要的逻辑超出了单个 shell 命令所能实现的范围。请使用 Claude SDK 运行它。
CLI
此工作流需要的逻辑超出了单个 shell 命令所能实现的范围。请使用 Claude SDK 运行它。
Python
client = anthropic.Anthropic() weather_tool = { "name": "get_weather", "description": "Get current weather for a location", "input_schema": { "type": "object", "properties": {"location": {"type": "string", "description": "City name"}}, "required": ["location"], }, } response = client.messages.create( model="claude-opus-5-5", max_tokens=16000, thinking={"type": "adaptive"}, tools=[weather_tool], messages=[{"role": "user", "content": "What's the weather in Paris?"}], ) # 提取 tool_use 块以获取其 ID,用于 tool_result tool_use_block = next(block for block in response.content if block.type == "tool_use") # 您实际调用天气 API 的代码应放在此处 # 假设这是天气 API 返回的结果 weather_data = {"temperature": 88} # 第二个请求:包含助手轮次和工具结果 continuation = client.messages.create( model="claude-opus-5-5", max_tokens=16000, thinking={"type": "adaptive"}, tools=[weather_tool], messages=[ {"role": "user", "content": "What's the weather in Paris?"}, # 按原样回传 assistant 内容。当存在 thinking # 块时,它必须与 tool_use 块一同提供。 {"role": "assistant", "content": response.content}, { "role": "user", "content": [ { "type": "tool_result", "tool_use_id": tool_use_block.id, "content": f"Current temperature: {weather_data['temperature']}°F", } ], }, ], ) print(continuation)TypeScript
const client = new Anthropic(); const weatherTool: Anthropic.Tool = { name: "get_weather", description: "Get current weather for a location", input_schema: { type: "object", properties: { location: { type: "string", description: "City name" } }, required: ["location"] } }; const response = await client.messages.create({ model: "claude-opus-5-5", max_tokens: 16000, thinking: { type: "adaptive" }, tools: [weatherTool], messages: [{ role: "user", content: "What's the weather in Paris?" }] }); // 提取 tool_use 块以获取其 ID,用于构造 tool_result const toolUseBlock = response.content.find((block) => block.type === "tool_use"); // 此处应放置您实际的天气 API 调用 // 假设这是天气 API 返回的内容 const weatherData = { temperature: 88 }; if (toolUseBlock) { // 第二个请求:包含 assistant 轮次和工具结果 const continuation = await client.messages.create({ model: "claude-opus-5-5", max_tokens: 16000, thinking: { type: "adaptive" }, tools: [weatherTool], messages: [ { role: "user", content: "What's the weather in Paris?" }, // 原样回传收到的 assistant 内容。当存在 thinking // 块时,它必须与 tool_use 块一同提供。 { role: "assistant", content: response.content }, { role: "user", content: [ { type: "tool_result" as const, tool_use_id: toolUseBlock.id, content: `Current temperature: ${weatherData.temperature}°F` } ] } ] }); console.log(continuation); }C#
AnthropicClient client = new(); var weatherTool = new ToolUnion(new Tool() { Name = "get_weather", Description = "Get current weather for a location", InputSchema = new InputSchema() { Properties = new Dictionary<string, JsonElement> { ["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "City name" }), }, Required = ["location"], }, }); var parameters = new MessageCreateParams { Model = Model.ClaudeOpus5_5, MaxTokens = 16000, Thinking = new ThinkingConfigAdaptive(), Tools = [weatherTool], Messages = [new UserMessageParam { Content = "What's the weather in Paris?" }] }; var response = await client.Messages.Create(parameters); // 提取 tool_use 块以获取其 ID,用于构建工具结果 ToolUseBlock? toolUseBlock = null; foreach (var block in response.Content) { if (block.TryPickToolUse(out var toolUse)) { toolUseBlock = toolUse; break; } } var weatherData = new { temperature = 88 }; // 使用工具结果构建后续请求 var continuationParams = new MessageCreateParams { Model = Model.ClaudeOpus5_5, MaxTokens = 16000, Thinking = new ThinkingConfigAdaptive(), Tools = [weatherTool], Messages = [ new UserMessageParam { Content = "What's the weather in Paris?" }, // response.Content 包含思考块;必须将它们原样传回 new AssistantMessageParam { Content = response.Content.Select(block => new ContentBlockParam(block.Json)).ToList() }, new UserMessageParam { Content = new List<ContentBlockParam> { new ContentBlockParam(new ToolResultBlockParam() { ToolUseID = toolUseBlock?.ID ?? "", Content = $"Current temperature: {weatherData.temperature}°F" }) } } ] }; var continuation = await client.Messages.Create(continuationParams); Console.WriteLine(continuation);Go
client := anthropic.NewClient() weatherTool := anthropic.ToolUnionParam{ OfTool: &anthropic.ToolParam{ Name: "get_weather", Description: anthropic.String("Get current weather for a location"), InputSchema: anthropic.ToolInputSchemaParam{ Properties: map[string]any{ "location": map[string]any{ "type": "string", "description": "City name", }, }, Required: []string{"location"}, }, }, } response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ Model: anthropic.ModelClaudeOpus5_5, MaxTokens: 16000, Thinking: anthropic.ThinkingConfigParamUnion{ OfAdaptive: &anthropic.ThinkingConfigAdaptiveParam{}, }, Tools: []anthropic.ToolUnionParam{weatherTool}, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("What's the weather in Paris?")), }, }) if err != nil { log.Fatal(err) } var toolUseBlock anthropic.ToolUseBlock for _, block := range response.Content { if v, ok := block.AsAny().(anthropic.ToolUseBlock); ok { toolUseBlock = v break } } weatherData := map[string]int{"temperature": 88} continuation, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ Model: anthropic.ModelClaudeOpus5_5, MaxTokens: 16000, Thinking: anthropic.ThinkingConfigParamUnion{ OfAdaptive: &anthropic.ThinkingConfigAdaptiveParam{}, }, Tools: []anthropic.ToolUnionParam{weatherTool}, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("What's the weather in Paris?")), response.ToParam(), anthropic.NewUserMessage( anthropic.NewToolResultBlock(toolUseBlock.ID, fmt.Sprintf("Current temperature: %d°F", weatherData["temperature"]), false), ), }, }) if err != nil { log.Fatal(err) } fmt.Println(continuation)Java
import com.anthropic.models.messages.ThinkingConfigAdaptive; // ... void main() { AnthropicClient client = AnthropicOkHttpClient.fromEnv(); Tool weatherTool = Tool.builder() .name("get_weather") .description("Get current weather for a location") .inputSchema(Tool.InputSchema.builder() .properties(JsonValue.from(Map.of( "location", Map.of("type", "string", "description", "City name") ))) .required(List.of("location")) .build()) .build(); MessageCreateParams initialParams = MessageCreateParams.builder() .model(Model.CLAUDE_OPUS_5_5) .maxTokens(16000L) .thinking(ThinkingConfigAdaptive.builder().build()) .addTool(weatherTool) .addUserMessage("What's the weather in Paris?") .build(); Message response = client.messages().create(initialParams); ToolUseBlock toolUseBlock = null; for (var block : response.content()) { if (block.toolUse().isPresent()) { toolUseBlock = block.toolUse().get(); break; } } int temperature = 88; // 第二次请求:原样回传收到的 assistant 轮次,然后附上工具结果 MessageCreateParams continuationParams = MessageCreateParams.builder() .model(Model.CLAUDE_OPUS_5_5) .maxTokens(16000L) .thinking(ThinkingConfigAdaptive.builder().build()) .addTool(weatherTool) .addUserMessage("What's the weather in Paris?") .addMessage(response) .addUserMessageOfContentBlockParams(List.of( ContentBlockParam.ofToolResult( ToolResultBlockParam.builder() .toolUseId(toolUseBlock.id()) .content("Current temperature: " + temperature + "°F") .build() ) )) .build(); Message continuation = client.messages().create(continuationParams); IO.println(continuation); }PHP
$client = new Client(); $weatherTool = [ 'name' => 'get_weather', 'description' => 'Get current weather for a location', 'input_schema' => [ 'type' => 'object', 'properties' => [ 'location' => [ 'type' => 'string', 'description' => 'City name' ] ], 'required' => ['location'] ] ]; $response = $client->messages->create( maxTokens: 16000, messages: [ ['role' => 'user', 'content' => "What's the weather in Paris?"] ], model: 'claude-opus-5-5', thinking: ['type' => 'adaptive'], tools: [$weatherTool], ); $toolUseBlock = null; foreach ($response->content as $block) { if ($block->type === 'tool_use') { $toolUseBlock = $block; break; } } $weatherData = ['temperature' => 88]; $continuation = $client->messages->create( maxTokens: 16000, messages: [ ['role' => 'user', 'content' => "What's the weather in Paris?"], ['role' => 'assistant', 'content' => $response->content], ['role' => 'user', 'content' => [ [ 'type' => 'tool_result', 'tool_use_id' => $toolUseBlock->id, 'content' => "Current temperature: {$weatherData['temperature']}°F" ] ]] ], model: 'claude-opus-5-5', thinking: ['type' => 'adaptive'], tools: [$weatherTool], ); echo $continuation;Ruby
client = Anthropic::Client.new weather_tool = { name: "get_weather", description: "Get current weather for a location", input_schema: { type: "object", properties: { location: { type: "string", description: "City name" } }, required: ["location"] } } response = client.messages.create( model: Anthropic::Model::CLAUDE_OPUS_5_5, max_tokens: 16000, thinking: { type: "adaptive" }, tools: [weather_tool], messages: [ { role: "user", content: "What's the weather in Paris?" } ] ) tool_use_block = response.content.find { |block| block.type == :tool_use } raise "No tool_use block found" unless tool_use_block weather_data = { temperature: 88 } continuation = client.messages.create( model: Anthropic::Model::CLAUDE_OPUS_5_5, max_tokens: 16000, thinking: { type: "adaptive" }, tools: [weather_tool], messages: [ { role: "user", content: "What's the weather in Paris?" }, { role: "assistant", content: response.content }, { role: "user", content: [ { type: "tool_result", tool_use_id: tool_use_block.id, content: "Current temperature: #{weather_data[:temperature]}°F" } ] } ] ) puts continuation -
读取最终响应
您应该会看到 Claude 以文本完成该轮次。由于 interleaved thinking(交错思考)在自适应模式下是自动的,因此续写内容也可能在最终文本之前以一个新的思考块开头,详见交错思考:
Output
{ "content": [ { "type": "text", "text": "Currently in Paris, the temperature is 88°F (31°C)" } ] }
交错思考如何改变流程
交错思考让 Claude 能够在工具调用之间进行思考,在对每个工具结果采取行动之前先对其进行推理。其概念和各模型的可用性在思考页面的交错思考部分有介绍;交错改变的是思考块出现的位置,而不是工具调用能否链式进行。以下对比展示了交错思考在双工具工作流中带来的变化:
不使用交错思考的工具使用
在没有交错思考的情况下,Claude 在助手轮次开始时思考一次。工具结果之后的后续响应会继续进行,而不会产生新的思考块。
User: "What's the total revenue if we sold 150 units at $50 each,
and how does this compare to our average monthly revenue?"
Response 1: [thinking] "I need to calculate 150 * $50, then check the database..."
[tool_use: calculator] { "expression": "150 * 50" }
↓ tool result: "7500"
Response 2: [tool_use: database_query] { "query": "SELECT AVG(revenue)..." }
↑ no thinking block
↓ tool result: "5200"
Response 3: [text] "The total revenue is $7,500, which is 44% above your
average monthly revenue of $5,200."
↑ no thinking block
使用交错思考的工具使用
启用交错思考后,Claude 可以在收到每个工具结果后进行思考,从而能够在继续之前对中间结果进行推理。
User: "What's the total revenue if we sold 150 units at $50 each,
and how does this compare to our average monthly revenue?"
Response 1: [thinking] "I need to calculate 150 * $50 first..."
[tool_use: calculator] { "expression": "150 * 50" }
↓ tool result: "7500"
Response 2: [thinking] "Got $7,500. Now I should query the database to compare..."
[tool_use: database_query] { "query": "SELECT AVG(revenue)..." }
↑ thinking after receiving calculator result
↓ tool result: "5200"
Response 3: [thinking] "$7,500 vs $5,200 average - that's a 44% increase..."
[text] "The total revenue is $7,500, which is 44% above your
average monthly revenue of $5,200."
↑ thinking before final answer