---
title: 도구 및 멀티턴 워크플로에서의 사고
url: https://platform.claude.com/docs/ko/build-with-claude/thinking-tool-workflows
description: 사고 블록을 올바르게 보존하는 완전한 2턴 도구 사용 왕복 과정을 단계별로 살펴보고, 인터리브 사고가 흐름을 어떻게 바꾸는지 확인합니다.
---

<Note>
  "zero data retention"(제로 데이터 보존), 즉 ZDR이 이 기능에 어떻게 적용되는지 알아보려면 [API 및 데이터 보존](https://platform.claude.com/docs/ko/manage-claude/api-and-data-retention)을 참조하세요.
</Note>

이 페이지는 사고가 활성화된 상태에서 완전한 2턴 "tool use"(도구 사용) 왕복 과정을 단계별로 살펴봅니다. Claude가 사고하고, 도구 호출을 요청하고, 결과를 받은 뒤 답변을 마무리하며, 모든 단계에서 사고 블록이 올바르게 처리됩니다. 전체 규칙은 [사고](https://platform.claude.com/docs/ko/build-with-claude/thinking) 페이지의 [도구 사용과 함께하는 사고](https://platform.claude.com/docs/ko/build-with-claude/thinking#thinking-with-tool-use) 및 [사고 블록 보존](https://platform.claude.com/docs/ko/build-with-claude/thinking#preserving-thinking-blocks)에 있으며, 이 페이지는 해당 규칙을 실행 가능한 코드에 적용한 모습을 보여줍니다.

## 이 안내에서 적용하는 규칙

각 링크는 사고 페이지의 전체 설명으로 연결됩니다:

* [수동 모드에서는 도구 선택을 `auto` 또는 `none`으로 제한](https://platform.claude.com/docs/ko/build-with-claude/thinking#thinking-with-tool-use): 도구 사용을 강제하는 `tool_choice` 옵션은 수동 확장 사고(`thinking: {type: "enabled"}`)와 함께 사용하면 오류를 반환합니다. 적응형 사고는 강제 도구 사용을 지원하지만, Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1, Claude Mythos 5.1은 예외로 400 오류를 반환합니다. 강제 도구 사용이 허용되는 경우에는 사고를 건너뛰며, 응답은 도구 호출로 시작합니다.
* [어시스턴트 턴당 하나의 사고 구성 유지](https://platform.claude.com/docs/ko/build-with-claude/thinking#thinking-with-tool-use): 도구 사용 루프는 하나의 어시스턴트 턴이므로, 구성은 턴 사이에서만 변경하세요.
* [사고 블록을 완전하고 수정 없이 다시 전달](https://platform.claude.com/docs/ko/build-with-claude/thinking#preserving-thinking-blocks): 도구 결과를 반환할 때 어시스턴트 메시지의 사고 블록도 함께 돌려보내야 합니다.
* [어시스턴트 메시지를 받은 그대로 정확히 되돌려 보내기](https://platform.claude.com/docs/ko/build-with-claude/thinking#preserving-thinking-blocks): 메시지를 재구성하거나 `redacted_thinking` 블록을 걸러내면 400 오류가 발생합니다.

샘플은 적응형 사고를 사용합니다. 확장 사고만 지원하는 모델에서는 `thinking: {type: "enabled", budget_tokens: N}`으로 대체하세요. 왕복 규칙은 동일합니다.

## 2턴 도구 사용 왕복 과정 살펴보기

이 예제는 `get_weather` 도구를 정의하고, Claude가 사고한 뒤 도구 호출을 요청하게 한 다음, 사고 블록을 포함하여 받은 그대로 정확히 되돌린 어시스턴트 턴과 함께 도구 결과를 반환합니다.

<Steps>
  <Step title="도구를 사용 가능하게 하여 첫 번째 요청 보내기">
    적응형 사고를 활성화하고 도구를 정의한 요청을 보냅니다. `thinking` 매개변수를 제외하면 이는 표준 [도구 사용](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/overview) 요청입니다:

    <CodeGroup>
      ```bash 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?"}]
        }'
      ```

      ```bash CLI
      ant messages create --transform content <<'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?"
      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"],
          },
      }

      # 첫 번째 요청 - 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 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);
      ```

      ```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.ClaudeOpus5_5,
          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.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 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 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-5-5',
          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-5-5",
        max_tokens: 16000,
        thinking: {
          type: "adaptive"
        },
        tools: [weather_tool],
        messages: [
          { role: "user", content: "What's the weather in Paris?" }
        ]
      )
      puts message
      ```
    </CodeGroup>
  </Step>

  <Step title="되돌려 보낼 content 배열 캡처하기">
    Claude가 사고하기로 선택한 실행에서는 응답 content에 `thinking` 및 `tool_use` 블록이 표시됩니다(더 단순한 요청에서는 적응형 모드가 사고 블록을 건너뛸 수 있습니다). Claude가 도구 호출 전에 작성하는 메모는 `text` 블록으로 반환되거나, [진행 상황 업데이트](https://platform.claude.com/docs/ko/build-with-claude/thinking#progress-updates)를 작성하는 모델에서는 또 다른 `thinking` 블록으로 반환됩니다. 이 content 배열을 그대로 유지하세요. 다음 단계에서 이를 그대로 다시 전송합니다.

    <Note>
      이 출력과 같은 사고 텍스트를 보려면 요청에 `display: "summarized"`를 추가하세요. Claude Opus 5.5를 포함하여 display 기본값이 omitted인 모델에서는, 그렇지 않으면 `thinking` 필드가 빈 문자열로 반환되고 `signature`만 채워집니다. 어느 경우든 content 배열을 변경 없이 되돌려 보내세요. [사고 표시 제어](https://platform.claude.com/docs/ko/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": "tool_use",
          "id": "toolu_01CswdEQBMshySk6Y9DFKrfq",
          "name": "get_weather",
          "input": {
            "location": "Paris"
          }
        }
      ]
    }
    ```
  </Step>

  <Step title="어시스턴트 턴을 그대로 되돌리며 도구 결과 반환하기">
    여러분 측에서 도구를 실행한 다음, 대화에 두 개의 메시지를 추가하는 두 번째 요청을 보냅니다. 첫 번째는 받은 그대로 정확히 되돌린 어시스턴트 content로, 사고 블록이 `tool_use` 블록과 함께 변경 없이 유지됩니다. 두 번째는 `tool_result`를 담은 사용자 메시지입니다.

    각 샘플은 독립적으로 실행되는 스크립트입니다. 첫 번째 요청을 반복한 다음, 방금 받은 응답을 사용하여 즉시 후속 요청을 보냅니다.

    <CodeGroup exclude="shell:cURL">
      <CodeGroupItem language="cURL">
        이 워크플로에는 단일 셸 명령보다 더 많은 로직이 필요합니다. 실행하려면 Claude SDK를 사용하세요.
      </CodeGroupItem>

      ```bash CLI
      # 첫 번째 턴: assistant content 배열(thinking 및 tool_use
      # 블록, 서명 포함)을 파일에 기록합니다. 모델이 생성한 텍스트를 파일로 전달하면
      # 이후 셸 확장이 일어나는 위치에 놓이지 않습니다.
      ant messages create --transform content --format jsonl \
        > assistant_content.json <<'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?
      YAML

      # 두 번째 턴: jq가 캡처한 파일로 두 개의 null 자리 표시자를 채우므로,
      # 블록이 assistant 메시지로 그대로 반환됩니다. thinking
      # 블록은 반드시 tool_use 블록과 함께 있어야 합니다. 따옴표로 감싼 구분자는
      # 셸이 본문의 내용을 확장하지 않도록 합니다.
      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-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?"},
          {"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-5-5",
          max_tokens=16000,
          thinking={"type": "adaptive"},
          tools=[weather_tool],
          messages=[{"role": "user", "content": "What's the weather in Paris?"}],
      )
      # 도구 결과에 사용할 ID를 얻기 위해 도구 사용 블록을 추출합니다
      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?"},
              # 어시스턴트 콘텐츠를 받은 그대로 다시 전달합니다. 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 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_result에 사용할 ID를 얻기 위해 tool_use 블록을 추출합니다
      const toolUseBlock = response.content.find(
        (block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
      );

      // 실제 날씨 API를 호출합니다. 실제 API 호출이 들어갈 위치입니다
      // 이것이 반환된 결과라고 가정합니다
      const weatherData = { temperature: 88 };

      if (toolUseBlock) {
        // 두 번째 요청 - 어시스턴트 턴과 tool_result를 포함합니다
        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?" },
            // 어시스턴트 콘텐츠를 받은 그대로 다시 전달합니다. 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);
      }
      ```

      ```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.ClaudeOpus5_5,
          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);

      // tool_result 에 사용할 ID를 얻기 위해 tool_use 블록을 추출합니다
      ToolUseBlock? toolUseBlock = null;
      foreach (var block in response.Content)
      {
          if (block.TryPickToolUse(out var toolUse))
          {
              toolUseBlock = toolUse;
              break;
          }
      }

      var weatherData = new { temperature = 88 };

      // tool_result 를 포함한 후속 요청을 구성합니다
      var continuationParams = new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 16000,
          Thinking = new ThinkingConfigAdaptive(),
          Tools = [weatherTool],
          Messages = [
              new() { Role = Role.User, Content = "What's the weather in Paris?" },
              // response.Content 에는 thinking 블록이 포함되어 있으며, 이를 다시 전달하는 것이 필수입니다
              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.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 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;

          // 두 번째 요청: 받은 어시스턴트 턴을 그대로 반환한 다음 도구 결과를 전달
          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)
              .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-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 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-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: "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
      ```
    </CodeGroup>
  </Step>

  <Step title="최종 응답 읽기">
    Claude가 텍스트로 턴을 완료하는 것을 볼 수 있습니다. 적응형 모드에서는 [인터리브 사고](https://platform.claude.com/docs/ko/build-with-claude/thinking#interleaved-thinking)가 자동이므로, 이어지는 응답이 최종 텍스트 앞에 새로운 사고 블록으로 시작할 수도 있습니다:

    ```json Output
    {
      "content": [
        {
          "type": "text",
          "text": "Currently in Paris, the temperature is 88°F (31°C)"
        }
      ]
    }
    ```
  </Step>
</Steps>

## 인터리브 사고가 흐름을 바꾸는 방식

"Interleaved thinking"(인터리브 사고)은 Claude가 도구 호출 사이에 사고하여, 각 도구 결과에 따라 행동하기 전에 그 결과에 대해 추론할 수 있게 합니다. 개념과 모델별 지원 여부는 사고 페이지의 [인터리브 사고](https://platform.claude.com/docs/ko/build-with-claude/thinking#interleaved-thinking)에서 다룹니다. 인터리빙은 사고 블록이 나타나는 위치를 바꿀 뿐, 도구 호출을 연쇄할 수 있는지 여부를 바꾸지는 않습니다. 다음 비교는 두 개의 도구를 사용하는 워크플로에서 인터리브 사고가 무엇을 바꾸는지 보여줍니다:

<AccordionGroup>
  <Accordion title="인터리브 사고 없는 도구 사용">
    인터리브 사고가 없으면 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, 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
    ```
  </Accordion>

  <Accordion title="인터리브 사고가 있는 도구 사용">
    인터리브 사고가 활성화되면 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
    ```
  </Accordion>
</AccordionGroup>

## 다음 단계

<CardGroup cols={3}>
  <Card title="사고" icon="brain" href="https://platform.claude.com/docs/ko/build-with-claude/thinking">
    개요: 사고를 켜고, 사고 출력을 읽고, 도구 사용, 캐싱, 스트리밍에 대한 전체 규칙을 검토합니다.
  </Card>

  <Card title="사고 조정하기" icon="compass" href="https://platform.claude.com/docs/ko/build-with-claude/thinking-steering-and-cost">
    노력 수준과 프롬프트 기반 안내를 통해 Claude가 얼마나 자주, 얼마나 깊이 사고할지 조정합니다.
  </Card>

  <Card title="확장 사고" icon="clock" href="https://platform.claude.com/docs/ko/build-with-claude/extended-thinking">
    이전 모델에서의 수동 사고 예산: `budget_tokens` 동작 방식과 적응형으로의 마이그레이션.
  </Card>
</CardGroup>
