---
title: 프로그래매틱 도구 호출
url: https://platform.claude.com/docs/ko/agents-and-tools/tool-use/programmatic-tool-calling
description: Claude가 코드 실행 컨테이너 안의 코드에서 도구를 호출하도록 하여, 다중 도구 워크플로에서 모델 왕복 횟수와 토큰 사용량을 줄입니다.
featureMetadata:
  status: ga
  zdr: not-eligible
  supportedModels:
    - claude-fable-5-1
    - claude-mythos-5-1
    - claude-fable-5
    - claude-mythos-5
    - claude-opus-5-5
    - claude-opus-5
    - claude-opus-4-8
    - claude-opus-4-7
    - claude-opus-4-6
    - claude-opus-4-5-20251101
    - claude-sonnet-5-5
    - claude-sonnet-5
    - claude-sonnet-4-6
    - claude-sonnet-4-5-20250929
    - claude-haiku-5-5
  supportedPlatforms:
    Claude API: ga
    Claude Platform on AWS: ga
    Microsoft Foundry:
      availability: ga
      note: "[Microsoft Foundry](https://platform.claude.com/docs/ko/build-with-claude/claude-in-microsoft-foundry)에서 프로그래밍 방식 도구 호출을 사용하려면 [Hosted on Anthropic 배포](https://platform.claude.com/docs/ko/build-with-claude/claude-in-microsoft-foundry#additional-features-not-supported-when-hosted-on-azure)가 필요합니다."
  details:
    - 프로그래밍 방식 도구 호출에는 `code_execution_20260120` 이상의 [도구 버전](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/code-execution-tool#tool-versions)을 사용하는 코드 실행 도구가 필요합니다.
    - Claude Haiku 4.5는 `code_execution_20260120` 이상의 도구 버전을 허용하지만 프로그래밍 방식 도구 호출은 지원하지 않습니다.
---

"Programmatic tool calling"(프로그래매틱 도구 호출)을 사용하면 Claude가 각 도구 호출마다 모델을 거치는 왕복을 요구하는 대신, [코드 실행](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/code-execution-tool) 컨테이너 내에서 도구를 프로그래매틱하게 호출하는 코드를 작성할 수 있습니다. 이를 통해 다중 도구 워크플로의 "latency"(지연 시간)가 줄어들고, 데이터가 모델의 "context window"(컨텍스트 윈도우)에 도달하기 전에 Claude가 데이터를 필터링하거나 처리할 수 있으므로 토큰 소비도 감소합니다. 다단계 웹 리서치와 복잡한 정보 검색을 테스트하는 [BrowseComp](https://arxiv.org/abs/2504.12516) 및 [DeepSearchQA](https://github.com/google-deepmind/deepsearchqa)와 같은 에이전트 검색 벤치마크에서, 기본 검색 도구 위에 프로그래매틱 도구 호출을 추가하면 입력 토큰을 24% 적게 사용하면서 성능이 평균 11% 향상되었습니다([동적 필터링을 통한 웹 검색 개선](https://claude.com/blog/improved-web-search-with-dynamic-filtering) 참조).

직원 20명의 예산 준수 여부를 확인하는 경우를 생각해 보세요. 기존 방식은 20번의 개별 모델 왕복이 필요하며, 그 과정에서 수천 개의 지출 항목을 컨텍스트로 가져옵니다. 프로그래매틱 도구 호출을 사용하면 단일 스크립트가 20번의 조회를 모두 실행하고, 결과를 필터링하여 한도를 초과한 직원만 반환하므로, Claude가 추론해야 하는 대상이 수백 킬로바이트에서 몇 줄로 줄어듭니다.

<Tip>
  프로그래매틱 도구 호출이 해결하는 추론 및 컨텍스트 비용에 대해 더 자세히 알아보려면 [고급 도구 사용](https://www.anthropic.com/engineering/advanced-tool-use)을 참조하세요.
</Tip>

프로그래매틱 도구 호출에는 도구 버전 `code_execution_20260120` 이상의 [코드 실행 도구](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/code-execution-tool)가 필요합니다. 요청을 보내기 전에 모델이 프로그래매틱 도구 호출을 지원하는지 확인하려면 Models API에서 해당 모델의 `capabilities.code_execution.supported` 값을 읽으세요. 이 필드에 대한 설명은 [Models API 사용하기](https://platform.claude.com/docs/ko/models/overview#using-the-models-api)에 있습니다.

## 빠른 시작

다음은 Claude가 데이터베이스를 프로그래매틱하게 여러 번 쿼리하고 결과를 집계하는 예시입니다. 도구 정의에 `allowed_callers: ["code_execution_20260120"]`을 추가하면 해당 도구를 코드 실행 내에서 호출할 수 있게 됩니다([`allowed_callers` 필드](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/programmatic-tool-calling#the-allowed-callers-field) 참조):

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
      --header "x-api-key: $ANTHROPIC_API_KEY" \
      --header "anthropic-version: 2023-06-01" \
      --header "content-type: application/json" \
      --data '{
          "model": "claude-opus-5-5",
          "max_tokens": 4096,
          "messages": [
              {
                  "role": "user",
                  "content": "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"
              }
          ],
          "tools": [
              {
                  "type": "code_execution_20260120",
                  "name": "code_execution"
              },
              {
                  "name": "query_database",
                  "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
                  "input_schema": {
                      "type": "object",
                      "properties": {
                          "sql": {
                              "type": "string",
                              "description": "SQL query to execute"
                          }
                      },
                      "required": ["sql"]
                  },
                  "allowed_callers": ["code_execution_20260120"]
              }
          ]
      }'
  ```

  ```bash CLI
  ant messages create <<'YAML'
  model: claude-opus-5-5
  max_tokens: 4096
  messages:
    - role: user
      content: >-
        Query sales data for the West, East, and Central regions, then
        tell me which region had the highest revenue
  tools:
    - type: code_execution_20260120
      name: code_execution
    - name: query_database
      description: >-
        Execute a SQL query against the sales database. Returns a list
        of rows as JSON objects.
      input_schema:
        type: object
        properties:
          sql:
            type: string
            description: SQL query to execute
        required:
          - sql
      allowed_callers:
        - code_execution_20260120
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  response = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=4096,
      messages=[
          {
              "role": "user",
              "content": "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue",
          }
      ],
      tools=[
          {"type": "code_execution_20260120", "name": "code_execution"},
          {
              "name": "query_database",
              "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
              "input_schema": {
                  "type": "object",
                  "properties": {
                      "sql": {"type": "string", "description": "SQL query to execute"}
                  },
                  "required": ["sql"],
              },
              "allowed_callers": ["code_execution_20260120"],
          },
      ],
  )

  print(response)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 4096,
    messages: [
      {
        role: "user",
        content:
          "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"
      }
    ],
    tools: [
      {
        type: "code_execution_20260120",
        name: "code_execution"
      },
      {
        name: "query_database",
        description:
          "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
        input_schema: {
          type: "object" as const,
          properties: {
            sql: {
              type: "string",
              description: "SQL query to execute"
            }
          },
          required: ["sql"]
        },
        allowed_callers: ["code_execution_20260120"]
      }
    ]
  });

  console.log(response);
  ```

  ```csharp C#
  AnthropicClient client = new();

  var parameters = new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 4096,
      Messages = [
          new() {
              Role = Role.User,
              Content = "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"
          }
      ],
      Tools = [
          new CodeExecutionTool20260120(),
          new ToolUnion(new Tool()
          {
              Name = "query_database",
              Description = "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
              InputSchema = new InputSchema()
              {
                  Properties = new Dictionary<string, JsonElement>
                  {
                      ["sql"] = JsonSerializer.SerializeToElement(new { type = "string", description = "SQL query to execute" }),
                  },
                  Required = ["sql"],
              },
              AllowedCallers = ["code_execution_20260120"]
          }),
      ]
  };

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

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 4096,
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue")),
  	},
  	Tools: []anthropic.ToolUnionParam{
  		{OfCodeExecutionTool20260120: &anthropic.CodeExecutionTool20260120Param{}},
  		{OfTool: &anthropic.ToolParam{
  			Name:        "query_database",
  			Description: anthropic.String("Execute a SQL query against the sales database. Returns a list of rows as JSON objects."),
  			InputSchema: anthropic.ToolInputSchemaParam{
  				Properties: map[string]any{
  					"sql": map[string]any{
  						"type":        "string",
  						"description": "SQL query to execute",
  					},
  				},
  				Required: []string{"sql"},
  			},
  			AllowedCallers: []string{"code_execution_20260120"},
  		}},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(response.RawJSON())
  ```

  ```java Java
  import com.anthropic.models.messages.CodeExecutionTool20260120;
  // ...

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(4096L)
          .addUserMessage("Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue")
          .addTool(CodeExecutionTool20260120.builder().build())
          .addTool(Tool.builder()
              .name("query_database")
              .description("Execute a SQL query against the sales database. Returns a list of rows as JSON objects.")
              .inputSchema(InputSchema.builder()
                  .properties(JsonValue.from(Map.of(
                      "sql", Map.of(
                          "type", "string",
                          "description", "SQL query to execute"
                      )
                  )))
                  .putAdditionalProperty("required", JsonValue.from(List.of("sql")))
                  .build())
              .allowedCallers(List.of(Tool.AllowedCaller.of("code_execution_20260120")))
              .build())
          .build();

      Message response = client.messages().create(params);
      IO.println(response);
  }
  ```

  ```php PHP
  $client = new Client();

  $message = $client->messages->create(
      maxTokens: 4096,
      messages: [
          ['role' => 'user', 'content' => 'Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue'],
      ],
      model: 'claude-opus-5-5',
      tools: [
          [
              'type' => 'code_execution_20260120',
              'name' => 'code_execution',
          ],
          [
              'name' => 'query_database',
              'description' => 'Execute a SQL query against the sales database. Returns a list of rows as JSON objects.',
              'input_schema' => [
                  'type' => 'object',
                  'properties' => [
                      'sql' => [
                          'type' => 'string',
                          'description' => 'SQL query to execute',
                      ],
                  ],
                  'required' => ['sql'],
              ],
              'allowed_callers' => ['code_execution_20260120'],
          ],
      ],
  );

  echo $message;
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  message = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 4096,
    messages: [
      {
        role: "user",
        content: "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"
      }
    ],
    tools: [
      {
        type: "code_execution_20260120",
        name: "code_execution"
      },
      {
        name: "query_database",
        description: "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
        input_schema: {
          type: "object",
          properties: {
            sql: {
              type: "string",
              description: "SQL query to execute"
            }
          },
          required: ["sql"]
        },
        allowed_callers: ["code_execution_20260120"]
      }
    ]
  )

  puts message
  ```
</CodeGroup>

응답은 `stop_reason: "tool_use"`, `container` ID, 그리고 `query_database`에 대한 `tool_use` 블록과 함께 중지되며, 이 블록의 `caller` 필드는 해당 도구를 호출한 코드 실행을 식별합니다. 코드가 완료될 수 있도록 [예시 워크플로의 3단계](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/programmatic-tool-calling#step-3-provide-tool-result)에 표시된 대로 결과를 반환하세요.

## 프로그래매틱 도구 호출의 작동 방식

도구를 코드 실행에서 호출 가능하도록 구성하고 Claude가 해당 도구가 필요하다고 판단하면:

1. Claude가 도구를 함수로 호출하는 Python 코드를 작성합니다. 여기에는 여러 도구 호출과 전처리/후처리 로직이 포함될 수 있습니다
2. Claude가 코드 실행을 통해 샌드박스 컨테이너에서 이 코드를 실행합니다
3. 도구 함수가 호출되면 코드 실행이 일시 중지되고 API가 `tool_use` 블록을 반환합니다
4. 도구 결과를 제공하면 코드 실행이 계속됩니다(중간 결과는 Claude의 컨텍스트 윈도우에 로드되지 않습니다)
5. 모든 코드 실행이 완료되면 Claude가 최종 출력을 받고 작업을 계속합니다

이 접근 방식은 특히 다음과 같은 경우에 유용합니다:

* **대용량 데이터 처리:** 도구 결과가 Claude의 컨텍스트에 도달하기 전에 필터링하거나 집계합니다
* **다단계 워크플로:** 도구 호출 사이에 Claude를 샘플링하지 않고 도구를 순차적으로 또는 루프에서 호출하여 토큰과 지연 시간을 절약합니다
* **조건부 로직:** 중간 도구 결과를 기반으로 결정을 내립니다

<Note>
  코드 실행 호출자를 허용하는 도구는 Claude의 코드에 비동기 Python 함수로 노출되므로, Claude는 `asyncio.gather`를 사용하여 이를 병렬로 실행할 수 있습니다. 각 함수는 단일 인수 dict를 받고 문자열, 즉 여러분이 다시 보내는 `tool_result`의 텍스트를 반환합니다. Claude의 코드는 최상위 `await`로 이러한 함수를 기다리고, 필요한 결과를 구조화된 데이터로 파싱합니다. 예: `rows = json.loads(await query_database({"sql": "<sql>"}))`.
</Note>

## 핵심 개념

### `allowed_callers` 필드

`allowed_callers` 필드는 어떤 컨텍스트에서 도구를 호출할 수 있는지 지정합니다:

```json
{
  "name": "query_database",
  "description": "Execute a SQL query against the database",
  "input_schema": {
    // ...
  },
  "allowed_callers": ["code_execution_20260120"]
}
```

**가능한 값:**

* `["direct"]` - Claude가 이 도구를 직접 호출하도록 안내됩니다(생략 시 기본값)
* `["code_execution_20260120"]` - Claude가 이 도구를 코드 실행 내에서만 호출하도록 안내됩니다
* `["direct", "code_execution_20260120"]` - Claude가 이 도구를 직접 또는 코드 실행 내에서 호출할 수 있습니다

`"code_execution_20260120"`과 `"code_execution_20260521"` 모두 `allowed_callers`에서 허용되며 서로 교환 가능합니다. 어느 코드 실행 도구 버전을 사용하는 요청이든 두 호출자 중 하나를 나열한 도구를 충족합니다. 응답 블록은 요청에서 선언한 버전과 관계없이 항상 호출자를 `code_execution_20260120`으로 태그합니다.

<Tip>
  각 도구에 대해 둘 다 활성화하기보다는 `["direct"]` 또는 `["code_execution_20260120"]` 중 하나를 선택하세요. 이렇게 하면 Claude에게 도구를 가장 잘 사용하는 방법에 대한 더 명확한 안내를 제공할 수 있습니다.
</Tip>

<Note>
  `allowed_callers`는 도구가 Claude에게 제시되는 방식을 제어하고 `tool_choice`에 대해 검증되지만, 직접 호출에 대한 API 수준의 강제 차단은 아닙니다. Claude는 이를 준수하도록 강하게 안내되지만, 클라이언트는 여전히 정의한 모든 도구에 대한 직접 `tool_use`를 처리할 준비가 되어 있어야 합니다. `allowed_callers`를 보안 경계로 의존하지 마세요.
</Note>

### 응답의 `caller` 필드

모든 도구 사용 블록에는 호출 방식을 나타내는 `caller` 필드가 포함됩니다:

**직접 호출(기존 도구 사용):**

```json
{
  "type": "tool_use",
  "id": "toolu_abc123",
  "name": "query_database",
  "input": { "sql": "<sql>" },
  "caller": { "type": "direct" }
}
```

**프로그래매틱 호출:**

```json
{
  "type": "tool_use",
  "id": "toolu_xyz789",
  "name": "query_database",
  "input": { "sql": "<sql>" },
  "caller": {
    "type": "code_execution_20260120",
    "tool_id": "srvtoolu_abc123"
  }
}
```

`tool_id`는 호출을 수행한 코드 실행 `server_tool_use` 블록의 `id`이므로, 각 프로그래매틱 `tool_use`를 이를 생성한 코드 실행과 매칭할 수 있습니다.

### 컨테이너 수명 주기

프로그래매틱 도구 호출은 코드 실행과 동일한 컨테이너를 사용합니다:

* **컨테이너 생성:** 기존 컨테이너를 재사용하지 않는 한 각 요청마다 새 컨테이너가 생성됩니다
* **컨테이너 ID:** 응답의 `container` 필드에 `expires_at` 타임스탬프와 함께 반환됩니다
* **재사용:** 상태를 유지하려면 다음 요청에 컨테이너 ID를 다시 전달하세요. 프로그래매틱 도구 호출이 결과를 기다리는 동안에는 해당 요청에서 컨테이너 ID가 선택 사항이 아니라 필수입니다. API는 컨테이너 ID가 없는 요청을 거부합니다.
* **만료:** `expires_at`은 컨테이너의 남은 시간을 알려줍니다. 유휴 컨테이너는 현재 약 5분 후에 회수되며, 어떤 컨테이너도 생성 후 30일이 지나면 재사용할 수 없습니다.

<Warning>
  Claude의 코드가 프로그래매틱 도구 결과를 기다리는 동안, 대기 중인 호출은 약 4분 후에 타임아웃되어 코드 내부에서 `TimeoutError`를 발생시킵니다. 일시 중지된 응답의 `expires_at` 타임스탬프보다 충분히 일찍 각 도구 결과를 반환하세요. [도구 호출 중 컨테이너 만료](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/programmatic-tool-calling#container-expiration-during-tool-call)를 참조하세요.
</Warning>

## 예시 워크플로

전체 프로그래매틱 도구 호출 흐름은 다음과 같이 작동합니다:

### 1단계: 초기 요청

코드 실행과 프로그래매틱 호출을 허용하는 도구를 포함한 요청을 보냅니다. 프로그래매틱 호출을 활성화하려면 도구 정의에 `allowed_callers` 필드를 추가하세요.

<Note>
  도구 설명에 도구의 출력 형식에 대한 자세한 설명을 제공하세요. 도구가 JSON을 반환한다고 지정하면 Claude는 코드에서 결과를 역직렬화하고 처리하려고 시도합니다. 출력 스키마에 대해 더 자세히 제공할수록 Claude가 응답을 프로그래매틱하게 더 잘 처리할 수 있습니다.
</Note>

요청 형태는 [빠른 시작](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/programmatic-tool-calling#quick-start) 예시와 동일합니다. 도구 목록에 `code_execution`을 포함하고, Claude가 코드에서 호출하기를 원하는 모든 도구에 `allowed_callers: ["code_execution_20260120"]`을 추가한 다음 사용자 메시지를 보내세요. 이 워크플로의 나머지 단계에서는 사용자 메시지 `"Query customer purchase history from the last quarter and identify our top 5 customers by revenue"`를 사용합니다.

### 2단계: 도구 호출이 포함된 API 응답

Claude가 도구를 호출하는 코드를 작성합니다. API가 일시 중지되고 다음을 반환합니다:

```json Output
{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "I'll query the purchase history and analyze the results."
    },
    {
      "type": "server_tool_use",
      "id": "srvtoolu_abc123",
      "name": "code_execution",
      "input": {
        "code": "import json\n\nrows = json.loads(await query_database({'sql': '<sql>'}))\ntop_customers = sorted(rows, key=lambda x: x['revenue'], reverse=True)[:5]\nprint(f'Top 5 customers: {top_customers}')"
      }
    },
    {
      "type": "tool_use",
      "id": "toolu_def456",
      "name": "query_database",
      "input": { "sql": "<sql>" },
      "caller": {
        "type": "code_execution_20260120",
        "tool_id": "srvtoolu_abc123"
      }
    }
  ],
  "container": {
    "id": "container_xyz789",
    "expires_at": "2026-01-20T14:30:00Z"
  },
  "stop_reason": "tool_use"
}
```

### 3단계: 도구 결과 제공

전체 대화 기록과 도구 결과를 함께 보냅니다. 이 요청에서는 세 가지 세부 사항이 중요합니다:

* 결과를 담는 사용자 메시지에는 `tool_result` 블록만 포함될 수 있습니다. [메시지 형식 제한](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/programmatic-tool-calling#message-formatting-restrictions)을 참조하세요.
* 일시 중지된 응답의 `container` ID를 전달하세요. API는 대기 중인 프로그래매틱 도구 호출이 있지만 컨테이너 ID가 없는 연속 요청을 거부합니다.
* 원래 요청과 동일한 `tools` 배열을 보내세요. 일시 중지된 코드가 재개되려면 코드 실행 도구가 여전히 존재해야 하며, 이 요청에서 보내는 도구는 Claude와 실행 중인 코드가 턴의 나머지 동안 사용할 수 있는 정의입니다.

<CodeGroup>
  ```bash cURL
  curl https://api.anthropic.com/v1/messages \
      --header "x-api-key: $ANTHROPIC_API_KEY" \
      --header "anthropic-version: 2023-06-01" \
      --header "content-type: application/json" \
      --data '{
          "model": "claude-opus-5-5",
          "max_tokens": 4096,
          "container": "container_xyz789",
          "messages": [
              {
                  "role": "user",
                  "content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"
              },
              {
                  "role": "assistant",
                  "content": [
                      {
                          "type": "text",
                          "text": "I'\''ll query the purchase history and analyze the results."
                      },
                      {
                          "type": "server_tool_use",
                          "id": "srvtoolu_abc123",
                          "name": "code_execution",
                          "input": {"code": "..."}
                      },
                      {
                          "type": "tool_use",
                          "id": "toolu_def456",
                          "name": "query_database",
                          "input": {"sql": "<sql>"},
                          "caller": {
                              "type": "code_execution_20260120",
                              "tool_id": "srvtoolu_abc123"
                          }
                      }
                  ]
              },
              {
                  "role": "user",
                  "content": [
                      {
                          "type": "tool_result",
                          "tool_use_id": "toolu_def456",
                          "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}]"
                      }
                  ]
              }
          ],
          "tools": [
              {
                  "type": "code_execution_20260120",
                  "name": "code_execution"
              },
              {
                  "name": "query_database",
                  "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
                  "input_schema": {
                      "type": "object",
                      "properties": {
                          "sql": {
                              "type": "string",
                              "description": "SQL query to execute"
                          }
                      },
                      "required": ["sql"]
                  },
                  "allowed_callers": ["code_execution_20260120"]
              }
          ]
      }'
  ```

  ```bash CLI
  ant messages create <<'YAML'
  model: claude-opus-5-5
  max_tokens: 4096
  container: container_xyz789
  messages:
    - role: user
      content: >-
        Query customer purchase history from the last quarter and identify our
        top 5 customers by revenue
    - role: assistant
      content:
        - type: text
          text: I'll query the purchase history and analyze the results.
        - type: server_tool_use
          id: srvtoolu_abc123
          name: code_execution
          input:
            code: "..."
        - type: tool_use
          id: toolu_def456
          name: query_database
          input:
            sql: "<sql>"
          caller:
            type: code_execution_20260120
            tool_id: srvtoolu_abc123
    - role: user
      content:
        - type: tool_result
          tool_use_id: toolu_def456
          content: >-
            [{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2",
            "revenue": 38000}, ...]
  # 원래 요청과 동일한 tools 배열
  tools:
    - type: code_execution_20260120
      name: code_execution
    - name: query_database
      description: >-
        Execute a SQL query against the sales database. Returns a list
        of rows as JSON objects.
      input_schema:
        type: object
        properties:
          sql:
            type: string
            description: SQL query to execute
        required:
          - sql
      allowed_callers:
        - code_execution_20260120
  YAML
  ```

  ```python Python
  response = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=4096,
      container="container_xyz789",  # Reuse the container
      messages=[
          {
              "role": "user",
              "content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue",
          },
          {
              "role": "assistant",
              "content": [
                  {
                      "type": "text",
                      "text": "I'll query the purchase history and analyze the results.",
                  },
                  {
                      "type": "server_tool_use",
                      "id": "srvtoolu_abc123",
                      "name": "code_execution",
                      "input": {"code": "..."},
                  },
                  {
                      "type": "tool_use",
                      "id": "toolu_def456",
                      "name": "query_database",
                      "input": {"sql": "<sql>"},
                      "caller": {
                          "type": "code_execution_20260120",
                          "tool_id": "srvtoolu_abc123",
                      },
                  },
              ],
          },
          {
              "role": "user",
              "content": [
                  {
                      "type": "tool_result",
                      "tool_use_id": "toolu_def456",
                      "content": '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]',
                  }
              ],
          },
      ],
      # 원래 요청과 동일한 tools 배열
      tools=[
          {"type": "code_execution_20260120", "name": "code_execution"},
          {
              "name": "query_database",
              "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
              "input_schema": {
                  "type": "object",
                  "properties": {
                      "sql": {"type": "string", "description": "SQL query to execute"}
                  },
                  "required": ["sql"],
              },
              "allowed_callers": ["code_execution_20260120"],
          },
      ],
  )

  print(response)
  ```

  ```typescript TypeScript
  const response = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 4096,
    container: "container_xyz789", // Reuse the container
    messages: [
      {
        role: "user",
        content:
          "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"
      },
      {
        role: "assistant",
        content: [
          { type: "text", text: "I'll query the purchase history and analyze the results." },
          {
            type: "server_tool_use",
            id: "srvtoolu_abc123",
            name: "code_execution",
            input: { code: "..." }
          },
          {
            type: "tool_use",
            id: "toolu_def456",
            name: "query_database",
            input: { sql: "<sql>" },
            caller: {
              type: "code_execution_20260120",
              tool_id: "srvtoolu_abc123"
            }
          }
        ]
      },
      {
        role: "user",
        content: [
          {
            type: "tool_result",
            tool_use_id: "toolu_def456",
            content:
              '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]'
          }
        ]
      }
    ],
    // 원래 요청과 동일한 tools 배열입니다
    tools: [
      {
        type: "code_execution_20260120",
        name: "code_execution"
      },
      {
        name: "query_database",
        description:
          "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
        input_schema: {
          type: "object" as const,
          properties: {
            sql: {
              type: "string",
              description: "SQL query to execute"
            }
          },
          required: ["sql"]
        },
        allowed_callers: ["code_execution_20260120"]
      }
    ]
  });

  console.log(response);
  ```

  ```csharp C#
  AnthropicClient client = new();

  var parameters = new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 4096,
      Container = "container_xyz789",
      Messages =
      [
          new()
          {
              Role = Role.User,
              Content = "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"
          },
          new()
          {
              Role = Role.Assistant,
              Content = new ContentBlock[]
              {
                  new TextBlock { Text = "I'll query the purchase history and analyze the results." },
                  new ServerToolUseBlock
                  {
                      Id = "srvtoolu_abc123",
                      Name = "code_execution",
                      Input = new { code = "..." }
                  },
                  new ToolUseBlock
                  {
                      Id = "toolu_def456",
                      Name = "query_database",
                      Input = new { sql = "<sql>" },
                      Caller = new ToolCaller
                      {
                          Type = "code_execution_20260120",
                          ToolId = "srvtoolu_abc123"
                      }
                  }
              }
          },
          new()
          {
              Role = Role.User,
              Content = new ContentBlockParam[]
              {
                  new ToolResultBlockParam
                  {
                      ToolUseID = "toolu_def456",
                      Content = "[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}, ...]"
                  }
              }
          }
      ],
      // 원래 요청과 동일한 tools 배열입니다
      Tools = [
          new CodeExecutionTool20260120(),
          new ToolUnion(new Tool()
          {
              Name = "query_database",
              Description = "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
              InputSchema = new InputSchema()
              {
                  Properties = new Dictionary<string, JsonElement>
                  {
                      ["sql"] = JsonSerializer.SerializeToElement(new { type = "string", description = "SQL query to execute" }),
                  },
                  Required = ["sql"],
              },
              AllowedCallers = ["code_execution_20260120"]
          }),
      ]
  };

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

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 4096,
  	Container: anthropic.MessageCreateParamsContainerUnion{
  		OfString: anthropic.String("container_xyz789"),
  	},
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Query customer purchase history from the last quarter and identify our top 5 customers by revenue")),
  		{
  			Role: anthropic.MessageParamRoleAssistant,
  			Content: []anthropic.ContentBlockParamUnion{
  				anthropic.NewTextBlock("I'll query the purchase history and analyze the results."),
  				{OfServerToolUse: &anthropic.ServerToolUseBlockParam{
  					ID:    "srvtoolu_abc123",
  					Name:  anthropic.ServerToolUseBlockParamNameCodeExecution,
  					Input: map[string]any{"code": "..."},
  				}},
  				{OfToolUse: &anthropic.ToolUseBlockParam{
  					ID:    "toolu_def456",
  					Name:  "query_database",
  					Input: map[string]any{"sql": "<sql>"},
  					Caller: anthropic.ServerToolUseBlockParamCallerUnion{
  						OfCodeExecution20260120: &anthropic.ServerToolCaller20260120Param{
  							ToolID: "srvtoolu_abc123",
  						},
  					},
  				}},
  			},
  		},
  		{
  			Role: anthropic.MessageParamRoleUser,
  			Content: []anthropic.ContentBlockParamUnion{
  				{OfToolResult: &anthropic.ToolResultBlockParam{
  					ToolUseID: "toolu_def456",
  					Content: []anthropic.ToolResultBlockParamContentUnion{
  						{OfText: &anthropic.TextBlockParam{
  							Text: `[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]`,
  						}},
  					},
  				}},
  			},
  		},
  	},
  	// 원래 요청과 동일한 tools 배열입니다
  	Tools: []anthropic.ToolUnionParam{
  		{OfCodeExecutionTool20260120: &anthropic.CodeExecutionTool20260120Param{}},
  		{OfTool: &anthropic.ToolParam{
  			Name:        "query_database",
  			Description: anthropic.String("Execute a SQL query against the sales database. Returns a list of rows as JSON objects."),
  			InputSchema: anthropic.ToolInputSchemaParam{
  				Properties: map[string]any{
  					"sql": map[string]any{
  						"type":        "string",
  						"description": "SQL query to execute",
  					},
  				},
  				Required: []string{"sql"},
  			},
  			AllowedCallers: []string{"code_execution_20260120"},
  		}},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println(response.RawJSON())
  ```

  ```java Java
  import com.anthropic.models.messages.CodeExecutionTool20260120;
  // ...

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(4096L)
          .container("container_xyz789")
          .addUserMessage("Query customer purchase history from the last quarter and identify our top 5 customers by revenue")
          .addAssistantMessageOfBlockParams(List.of(
              ContentBlockParam.ofText(
                  TextBlockParam.builder()
                      .text("I'll query the purchase history and analyze the results.")
                      .build()),
              ContentBlockParam.ofServerToolUse(
                  ServerToolUseBlockParam.builder()
                      .id("srvtoolu_abc123")
                      .name("code_execution")
                      .input(JsonValue.from(Map.of("code", "...")))
                      .build()),
              ContentBlockParam.ofToolUse(
                  ToolUseBlockParam.builder()
                      .id("toolu_def456")
                      .name("query_database")
                      .input(JsonValue.from(Map.of("sql", "<sql>")))
                      .codeExecution20260120Caller("srvtoolu_abc123")
                      .build())
          ))
          .addUserMessageOfBlockParams(List.of(
              ContentBlockParam.ofToolResult(
                  ToolResultBlockParam.builder()
                      .toolUseId("toolu_def456")
                      .content("[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}, ...]")
                      .build())
          ))
          // 원래 요청과 동일한 tools 배열
          .addTool(CodeExecutionTool20260120.builder().build())
          .addTool(Tool.builder()
              .name("query_database")
              .description("Execute a SQL query against the sales database. Returns a list of rows as JSON objects.")
              .inputSchema(InputSchema.builder()
                  .properties(JsonValue.from(Map.of(
                      "sql", Map.of(
                          "type", "string",
                          "description", "SQL query to execute"
                      )
                  )))
                  .putAdditionalProperty("required", JsonValue.from(List.of("sql")))
                  .build())
              .allowedCallers(List.of(Tool.AllowedCaller.of("code_execution_20260120")))
              .build())
          .build();

      Message response = client.messages().create(params);
      IO.println(response);
  }
  ```

  ```php PHP
  $client = new Client();

  $message = $client->messages->create(
      maxTokens: 4096,
      messages: [
          [
              'role' => 'user',
              'content' => 'Query customer purchase history from the last quarter and identify our top 5 customers by revenue',
          ],
          [
              'role' => 'assistant',
              'content' => [
                  [
                      'type' => 'text',
                      'text' => "I'll query the purchase history and analyze the results.",
                  ],
                  [
                      'type' => 'server_tool_use',
                      'id' => 'srvtoolu_abc123',
                      'name' => 'code_execution',
                      'input' => ['code' => '...'],
                  ],
                  [
                      'type' => 'tool_use',
                      'id' => 'toolu_def456',
                      'name' => 'query_database',
                      'input' => ['sql' => '<sql>'],
                      'caller' => [
                          'type' => 'code_execution_20260120',
                          'tool_id' => 'srvtoolu_abc123',
                      ],
                  ],
              ],
          ],
          [
              'role' => 'user',
              'content' => [
                  [
                      'type' => 'tool_result',
                      'tool_use_id' => 'toolu_def456',
                      'content' => '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]',
                  ],
              ],
          ],
      ],
      model: 'claude-opus-5-5',
      container: 'container_xyz789',
      // 원래 요청과 동일한 tools 배열
      tools: [
          [
              'type' => 'code_execution_20260120',
              'name' => 'code_execution',
          ],
          [
              'name' => 'query_database',
              'description' => 'Execute a SQL query against the sales database. Returns a list of rows as JSON objects.',
              'input_schema' => [
                  'type' => 'object',
                  'properties' => [
                      'sql' => [
                          'type' => 'string',
                          'description' => 'SQL query to execute',
                      ],
                  ],
                  'required' => ['sql'],
              ],
              'allowed_callers' => ['code_execution_20260120'],
          ],
      ],
  );

  echo $message;
  ```

  ```ruby Ruby
  require "anthropic"

  client = Anthropic::Client.new

  message = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 4096,
    container: "container_xyz789",
    messages: [
      {
        role: "user",
        content: "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"
      },
      {
        role: "assistant",
        content: [
          {
            type: "text",
            text: "I'll query the purchase history and analyze the results."
          },
          {
            type: "server_tool_use",
            id: "srvtoolu_abc123",
            name: "code_execution",
            input: { code: "..." }
          },
          {
            type: "tool_use",
            id: "toolu_def456",
            name: "query_database",
            input: { sql: "<sql>" },
            caller: {
              type: "code_execution_20260120",
              tool_id: "srvtoolu_abc123"
            }
          }
        ]
      },
      {
        role: "user",
        content: [
          {
            type: "tool_result",
            tool_use_id: "toolu_def456",
            content: '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]'
          }
        ]
      }
    ],
    # 원래 요청과 동일한 tools 배열
    tools: [
      {
        type: "code_execution_20260120",
        name: "code_execution"
      },
      {
        name: "query_database",
        description: "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
        input_schema: {
          type: "object",
          properties: {
            sql: {
              type: "string",
              description: "SQL query to execute"
            }
          },
          required: ["sql"]
        },
        allowed_callers: ["code_execution_20260120"]
      }
    ]
  )

  puts message
  ```
</CodeGroup>

### 4단계: 다음 도구 호출 또는 완료

코드는 일시 중지된 지점에서 다시 시작하여 결과를 처리합니다. 각 연속 응답은 더 많은 프로그래매틱 `tool_use` 블록과 함께 다시 일시 중지되거나, 코드 실행을 완료하고 Claude가 턴을 계속하도록 합니다(5단계). 둘을 구분하려면 `stop_reason`과 각 `tool_use` 블록의 `caller`를 확인하세요. 여러분을 위해 일시 중지된 응답은 `stop_reason: "tool_use"`와 `caller`가 코드 실행 버전을 지정하는 `tool_use` 블록을 가지며, 이 경우 하나의 사용자 메시지에 대기 중인 모든 프로그래매틱 호출에 대한 `tool_result`를 담아 3단계를 반복합니다.

### 5단계: 최종 응답

코드 실행이 완료되면 Claude가 최종 응답을 제공합니다:

```json Output
{
  "content": [
    {
      "type": "code_execution_tool_result",
      "tool_use_id": "srvtoolu_abc123",
      "content": {
        "type": "code_execution_result",
        "stdout": "Top 5 customers: [{'customer_id': 'C1', 'revenue': 45000}, {'customer_id': 'C2', 'revenue': 38000}, {'customer_id': 'C5', 'revenue': 32000}, {'customer_id': 'C8', 'revenue': 28500}, {'customer_id': 'C3', 'revenue': 24000}]",
        "stderr": "",
        "return_code": 0,
        "content": []
      }
    },
    {
      "type": "text",
      "text": "I've analyzed the purchase history from last quarter. Your top 5 customers generated $167,500 in total revenue, with Customer C1 leading at $45,000."
    }
  ],
  "stop_reason": "end_turn"
}
```

## 고급 패턴

### 루프를 사용한 배치 처리

Claude는 여러 항목을 효율적으로 처리하는 코드를 작성할 수 있습니다:

```python
regions = ["West", "East", "Central", "North", "South"]
results = {}
for region in regions:
    rows = json.loads(await query_database({"sql": f"<sql for {region}>"}))
    results[region] = sum(row["revenue"] for row in rows)

