---
title: Программный вызов инструментов
url: https://platform.claude.com/docs/ru/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/ru/build-with-claude/claude-in-microsoft-foundry) программный вызов инструментов требует [развёртывания Hosted on Anthropic](https://platform.claude.com/docs/ru/build-with-claude/claude-in-microsoft-foundry#additional-features-not-supported-when-hosted-on-azure).
  details:
    - Программный вызов инструментов требует инструмента выполнения кода с [версией инструмента](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/code-execution-tool#tool-versions) `code_execution_20260120` или более поздней.
    - Claude Haiku 4.5 принимает версии инструмента `code_execution_20260120` и более поздние, но не поддерживает программный вызов инструментов.
---

«Programmatic tool calling» (программный вызов инструментов) позволяет Claude писать код, который программно вызывает ваши инструменты внутри контейнера [выполнения кода](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/code-execution-tool), вместо того чтобы требовать обращения к модели для каждого вызова инструмента. Это снижает «latency» (задержку) в рабочих процессах с несколькими инструментами и уменьшает расход токенов, позволяя Claude фильтровать или обрабатывать данные до того, как они попадут в «context window» (контекстное окно) модели. В бенчмарках агентного поиска, таких как [BrowseComp](https://arxiv.org/abs/2504.12516) и [DeepSearchQA](https://github.com/google-deepmind/deepsearchqa), которые проверяют многошаговое веб-исследование и сложный поиск информации, добавление программного вызова инструментов поверх базовых инструментов поиска улучшило результаты в среднем на 11% при использовании на 24% меньше входных токенов (см. [Improved web search with dynamic filtering](https://claude.com/blog/improved-web-search-with-dynamic-filtering)).

Рассмотрим проверку соблюдения бюджета для 20 сотрудников: традиционный подход требует 20 отдельных обращений к модели, попутно затягивая в контекст тысячи строк расходов. При программном вызове инструментов один скрипт выполняет все 20 запросов, фильтрует результаты и возвращает только тех сотрудников, которые превысили свои лимиты, сокращая объём данных, над которыми Claude нужно рассуждать, с сотен килобайт до нескольких строк.

<Tip>
  Более подробный разбор затрат на инференс и контекст, которые устраняет программный вызов инструментов, см. в статье [Advanced tool use](https://www.anthropic.com/engineering/advanced-tool-use).
</Tip>

Программный вызов инструментов требует [инструмента выполнения кода](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/code-execution-tool) с версией инструмента `code_execution_20260120` или более поздней. Чтобы до отправки запроса проверить, поддерживает ли модель программный вызов инструментов, прочитайте её значение `capabilities.code_execution.supported` из Models API. Это поле описано в разделе [Использование Models API](https://platform.claude.com/docs/ru/models/overview#using-the-models-api).

## Быстрый старт

Вот пример, в котором Claude программно несколько раз запрашивает базу данных и агрегирует результаты. Добавление `allowed_callers: ["code_execution_20260120"]` в определение инструмента — это то, что делает этот инструмент вызываемым из выполнения кода (см. [Поле `allowed_callers`](https://platform.claude.com/docs/ru/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` и блоком `tool_use` для `query_database`, поле `caller` которого идентифицирует запуск выполнения кода, вызвавший его. Верните результат, как показано в [шаге 3 примера рабочего процесса](https://platform.claude.com/docs/ru/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`. Каждая функция принимает один словарь аргументов и возвращает строку: текст `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` — это `id` блока `server_tool_use` выполнения кода, который сделал вызов, поэтому вы можете сопоставить каждый программный `tool_use` с запуском выполнения кода, который его породил.

### Жизненный цикл контейнера

Программный вызов инструментов использует те же контейнеры, что и выполнение кода:

* **Создание контейнера:** для каждого запроса создаётся новый контейнер, если вы не используете существующий повторно
* **Идентификатор контейнера:** возвращается в ответах в поле `container` вместе с временной меткой `expires_at`
* **Повторное использование:** передайте идентификатор контейнера обратно в следующем запросе, чтобы сохранить состояние. Пока программный вызов инструмента ожидает вашего результата, идентификатор контейнера в этом запросе обязателен, а не опционален: API отклоняет запрос без него.
* **Истечение срока:** `expires_at` сообщает, сколько времени осталось у контейнера. Простаивающие контейнеры в настоящее время освобождаются примерно через 5 минут, и ни один контейнер нельзя использовать повторно более чем через 30 дней после его создания.

<Warning>
  Пока код Claude ожидает результата программного вызова инструмента, ожидающий вызов завершается по тайм-ауту примерно через 4 минуты и вызывает `TimeoutError` внутри кода. Возвращайте каждый результат инструмента задолго до временной метки `expires_at` в приостановленном ответе. См. [Истечение срока контейнера во время вызова инструмента](https://platform.claude.com/docs/ru/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/ru/agents-and-tools/tool-use/programmatic-tool-calling#quick-start): включите `code_execution` в список инструментов, добавьте `allowed_callers: ["code_execution_20260120"]` к любому инструменту, который вы хотите, чтобы Claude вызывал из кода, и отправьте пользовательское сообщение. Остальные шаги этого рабочего процесса используют пользовательское сообщение `"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/ru/agents-and-tools/tool-use/programmatic-tool-calling#message-formatting-restrictions).
* Передайте идентификатор `container` из приостановленного ответа. API отклоняет продолжение, в котором есть ожидающие программные вызовы инструментов, но нет идентификатора контейнера.
* Отправьте тот же массив `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` и `caller` каждого блока `tool_use`, чтобы различить эти два случая: ответ, который приостанавливается в ожидании вас, имеет `stop_reason: "tool_use"` и блок `tool_use`, в `caller` которого указана версия выполнения кода, и вы повторяете шаг 3 с `tool_result` для каждого ожидающего программного вызова в одном пользовательском сообщении.

### Шаг 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
* Программно обрабатывает большие наборы результатов перед возвратом к 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`                        | `error_code` в блоке ошибки `code_execution_tool_result` в ответе | Инструменту выполнения кода были переданы недопустимые параметры                      | См. [ошибки инструмента выполнения кода](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/code-execution-tool#errors)               |
| `invalid_request_error` (для `tool_choice`) | Ответ с ошибкой HTTP 400                                          | `tool_choice` указывает инструмент, `allowed_callers` которого не включает `"direct"` | Либо добавьте `"direct"` в `allowed_callers` этого инструмента, либо удалите инструмент из `tool_choice` и позвольте Claude вызывать его из кода |

### Истечение срока контейнера во время вызова инструмента

Если результат вашего инструмента не поступает в течение примерно 4 минут, ожидающий вызов вызывает `TimeoutError` внутри выполняющегося кода Claude. 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` самого внутреннего уровня, либо замените рекурсивное свойство простым `{"type": "object"}`, `description` которого объясняет ожидаемую форму.

### Ограничения инструментов

Следующие инструменты нельзя вызывать программно:

* Инструменты, предоставляемые [коннектором MCP](https://platform.claude.com/docs/ru/agents-and-tools/mcp-connector)
* Наборы инструментов [computer use](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/computer-use-tool) и [browser use](https://platform.claude.com/docs/ru/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}]"
    }
  ]
}
```

Это ограничение применяется только при ответе на программные вызовы инструментов (из выполнения кода). Для обычных клиентских вызовов инструментов вы можете включать текстовый контент после результатов инструментов.

**Только текстовое содержимое результатов инструментов:** `content` каждого `tool_result`, отвечающего на программный вызов, должен быть строкой или блоками `text`. Изображения, документы и другие типы блоков контента отклоняются.

### Ограничения скорости

Программные вызовы инструментов подчиняются тем же «rate limits» (ограничениям скорости), что и обычные вызовы инструментов. Каждый вызов инструмента из выполнения кода считается отдельным вызовом.

### Проверяйте результаты инструментов перед использованием

При реализации пользовательских инструментов, которые будут вызываться программно:

* **Результаты инструментов возвращаются как строки:** они могут содержать любой контент, включая фрагменты кода или исполняемые команды, которые могут быть обработаны средой выполнения.
* **Проверяйте результаты внешних инструментов:** если ваш инструмент возвращает данные из внешних источников или принимает пользовательский ввод, учитывайте риски внедрения кода, если вывод будет интерпретироваться или выполняться как код.

## Эффективность по токенам

Программный вызов инструментов снижает расход токенов тремя способами:

* **Результаты инструментов из программных вызовов не добавляются в контекст Claude** — добавляется только итоговый вывод кода
* **Промежуточная обработка происходит в коде** — фильтрация, агрегирование и другие преобразования не расходуют токены модели
* **Несколько вызовов инструментов в одном выполнении кода** — снижает накладные расходы по сравнению с отдельными ходами модели

Например, прямой вызов 10 инструментов использует примерно в 10 раз больше токенов, чем их программный вызов с возвратом сводки.

Во внутренних оценках Anthropic на продакшн-модели Claude:

* В бенчмарке агента управления проектами с 75 инструментами включение программного вызова инструментов сократило тарифицируемые входные токены примерно на 38% без изменения точности выполнения задач.
* В [τ²-bench](https://arxiv.org/abs/2506.07982) (домены авиаперевозок, розничной торговли и телекоммуникаций), где каждый ход делает один или два последовательных вызова инструментов, программный вызов инструментов оставил оценки без изменений и стоил примерно на 8% дороже. Последовательные рабочие процессы с одиночными вызовами не получают выгоды.
* В продакшн-трафике API запросы, массив `tools` которых содержит от 10 до 49 определений инструментов, демонстрируют типичную экономию токенов от 20% до 40% при включённом программном вызове инструментов.

Фактическая экономия зависит от формы рабочей нагрузки. См. [Когда использовать программный вызов](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/programmatic-tool-calling#when-to-use-programmatic-calling).

## Использование и цены

Программный вызов инструментов использует те же цены, что и выполнение кода. Подробности см. в разделе [цены на выполнение кода](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/code-execution-tool#usage-and-pricing).

<Note>
  Подсчёт токенов для программных вызовов инструментов: результаты инструментов из программных вызовов не учитываются в вашем использовании входных/выходных токенов. Учитываются только итоговый результат выполнения кода и ответ Claude.
</Note>

## Лучшие практики

### Проектирование инструментов

* **Предоставляйте подробные описания вывода:** поскольку Claude десериализует результаты инструментов в коде, документируйте формат (структуру JSON и типы полей)
* **Возвращайте структурированные данные:** JSON или другие машиночитаемые форматы лучше всего подходят для программной обработки
* **Делайте ответы краткими:** возвращайте только необходимые данные, чтобы минимизировать накладные расходы на обработку

### Когда использовать программный вызов

Программный вызов инструментов обменивает небольшие фиксированные накладные расходы (запуск контейнера, генерация скрипта) на большую экономию токенов результатов инструментов и обращений к модели. Окупится ли этот обмен, зависит от формы рабочей нагрузки.

**Хорошо подходит:**

* Операции разветвления или параллельные операции над множеством элементов (например, проверка 50 эндпоинтов или поиск 20 записей)
* Большие результаты инструментов, которые можно отфильтровать, агрегировать или обобщить до попадания в контекст Claude
* Агентный поиск и извлечение информации, где в рабочем процессе преобладают итеративные запросы и фильтрация результатов

**Плохо подходит:**

* Строго последовательные рабочие процессы, где каждый вызов зависит от рассуждений Claude над предыдущим результатом, поскольку в этом случае скрипт не может пропустить обращение к модели
* Небольшое количество вызовов инструментов с небольшими ответами, особенно на первом ходе разговора, где накладные расходы на контейнер и скрипт могут превысить экономию
* Инструменты, требующие немедленной обратной связи от пользователя между вызовами

Если вы не уверены, измерьте тарифицируемые входные токены с `allowed_callers` и без него на репрезентативной выборке вашего трафика, прежде чем включать его широко.

### Оптимизация производительности

* **Повторно используйте контейнеры** при выполнении нескольких связанных запросов для сохранения состояния
* **Объединяйте похожие операции** в одно выполнение кода, когда это возможно

## Устранение неполадок

### Распространённые проблемы

**`invalid_request_error` при установке `tool_choice`**

* `tool_choice` не может указывать инструмент, в `allowed_callers` которого отсутствует `"direct"`. Либо добавьте `"direct"` в `allowed_callers` этого инструмента, либо удалите инструмент из `tool_choice` и позвольте Claude вызывать его из кода.

**Истечение срока контейнера**

* Отвечайте на каждый программный вызов инструмента задолго до временной метки `expires_at` приостановленного ответа. Код Claude перестаёт ждать результат примерно через 4 минуты, а простаивающие контейнеры в настоящее время освобождаются примерно через 5 минут.
* Рассмотрите реализацию более быстрого выполнения инструментов

**Результат инструмента разобран неправильно**

* Убедитесь, что ваш инструмент возвращает строковые данные, которые Claude может десериализовать
* Предоставьте чёткую документацию формата вывода в описании инструмента

### Советы по отладке

1. **Логируйте все вызовы инструментов и результаты**, чтобы отслеживать поток
2. **Проверяйте поле `caller`**, чтобы подтвердить программный вызов
3. **Отслеживайте идентификаторы контейнеров**, чтобы обеспечить правильное повторное использование
4. **Тестируйте инструменты независимо** перед включением программного вызова

## Почему программный вызов инструментов работает

Claude обучен на больших объёмах кода, поэтому представление инструментов в виде вызываемых функций Python позволяет ему использовать эту сильную сторону:

* **Композиция инструментов:** цепочки вызовов, циклы и условия — это обычный поток управления Python вместо серии обращений к модели
* **Обработка результатов:** код Claude фильтрует и агрегирует большие выводы инструментов или записывает их в файлы, и только итоговый вывод попадает в контекстное окно
* **Задержка:** модель не сэмплируется повторно между вызовами инструментов внутри одного выполнения кода

## Альтернативные реализации

Программный вызов инструментов — это обобщаемый паттерн, который также можно реализовать на собственной инфраструктуре. Вот как соотносятся подходы:

### Прямое выполнение на стороне клиента

Предоставьте Claude инструмент выполнения кода и опишите, какие функции доступны в этой среде. Когда Claude вызывает инструмент с кодом, ваше приложение выполняет его локально там, где определены эти функции.

**Преимущества:**

* Минимальная перестройка архитектуры вашего приложения
* Полный контроль над средой и инструкциями

**Недостатки:**

* Выполняет недоверенный код вне песочницы
* Вызовы инструментов могут быть векторами для внедрения кода

**Используйте, когда:** ваше приложение может безопасно выполнять произвольный код, вам нужна минимальная реализация, а управляемое предложение Anthropic не соответствует вашим потребностям.

### Самостоятельно управляемое изолированное выполнение

Тот же подход с точки зрения Claude, но код выполняется в изолированном контейнере с ограничениями безопасности (например, без исходящего сетевого трафика). Если вашим инструментам требуются внешние ресурсы, вам понадобится протокол для выполнения вызовов инструментов вне песочницы.

**Преимущества:**

* Безопасный программный вызов инструментов на собственной инфраструктуре
* Полный контроль над средой выполнения

**Недостатки:**

* Сложно создавать и поддерживать
* Требует управления как инфраструктурой, так и межпроцессным взаимодействием

**Используйте, когда:** безопасность критически важна, а управляемое решение Anthropic не соответствует вашим требованиям.

### Выполнение под управлением Anthropic

Программный вызов инструментов от Anthropic — это управляемая версия изолированного выполнения со специализированной средой Python, настроенной для Claude. Anthropic берёт на себя управление контейнерами, выполнение кода и безопасную коммуникацию при вызове инструментов.

**Преимущества:**

* Безопасно и защищено по умолчанию
* Включается определением инструмента, без необходимости запускать инфраструктуру
* Среда и инструкции оптимизированы для Claude

Рассмотрите использование управляемого решения Anthropic, если вы используете Claude API, [Claude Platform on AWS](https://platform.claude.com/docs/ru/build-with-claude/claude-platform-on-aws) или [Microsoft Foundry](https://platform.claude.com/docs/ru/build-with-claude/claude-in-microsoft-foundry). В Microsoft Foundry для программного вызова инструментов требуется [развёртывание Hosted on Anthropic](https://platform.claude.com/docs/ru/build-with-claude/claude-in-microsoft-foundry#additional-features-not-supported-when-hosted-on-azure).

## Хранение данных

Программный вызов инструментов построен на инфраструктуре выполнения кода и использует те же контейнеры-песочницы. Данные контейнера, включая артефакты выполнения и выводы, хранятся до 30 дней.

Информацию о соответствии требованиям ZDR для всех функций см. в разделе [API и хранение данных](https://platform.claude.com/docs/ru/manage-claude/api-and-data-retention).

## Следующие шаги

<CardGroup cols={2}>
  <Card title="Детализированная потоковая передача инструментов" icon="bolt" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/fine-grained-tool-streaming">
    Передавайте входные данные инструментов потоком без буферизации JSON на стороне сервера для приложений, чувствительных к задержке.
  </Card>

  <Card title="Инструмент выполнения кода" icon="code" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/code-execution-tool">
    Запускайте код на Python и bash в изолированном контейнере для анализа данных, генерации файлов и итеративной работы над решениями.
  </Card>

  <Card title="Использование инструментов с Claude" icon="wrench" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/overview">
    Подключите Claude к внешним инструментам и API. Узнайте, где выполняются инструменты, когда Claude их вызывает и какой инструмент подходит для вашей задачи.
  </Card>

  <Card title="Определение инструментов" icon="hammer" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/define-tools">
    Задавайте схемы инструментов, пишите эффективные описания и управляйте тем, когда Claude вызывает ваши инструменты.
  </Card>
</CardGroup>
