도구 및 멀티턴 워크플로에서의 thinking

도구 및 멀티턴 워크플로에서의 thinking (Thinking in tool and multi-turn workflows)

이 페이지는 thinking을 켠 상태에서 완전한 2턴 도구 사용 왕복(round trip)을 단계별로 보여줘요: Claude가 생각하고, 도구 호출을 요청하고, 결과를 받고, 답을 끝내며, 매 단계에서 thinking 블록을 올바르게 처리해요. 전체 규칙은 Thinking 페이지의 도구 사용과 thinkingThinking 블록 보존하기에 있고, 이 페이지는 그 규칙을 실행 가능한 코드로 보여줘요.

출처: 문서

본문

이 기능에 zero data retention(ZDR)이 어떻게 적용되는지 배우려면 [API 및 데이터 보존](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention)을 보세요.

이 페이지는 thinking을 켠 상태에서 완전한 2턴 도구 사용 왕복(round trip)을 단계별로 보여줘요: Claude가 생각하고, 도구 호출을 요청하고, 결과를 받고, 답을 끝내며, 매 단계에서 thinking 블록을 올바르게 처리해요. 전체 규칙은 Thinking 페이지의 도구 사용과 thinkingThinking 블록 보존하기에 있고, 이 페이지는 그 규칙을 실행 가능한 코드로 보여줘요.

이 워크스루가 적용하는 규칙

각 링크는 Thinking 페이지의 전체 진술로 이어져요:

샘플은 적응형 thinking을 씁니다. 확장 thinking만 지원하는 모델에서는 thinking: {type: "enabled", budget_tokens: N}을 대신하세요. 왕복 규칙은 동일해요.

2턴 도구 사용 왕복 워크스루

예시는 get_weather 도구를 정의하고, Claude가 생각하고 도구 호출을 요청하게 한 뒤, thinking 블록을 포함해 받은 그대로의 어시스턴트 턴과 함께 도구 결과를 반환해요.

적응형 thinking을 켜고 도구를 정의한 요청을 보내요. `thinking` 파라미터를 제외하면 표준 [도구 사용](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview) 요청이에요:
<CodeGroup>
  ```bash CLI
  ant messages create --transform content <<'YAML'
  model: claude-opus-4-8
  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?"
  YAML
  ```

  ```python 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"],
      },
  }

  # First request - Claude responds with thinking and tool request
  response = client.messages.create(
      model="claude-opus-4-8",
      max_tokens=16000,
      thinking={"type": "adaptive"},
      tools=[weather_tool],
      messages=[{"role": "user", "content": "What's the weather in Paris?"}],
  )
  print(response)
  ```

  ```typescript 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"]
    }
  };

  // First request - Claude responds with thinking and tool request
  const response = await client.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 16000,
    thinking: {
      type: "adaptive"
    },
    tools: [weatherTool],
    messages: [{ role: "user", content: "What's the weather in Paris?" }]
  });
  console.log(response);
  ```

  ```csharp 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.ClaudeOpus4_8,
      MaxTokens = 16000,
      Thinking = new ThinkingConfigAdaptive(),
      Tools = [weatherTool],
      Messages = [new() { Role = Role.User, Content = "What's the weather in Paris?" }]
  };

  var message = await client.Messages.Create(parameters);
  Console.WriteLine(message);
  ```

  ```go 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.ModelClaudeOpus4_8,
  	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 Java
  import com.anthropic.models.messages.ThinkingConfigAdaptive;
  // ...
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_4_8)
          .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 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: 'claude-opus-4-8',
      thinking: ['type' => 'adaptive'],
      tools: [$weatherTool],
  );
  echo $message;
  ```

  ```ruby 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: "claude-opus-4-8",
    max_tokens: 16000,
    thinking: {
      type: "adaptive"
    },
    tools: [weather_tool],
    messages: [
      { role: "user", content: "What's the weather in Paris?" }
    ]
  )
  puts message
  ```