# 프로그래밍 방식으로 결과 처리
top_region = max(results.items(), key=lambda x: x[1])
print(f"Top region: {top_region[0]} with ${top_region[1]:,} in revenue")
```

이 패턴은:

* 모델 왕복 횟수를 N(지역당 1회)에서 1로 줄입니다
* Claude에게 반환하기 전에 대규모 결과 집합을 프로그래매틱하게 처리합니다
* 원시 데이터 대신 집계된 결론만 반환하여 토큰을 절약합니다

### 조기 종료

Claude는 성공 기준이 충족되는 즉시 처리를 중단할 수 있습니다:

```python
endpoints = ["us-east", "eu-west", "apac"]
for endpoint in endpoints:
    status = await check_health({"endpoint": endpoint})
    if status == "healthy":
        print(f"Found healthy endpoint: {endpoint}")
        break  # Stop early, don't check remaining
```

### 조건부 도구 선택

```python
path = "/tmp/example.txt"
file_info = json.loads(await get_file_info({"path": path}))
if file_info["size"] < 10000:
    content = await read_full_file({"path": path})
else:
    content = await read_file_summary({"path": path})
print(content)
```

### 데이터 필터링

```python
server_id = "srv-01"
log_text = await fetch_logs({"server_id": server_id})
errors = [line for line in log_text.splitlines() if "ERROR" in line]
print(f"Found {len(errors)} errors")
for error in errors[-10:]:  # Only return last 10 errors
    print(error)
```

## 응답 형식

### 프로그래매틱 도구 호출

코드 실행이 도구를 호출할 때:

```json
{
  "type": "tool_use",
  "id": "toolu_abc123",
  "name": "query_database",
  "input": { "sql": "<sql>" },
  "caller": {
    "type": "code_execution_20260120",
    "tool_id": "srvtoolu_xyz789"
  }
}
```

### 도구 결과 처리

도구 결과는 실행 중인 코드로 다시 전달됩니다:

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_abc123",
      "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000, \"orders\": 23}, {\"customer_id\": \"C2\", \"revenue\": 38000, \"orders\": 18}, ...]"
    }
  ]
}
```

### 코드 실행 완료

모든 도구 호출이 충족되고 코드가 완료되면:

```json
{
  "type": "code_execution_tool_result",
  "tool_use_id": "srvtoolu_xyz789",
  "content": {
    "type": "code_execution_result",
    "stdout": "Analysis complete. Top 5 customers identified from 847 total records.",
    "stderr": "",
    "return_code": 0,
    "content": []
  }
}
```

## 오류 처리

### 일반적인 오류

| 오류                                         | 나타나는 위치                                                 | 설명                                                              | 해결 방법                                                                                                          |
| ------------------------------------------ | ------------------------------------------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `invalid_tool_input`                       | 응답의 `code_execution_tool_result` 오류 블록에 있는 `error_code` | 코드 실행 도구에 잘못된 매개변수가 전달되었습니다                                     | [코드 실행 도구 오류](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/code-execution-tool#errors)를 참조하세요 |
| `invalid_request_error` (`tool_choice` 관련) | HTTP 400 오류 응답                                          | `tool_choice`가 `allowed_callers`에 `"direct"`가 포함되지 않은 도구를 지정합니다 | 해당 도구의 `allowed_callers`에 `"direct"`를 추가하거나, `tool_choice`에서 도구를 제거하고 Claude가 코드에서 호출하도록 하세요                   |

### 도구 호출 중 컨테이너 만료

도구 결과가 약 4분 이내에 도착하지 않으면, 대기 중인 호출이 Claude의 실행 중인 코드 내부에서 `TimeoutError`를 발생시킵니다. Claude는 `stderr`에서 오류를 확인하고 일반적으로 호출을 재시도합니다:

```json
{
  "type": "code_execution_tool_result",
  "tool_use_id": "srvtoolu_abc123",
  "content": {
    "type": "code_execution_result",
    "stdout": "",
    "stderr": "TimeoutError: Calling tool ['query_database'] timed out (no response after 270s).",
    "return_code": 0,
    "content": []
  }
}
```

타임아웃을 방지하려면:

* 응답의 `expires_at` 필드를 모니터링하세요
* 도구 실행에 타임아웃을 구현하세요
* 긴 작업을 더 작은 단위로 나누는 것을 고려하세요

### 도구 실행 오류

도구가 오류를 반환하는 경우:

```json
{
  "type": "tool_result",
  "tool_use_id": "toolu_abc123",
  "content": "Error: Query timeout - table lock exceeded 30 seconds"
}
```

Claude의 코드는 이 오류를 받아 적절하게 처리할 수 있습니다.

## 제약 사항 및 제한

### 기능 비호환성

* **구조화된 출력:** `strict: true`인 도구는 프로그래매틱 호출에서 지원되지 않습니다
* **도구 선택:** `tool_choice`를 통해 특정 도구의 프로그래매틱 호출을 강제할 수 없습니다
* **병렬 도구 사용:** `disable_parallel_tool_use: true`는 프로그래매틱 호출에서 지원되지 않습니다

### 입력 스키마 제한

`input_schema`에 재귀적 `$ref`(자기 자신을 참조하는 스키마와 같은 참조 순환)가 포함된 사용자 정의 도구는 프로그래매틱 호출을 활성화할 수 없습니다. 이러한 도구의 `allowed_callers`에 코드 실행 도구 버전을 포함하면 요청이 `400 invalid_request_error`로 실패하며, 메시지에 `Circular $ref detected`가 포함됩니다. 동일한 스키마는 직접 도구 호출에서는 허용됩니다.

이를 해결하려면 다음 중 하나를 수행하세요:

* `allowed_callers`를 생략하거나(`["direct"]`로 설정하여) 도구를 직접 호출 전용으로 유지하세요. 동일한 요청의 다른 도구는 여전히 프로그래매틱 호출을 사용할 수 있습니다.
* 스키마에서 순환을 제거하세요. 예를 들어, 재귀를 고정된 깊이로 펼치고 더 깊은 중첩은 가장 안쪽 수준의 `description`에 설명하거나, 재귀 속성을 예상 형태를 `description`에서 설명하는 일반 `{"type": "object"}`로 대체하세요.

### 도구 제한

다음 도구는 프로그래매틱하게 호출할 수 없습니다:

* [MCP 커넥터](https://platform.claude.com/docs/ko/agents-and-tools/mcp-connector)가 제공하는 도구
* [컴퓨터 사용](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/computer-use-tool) 및 [브라우저 사용](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/browser-use-tool) 도구 세트(`computer_toolset_20260801` 및 `browser_toolset_20260801`). 이들의 `allowed_callers` 필드는 `"direct"`만 허용합니다

### 메시지 형식 제한

프로그래매틱 도구 호출에 응답할 때는 엄격한 형식 요구 사항이 있습니다:

**도구 결과만 포함된 응답:** 결과를 기다리는 대기 중인 프로그래매틱 도구 호출이 있는 경우, 응답 메시지에는 **오직** `tool_result` 블록만 포함되어야 합니다. 도구 결과 뒤에라도 텍스트 콘텐츠를 포함할 수 없습니다.

잘못된 예 - 프로그래매틱 도구 호출에 응답할 때 텍스트를 포함할 수 없습니다:

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01",
      "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"
    },
    { "type": "text", "text": "What should I do next?" }
  ]
}
```

올바른 예 - 프로그래매틱 도구 호출에 응답할 때는 도구 결과만 포함합니다:

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01",
      "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"
    }
  ]
}
```