</CodeGroup>
Claude가 생각하기로 한 실행에서는 응답 content에 `thinking`, `text`, `tool_use` 블록이 보여요(더 단순한 요청에서는 적응형 모드가 thinking 블록을 건너뛸 수 있어요). 이 content 배열을 그대로 유지하세요: 다음 단계가 그것을 그대로 다시 보내요.
<Note>
  이 출력 같은 thinking 텍스트를 보려면 요청에 `display: "summarized"`를 추가하세요. claude-opus-4-8을 포함해 display가 omitted로 기본 설정된 모델에서는 그렇지 않으면 `thinking` 필드가 빈 문자열로 돌아오고 `signature`만 채워져요. 어느 쪽이든 content 배열을 그대로 다시 에코하세요. [Thinking 표시 제어](https://platform.claude.com/docs/en/build-with-claude/thinking#controlling-thinking-display)를 보세요.
</Note>

```json 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": "text",
      "text": "I can help you get the current weather information for Paris. Let me check that for you"
    },
    {
      "type": "tool_use",
      "id": "toolu_01CswdEQBMshySk6Y9DFKrfq",
      "name": "get_weather",
      "input": {
        "location": "Paris"
      }
    }
  ]
}
```
도구를 여러분 쪽에서 실행하고, 대화에 두 메시지를 덧붙이는 두 번째 요청을 보내요. 첫 번째는 받은 그대로 정확히 에코된 어시스턴트 content라서, thinking 블록이 `tool_use` 블록 옆에 그대로 남아요. 두 번째는 `tool_result`를 담은 사용자 메시지예요.
각 샘플은 자급자족 스크립트예요: 첫 요청을 반복하고, 방금 받은 응답을 사용해 즉시 후속 요청을 보내요.

<CodeGroup>
  ```bash CLI
  # First turn: write the assistant content array (thinking and tool_use
  # blocks, signatures intact) to a file. Routing model-generated text
  # through a file keeps it out of shell-expansion position later.
  ant messages create --transform content --format jsonl \
    > assistant_content.json <<'YAML'
  model: claude-opus-4-8
  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?
  YAML

  # Second turn: jq fills the two null placeholders from the captured file,
  # so the blocks return verbatim as the assistant message. The thinking
  # block MUST accompany the tool_use block. The quoted delimiter keeps the
  # shell from expanding anything in the body.
  jq --slurpfile blocks assistant_content.json '
    .messages[1].content = $blocks[0] |
    .messages[2].content[0].tool_use_id =
      ($blocks[0][] | select(.type == "tool_use") | .id)
  ' <<'JSON' | ant messages create
  {
    "model": "claude-opus-4-8",
    "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?"},
      {"role": "assistant", "content": null},
      {"role": "user", "content": [{
        "type": "tool_result",
        "tool_use_id": null,
        "content": "Current temperature: 88°F"
      }]}
    ]
  }
  JSON
  ```

  ```python 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-4-8",
      max_tokens=16000,
      thinking={"type": "adaptive"},
      tools=[weather_tool],
      messages=[{"role": "user", "content": "What's the weather in Paris?"}],
  )
  # Extract the tool use block to get its ID for the tool result
  tool_use_block = next(block for block in response.content if block.type == "tool_use")

  # Call your actual weather API, here is where your actual API call would go
  # Let's pretend this is what we get back
  weather_data = {"temperature": 88}

  # Second request - Include the assistant turn and the tool result
  continuation = client.messages.create(
      model="claude-opus-4-8",
      max_tokens=16000,
      thinking={"type": "adaptive"},
      tools=[weather_tool],
      messages=[
          {"role": "user", "content": "What's the weather in Paris?"},
          # Echo the assistant content exactly as received. When a thinking
          # block is present, it must accompany the tool_use block.
          {"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 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-4-8",
    max_tokens: 16000,
    thinking: {
      type: "adaptive"
    },
    tools: [weatherTool],
    messages: [{ role: "user", content: "What's the weather in Paris?" }]
  });

  // Extract the tool use block to get its ID for the tool result
  const toolUseBlock = response.content.find(
    (block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
  );

  // Call your actual weather API, here is where your actual API call would go
  // Let's pretend this is what we get back
  const weatherData = { temperature: 88 };

  if (toolUseBlock) {
    // Second request - Include the assistant turn and the tool result
    const continuation = await client.messages.create({
      model: "claude-opus-4-8",
      max_tokens: 16000,
      thinking: {
        type: "adaptive"
      },
      tools: [weatherTool],
      messages: [
        { role: "user", content: "What's the weather in Paris?" },
        // Echo the assistant content exactly as received. When a thinking
        // block is present, it must accompany the tool_use block.
        { 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);
  }
  ```

  ```csharp 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.ClaudeOpus4_8,
      MaxTokens = 16000,
      Thinking = new ThinkingConfigAdaptive(),
      Tools = [weatherTool],
      Messages = [
          new() { Role = Role.User, Content = "What's the weather in Paris?" }
      ]
  };

  var response = await client.Messages.Create(parameters);

  // Extract the tool_use block to get its ID for the tool result
  ToolUseBlock? toolUseBlock = null;
  foreach (var block in response.Content)
  {
      if (block.TryPickToolUse(out var toolUse))
      {
          toolUseBlock = toolUse;
          break;
      }
  }

  var weatherData = new { temperature = 88 };

  // Build continuation with tool result
  var continuationParams = new MessageCreateParams
  {
      Model = Model.ClaudeOpus4_8,
      MaxTokens = 16000,
      Thinking = new ThinkingConfigAdaptive(),
      Tools = [weatherTool],
      Messages = [
          new() { Role = Role.User, Content = "What's the weather in Paris?" },
          // response.Content includes the thinking blocks; passing them back is required
          new() { Role = Role.Assistant, Content = response.Content.Select(block => new ContentBlockParam(block.Json)).ToList() },
          new() { Role = Role.User, Content = new MessageParamContent(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 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.ModelClaudeOpus4_8,
  	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.ModelClaudeOpus4_8,
  	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 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_4_8)
          .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;

      // Second request: echo the assistant turn as received, then the tool result
      MessageCreateParams continuationParams = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_4_8)
          .maxTokens(16000L)
          .thinking(ThinkingConfigAdaptive.builder().build())
          .addTool(weatherTool)
          .addUserMessage("What's the weather in Paris?")
          .addMessage(response)
          .addUserMessageOfBlockParams(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 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-4-8',
      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-4-8',
      thinking: ['type' => 'adaptive'],
      tools: [$weatherTool],
  );

  echo $continuation;
  ```

  ```ruby 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: "claude-opus-4-8",
    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: "claude-opus-4-8",
    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
  ```
</CodeGroup>
Claude가 텍스트로 턴을 끝내는 것을 볼 수 있어요. [인터리브된 thinking](https://platform.claude.com/docs/en/build-with-claude/thinking#interleaved-thinking)이 적응형 모드에서 자동이므로, 이어지는 응답이 최종 텍스트 앞에 새 thinking 블록으로 열릴 수도 있어요:
```json Output
{
  "content": [
    {
      "type": "text",
      "text": "Currently in Paris, the temperature is 88°F (31°C)"
    }
  ]
}
```

인터리브된 thinking이 흐름을 바꾸는 방식

인터리브된 thinking은 Claude가 도구 호출 사이에 생각하게 해서, 각 도구 결과에 대해 행동하기 전에 추론하게 해요. 개념과 모델별 가용성은 Thinking 페이지의 인터리브된 thinking에서 다뤄요. 인터리빙은 thinking 블록이 나타나는 위치를 바꾸지, 도구 호출이 이어질 수 있는지 여부는 바꾸지 않아요. 다음 비교는 두 도구 워크플로에서 인터리브된 thinking이 무엇을 바꾸는지 보여줘요:

인터리브된 thinking이 없으면 Claude는 어시스턴트 턴 시작에 한 번 생각해요. 도구 결과 이후의 후속 응답은 새 thinking 블록 없이 계속돼요.
```text
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
```
인터리브된 thinking을 켜면 Claude는 각 도구 결과를 받은 뒤 생각할 수 있어서, 계속하기 전에 중간 결과를 추론할 수 있어요.
```text
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
```

다음 단계

The overview: turn thinking on, read thinking output, and review the full rules for tool use, caching, and streaming. Steer how often and how deeply Claude thinks with effort levels and prompt-based guidance. Manual thinking budgets on older models: `budget_tokens` mechanics and migration to adaptive.

더 알아보기 (Learn more)