이 제한은 프로그래매틱(코드 실행) 도구 호출에 응답할 때만 적용됩니다. 일반 클라이언트 측 도구 호출의 경우 도구 결과 뒤에 텍스트 콘텐츠를 포함할 수 있습니다.

**텍스트 전용 도구 결과 콘텐츠:** 프로그래매틱 호출에 응답하는 각 `tool_result`의 `content`는 문자열 또는 `text` 블록이어야 합니다. 이미지, 문서 및 기타 콘텐츠 블록 유형은 거부됩니다.

### 속도 제한

프로그래매틱 도구 호출은 일반 도구 호출과 동일한 속도 제한이 적용됩니다. 코드 실행에서의 각 도구 호출은 별도의 호출로 계산됩니다.

### 사용 전 도구 결과 검증

프로그래매틱하게 호출될 사용자 정의 도구를 구현할 때:

* **도구 결과는 문자열로 반환됩니다:** 실행 환경에서 처리될 수 있는 코드 스니펫이나 실행 가능한 명령을 포함하여 모든 콘텐츠를 담을 수 있습니다.
* **외부 도구 결과를 검증하세요:** 도구가 외부 소스의 데이터를 반환하거나 사용자 입력을 받는 경우, 출력이 코드로 해석되거나 실행될 때의 코드 인젝션 위험에 유의하세요.

## 토큰 효율성

프로그래매틱 도구 호출은 세 가지 방식으로 토큰 소비를 줄입니다:

* **프로그래매틱 호출의 도구 결과는 Claude의 컨텍스트에 추가되지 않습니다** - 최종 코드 출력만 추가됩니다
* **중간 처리는 코드에서 이루어집니다** - 필터링, 집계 및 기타 변환은 모델 토큰을 소비하지 않습니다
* **하나의 코드 실행에서 여러 도구 호출** - 별도의 모델 턴에 비해 오버헤드가 줄어듭니다

예를 들어, 10개의 도구를 직접 호출하면 프로그래매틱하게 호출하고 요약을 반환하는 것보다 약 10배의 토큰을 사용합니다.

프로덕션 Claude 모델에 대한 Anthropic의 내부 평가에서:

* 75개 도구를 사용하는 프로젝트 관리 에이전트 벤치마크에서, 프로그래매틱 도구 호출을 활성화하면 작업 정확도 변화 없이 청구되는 입력 토큰이 약 38% 감소했습니다.
* 각 턴에서 한두 번의 순차적 도구 호출을 수행하는 [τ²-bench](https://arxiv.org/abs/2506.07982)(항공, 소매, 통신 도메인)에서는 프로그래매틱 도구 호출이 점수에 변화를 주지 않았고 비용은 약 8% 더 들었습니다. 순차적 단일 호출 워크플로는 이점을 얻지 못합니다.
* 프로덕션 API 트래픽 전반에서, `tools` 배열에 10\~49개의 도구 정의가 포함된 요청은 프로그래매틱 도구 호출을 활성화했을 때 일반적으로 20%\~40%의 토큰 절감을 보입니다.

실제 절감량은 워크로드 형태에 따라 다릅니다. [프로그래매틱 호출을 사용해야 하는 경우](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/programmatic-tool-calling#when-to-use-programmatic-calling)를 참조하세요.

## 사용량 및 가격

프로그래매틱 도구 호출은 코드 실행과 동일한 가격을 사용합니다. 자세한 내용은 [코드 실행 가격](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/code-execution-tool#usage-and-pricing)을 참조하세요.

<Note>
  프로그래매틱 도구 호출의 토큰 계산: 프로그래매틱 호출의 도구 결과는 입력/출력 토큰 사용량에 포함되지 않습니다. 최종 코드 실행 결과와 Claude의 응답만 계산됩니다.
</Note>

## 모범 사례

### 도구 설계

* **자세한 출력 설명을 제공하세요:** Claude가 코드에서 도구 결과를 역직렬화하므로 형식(JSON 구조 및 필드 유형)을 문서화하세요
* **구조화된 데이터를 반환하세요:** JSON 또는 기타 기계 판독 가능 형식이 프로그래매틱 처리에 가장 적합합니다
* **응답을 간결하게 유지하세요:** 처리 오버헤드를 최소화하기 위해 필요한 데이터만 반환하세요

### 프로그래매틱 호출을 사용해야 하는 경우

프로그래매틱 도구 호출은 작은 고정 오버헤드(컨테이너 시작, 스크립트 생성)를 도구 결과 토큰과 모델 왕복에서의 큰 절감과 교환합니다. 이 교환이 이득이 되는지는 워크로드 형태에 따라 다릅니다.

**적합한 경우:**

* 많은 항목에 걸친 팬아웃 또는 병렬 작업(예: 50개 엔드포인트 확인 또는 20개 레코드 조회)
* Claude의 컨텍스트에 도달하기 전에 필터링, 집계 또는 요약할 수 있는 대용량 도구 결과
* 반복적인 쿼리와 결과 필터링이 워크플로를 지배하는 에이전트 검색 및 검색(retrieval)

**적합하지 않은 경우:**

* 각 호출이 이전 결과에 대한 Claude의 추론에 의존하는 엄격히 순차적인 워크플로. 이 경우 스크립트가 모델 왕복을 건너뛸 수 없기 때문입니다
* 응답이 작은 소수의 도구 호출, 특히 대화의 첫 번째 턴에서는 컨테이너 및 스크립트 오버헤드가 절감량을 초과할 수 있습니다
* 호출 사이에 즉각적인 사용자 피드백이 필요한 도구

확실하지 않다면, 광범위하게 활성화하기 전에 트래픽의 대표 샘플에서 `allowed_callers`를 사용한 경우와 사용하지 않은 경우의 청구 입력 토큰을 측정하세요.

### 성능 최적화

* 상태를 유지하기 위해 여러 관련 요청을 할 때 **컨테이너를 재사용하세요**
* 가능하면 단일 코드 실행에서 **유사한 작업을 배치 처리하세요**

## 문제 해결

### 일반적인 문제

**`tool_choice` 설정 시 `invalid_request_error`**

* `tool_choice`는 `allowed_callers`에 `"direct"`가 없는 도구를 지정할 수 없습니다. 해당 도구의 `allowed_callers`에 `"direct"`를 추가하거나, `tool_choice`에서 도구를 제거하고 Claude가 코드에서 호출하도록 하세요.

**컨테이너 만료**

* 일시 중지된 응답의 `expires_at` 타임스탬프보다 충분히 일찍 각 프로그래매틱 도구 호출에 응답하세요. Claude의 코드는 약 4분 후에 결과 대기를 중단하며, 유휴 컨테이너는 현재 약 5분 후에 회수됩니다.
* 더 빠른 도구 실행 구현을 고려하세요

**도구 결과가 올바르게 파싱되지 않음**

* 도구가 Claude가 역직렬화할 수 있는 문자열 데이터를 반환하는지 확인하세요
* 도구 설명에 명확한 출력 형식 문서를 제공하세요

### 디버깅 팁

1. 흐름을 추적하기 위해 **모든 도구 호출과 결과를 로깅하세요**
2. 프로그래매틱 호출을 확인하기 위해 **`caller` 필드를 확인하세요**
3. 적절한 재사용을 보장하기 위해 **컨테이너 ID를 모니터링하세요**
4. 프로그래매틱 호출을 활성화하기 전에 **도구를 독립적으로 테스트하세요**

## 프로그래매틱 도구 호출이 효과적인 이유

Claude는 대량의 코드로 학습되었으므로, 도구를 호출 가능한 Python 함수로 제시하면 그 강점을 활용할 수 있습니다:

* **도구 조합:** 연쇄 호출, 루프, 조건문이 일련의 모델 왕복 대신 일반적인 Python 제어 흐름이 됩니다
* **결과 처리:** Claude의 코드가 대용량 도구 출력을 필터링하고 집계하거나 파일에 기록하며, 최종 출력만 컨텍스트 윈도우에 들어갑니다
* **지연 시간:** 하나의 코드 실행 내 도구 호출 사이에 모델이 다시 샘플링되지 않습니다

## 대안 구현

프로그래매틱 도구 호출은 자체 인프라에서도 구현할 수 있는 일반화 가능한 패턴입니다. 접근 방식을 비교하면 다음과 같습니다:

### 클라이언트 측 직접 실행

Claude에게 코드 실행 도구를 제공하고 해당 환경에서 사용 가능한 함수를 설명합니다. Claude가 코드로 도구를 호출하면 애플리케이션이 해당 함수가 정의된 로컬에서 이를 실행합니다.

**장점:**

* 애플리케이션 재설계가 최소화됩니다
* 환경과 지침에 대한 완전한 제어

**단점:**

* 샌드박스 외부에서 신뢰할 수 없는 코드를 실행합니다
* 도구 호출이 코드 인젝션의 경로가 될 수 있습니다

**사용 시기:** 애플리케이션이 임의의 코드를 안전하게 실행할 수 있고, 가장 작은 구현을 원하며, Anthropic의 관리형 제품이 요구 사항에 맞지 않는 경우.

### 자체 관리형 샌드박스 실행

Claude의 관점에서는 동일한 접근 방식이지만, 코드가 보안 제한(예: 네트워크 송신 차단)이 있는 샌드박스 컨테이너에서 실행됩니다. 도구에 외부 리소스가 필요한 경우 샌드박스 외부에서 도구 호출을 실행하기 위한 프로토콜이 필요합니다.

**장점:**

* 자체 인프라에서 안전한 프로그래매틱 도구 호출
* 실행 환경에 대한 완전한 제어

**단점:**

* 구축 및 유지 관리가 복잡합니다
* 인프라와 프로세스 간 통신을 모두 관리해야 합니다

**사용 시기:** 보안이 중요하고 Anthropic의 관리형 솔루션이 요구 사항에 맞지 않는 경우.

### Anthropic 관리형 실행

Anthropic의 프로그래매틱 도구 호출은 Claude에 맞게 조정된 독자적인 Python 환경을 갖춘 샌드박스 실행의 관리형 버전입니다. Anthropic이 컨테이너 관리, 코드 실행 및 안전한 도구 호출 통신을 처리합니다.

**장점:**

* 기본적으로 안전하고 보안이 유지됩니다
* 실행할 인프라 없이 도구 정의만으로 활성화됩니다
* Claude에 최적화된 환경과 지침

Claude API, [Claude Platform on AWS](https://platform.claude.com/docs/ko/build-with-claude/claude-platform-on-aws) 또는 [Microsoft Foundry](https://platform.claude.com/docs/ko/build-with-claude/claude-in-microsoft-foundry)를 사용하는 경우 Anthropic의 관리형 솔루션 사용을 고려하세요. Microsoft Foundry에서 프로그래매틱 도구 호출을 사용하려면 [Hosted on Anthropic 배포](https://platform.claude.com/docs/ko/build-with-claude/claude-in-microsoft-foundry#additional-features-not-supported-when-hosted-on-azure)가 필요합니다.

## 데이터 보존

프로그래매틱 도구 호출은 코드 실행 인프라를 기반으로 구축되었으며 동일한 샌드박스 컨테이너를 사용합니다. 실행 아티팩트 및 출력을 포함한 컨테이너 데이터는 최대 30일 동안 보존됩니다.

모든 기능에 대한 ZDR 적격성은 [API 및 데이터 보존](https://platform.claude.com/docs/ko/manage-claude/api-and-data-retention)을 참조하세요.

## 다음 단계

<CardGroup cols={2}>
  <Card title="세분화된 도구 스트리밍" icon="bolt" href="https://platform.claude.com/docs/ko/agents-and-tools/tool-use/fine-grained-tool-streaming">
    지연 시간에 민감한 애플리케이션을 위해 서버 측 JSON 버퍼링 없이 도구 입력을 스트리밍합니다.
  </Card>

  <Card title="코드 실행 도구" icon="code" href="https://platform.claude.com/docs/ko/agents-and-tools/tool-use/code-execution-tool">
    샌드박스 컨테이너에서 Python 및 bash 코드를 실행하여 데이터를 분석하고, 파일을 생성하고, 솔루션을 반복 개선합니다.
  </Card>

  <Card title="Claude와 함께하는 도구 사용" icon="wrench" href="https://platform.claude.com/docs/ko/agents-and-tools/tool-use/overview">
    Claude를 외부 도구 및 API에 연결합니다. 도구가 어디서 실행되는지, Claude가 언제 호출하는지, 어떤 도구가 작업에 적합한지 확인하세요.
  </Card>

  <Card title="도구 정의" icon="hammer" href="https://platform.claude.com/docs/ko/agents-and-tools/tool-use/define-tools">
    도구 스키마를 지정하고, 효과적인 설명을 작성하고, Claude가 도구를 호출하는 시점을 제어합니다.
  </Card>
</CardGroup>
