Programmatic tool calling (программный вызов инструментов) позволяет Claude писать код, который программно вызывает ваши инструменты внутри контейнера выполнения кода, вместо того чтобы требовать обращения к модели для каждого вызова инструмента. Это снижает задержку для рабочих процессов с несколькими инструментами и уменьшает потребление токенов, позволяя Claude фильтровать или обрабатывать данные до того, как они попадут в контекстное окно модели. На бенчмарках агентного поиска, таких как BrowseComp и DeepSearchQA, которые тестируют многошаговое веб-исследование и сложное извлечение информации, добавление программного вызова инструментов поверх базовых инструментов поиска улучшило производительность в среднем на 11% при использовании на 24% меньше входных токенов (см. Improved web search with dynamic filtering).
Рассмотрим проверку соблюдения бюджета для 20 сотрудников: традиционный подход требует 20 отдельных обращений к модели, попутно загружая тысячи строк расходов в контекст. С программным вызовом инструментов один скрипт выполняет все 20 запросов, фильтрует результаты и возвращает только тех сотрудников, которые превысили свои лимиты, сокращая объём данных, над которыми Claude должен рассуждать, с сотен килобайт до нескольких строк.
Программный вызов инструментов требует code_execution_20260120 или более поздней версии, которая поддерживается следующими моделями:
| Модель |
|---|
| Claude Fable 5 () |
| Claude Mythos 5 () |
| Claude Opus 5 () |
| Claude Opus 4.8 () |
| Claude Opus 4.7 () |
| Claude Opus 4.6 () |
| Claude Sonnet 5 () |
| Claude Sonnet 4.6 () |
| Claude Opus 4.5 () |
| Claude Sonnet 4.5 () |
Полную матрицу версий инструмента выполнения кода см. в таблице совместимости моделей инструмента выполнения кода. Программный вызов инструментов доступен в Claude API, Claude Platform на AWS и Microsoft Foundry. В Microsoft Foundry программный вызов инструментов требует развёртывания Hosted on Anthropic. В настоящее время он недоступен в Amazon Bedrock и Google Cloud.
Вот пример, где Claude программно запрашивает базу данных несколько раз и агрегирует результаты:
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-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)Ответ останавливается с stop_reason: "tool_use", идентификатором container и блоком tool_use для query_database, чьё поле caller идентифицирует запуск выполнения кода, который его вызвал. Верните результат, как показано в Шаге 3 примера рабочего процесса, чтобы код мог завершиться.
Когда вы настраиваете инструмент так, чтобы его можно было вызывать из выполнения кода, и Claude решает использовать этот инструмент:
tool_useЭтот подход особенно полезен для:
allowed_callersПоле allowed_callers указывает, какие контексты могут вызывать инструмент:
{
"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 независимо от того, какую версию объявил запрос.
caller в ответахКаждый блок использования инструмента включает поле caller, указывающее, как он был вызван:
Прямой вызов (традиционное использование инструментов):
{
"type": "tool_use",
"id": "toolu_abc123",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": { "type": "direct" }
}Программный вызов:
{
"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_atexpires_at сообщает вам, сколько времени осталось у контейнера. Неактивные контейнеры в настоящее время освобождаются примерно через 5 минут, и ни один контейнер не может быть переиспользован более чем через 30 дней после его создания.Вот как работает полный поток программного вызова инструментов:
Отправьте запрос с выполнением кода и инструментом, который разрешает программный вызов. Чтобы включить программный вызов, добавьте поле allowed_callers в определение вашего инструмента.
Форма запроса идентична примеру из Быстрого старта: включите code_execution в ваш список инструментов, добавьте allowed_callers: ["code_execution_20260120"] к любому инструменту, который вы хотите, чтобы Claude вызывал из кода, и отправьте ваше пользовательское сообщение. Остальные шаги в этом рабочем процессе используют пользовательское сообщение "Query customer purchase history from the last quarter and identify our top 5 customers by revenue".
Claude пишет код, который вызывает ваш инструмент. API приостанавливается и возвращает:
{
"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"
}Отправьте полную историю разговора плюс ваш результат инструмента. В этом запросе важны три детали:
tool_result. См. Ограничения форматирования сообщений.container из приостановленного ответа. API отклоняет продолжение, которое имеет ожидающие программные вызовы инструментов, но не имеет идентификатора контейнера.tools, что и в исходном запросе. Инструмент выполнения кода всё ещё должен присутствовать, чтобы приостановленный код возобновился, а инструменты, которые вы отправляете в этом запросе, — это определения, которые Claude и выполняющийся код могут использовать до конца хода.response = client.messages.create(
model="claude-opus-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=[
{"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)Код продолжается с того места, где он приостановился, и обрабатывает ваш результат. Каждый ответ-продолжение либо снова приостанавливается с дополнительными программными блоками tool_use, либо завершает выполнение кода и позволяет Claude продолжить ход (Шаг 5). Проверяйте stop_reason и поле caller каждого блока tool_use, чтобы различить эти два случая: ответ, который приостанавливается для вас, имеет stop_reason: "tool_use" и блок tool_use, чей caller называет версию выполнения кода, и вы повторяете Шаг 3 с tool_result для каждого ожидающего программного вызова в одном пользовательском сообщении.
Как только выполнение кода завершается, Claude предоставляет финальный ответ:
{
"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 может писать код, который эффективно обрабатывает несколько элементов:
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")Этот паттерн:
Claude может остановить обработку, как только критерии успеха выполнены:
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 remainingpath = "/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)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)Когда выполнение кода вызывает инструмент:
{
"type": "tool_use",
"id": "toolu_abc123",
"name": "query_database",
"input": { "sql": "<sql>" },
"caller": {
"type": "code_execution_20260120",
"tool_id": "srvtoolu_xyz789"
}
}Ваш результат инструмента передаётся обратно в выполняющийся код:
{
"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}, ...]"
}
]
}Когда все вызовы инструментов удовлетворены и код завершается:
{
"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 в ответе | Недопустимые параметры были переданы инструменту выполнения кода | См. ошибки инструмента выполнения кода |
invalid_request_error (на tool_choice) | Ответ с ошибкой HTTP 400 | tool_choice называет инструмент, чей allowed_callers не включает "direct" | Либо добавьте "direct" в allowed_callers этого инструмента, либо удалите инструмент из tool_choice и позвольте Claude вызывать его из кода |
Если ваш результат инструмента не приходит в течение примерно 4 минут, ожидающий вызов вызывает TimeoutError внутри выполняющегося кода Claude. Claude видит ошибку в stderr и обычно повторяет вызов:
{
"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 в ответахЕсли ваш инструмент возвращает ошибку:
{
"type": "tool_result",
"tool_use_id": "toolu_abc123",
"content": "Error: Query timeout - table lock exceeded 30 seconds"
}Код Claude получает эту ошибку и может обработать её соответствующим образом.
strict: true не поддерживаются с программным вызовомtool_choicedisable_parallel_tool_use: true не поддерживается с программным вызовомПользовательские инструменты, чья input_schema содержит рекурсивный $ref (цикл ссылок, например схема, которая ссылается на саму себя), не могут быть включены для программного вызова. Включение версии инструмента выполнения кода в allowed_callers для такого инструмента приводит к сбою запроса с 400 invalid_request_error, сообщение которого содержит Circular $ref detected. Та же схема принимается для прямого вызова инструмента.
Чтобы обойти это, сделайте одно из следующего:
allowed_callers (или установив его в ["direct"]). Другие инструменты в том же запросе всё ещё могут использовать программный вызов.description самого внутреннего уровня, или замените рекурсивное свойство простым {"type": "object"}, чьё description объясняет ожидаемую форму.Следующие инструменты не могут быть вызваны программно:
При ответе на программные вызовы инструментов существуют строгие требования к форматированию:
Ответы только с результатами инструментов: Если есть ожидающие программные вызовы инструментов, ожидающие результатов, ваше ответное сообщение должно содержать только блоки tool_result. Вы не можете включать какой-либо текстовый контент, даже после результатов инструментов.
Недопустимо - Нельзя включать текст при ответе на программные вызовы инструментов:
{
"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?" }
]
}Допустимо - Только результаты инструментов при ответе на программные вызовы инструментов:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01",
"content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"
}
]
}Это ограничение применяется только при ответе на программные вызовы инструментов (выполнение кода). Для обычных клиентских вызовов инструментов вы можете включать текстовый контент после результатов инструментов.
Только текстовое содержимое результата инструмента: content каждого tool_result, который отвечает на программный вызов, должен быть строкой или блоками text. Изображения, документы и другие типы блоков контента отклоняются.
Программные вызовы инструментов подчиняются тем же ограничениям скорости, что и обычные вызовы инструментов. Каждый вызов инструмента из выполнения кода считается отдельным вызовом.
При реализации пользовательских инструментов, которые будут вызываться программно:
Программный вызов инструментов сокращает потребление токенов тремя способами:
Например, прямой вызов 10 инструментов использует примерно в 10 раз больше токенов, чем их программный вызов с возвратом сводки.
Во внутренних оценках Anthropic на производственной модели Claude:
tools содержит от 10 до 49 определений инструментов, показывают типичную экономию токенов от 20% до 40% при включённом программном вызове инструментов.Фактическая экономия варьируется в зависимости от формы рабочей нагрузки. См. Когда использовать программный вызов.
Программный вызов инструментов использует те же цены, что и выполнение кода. Подробности см. в ценах на выполнение кода.
Программный вызов инструментов обменивает небольшие фиксированные накладные расходы (запуск контейнера, генерация скрипта) на большую экономию токенов результатов инструментов и обращений к модели. Окупается ли этот обмен, зависит от формы рабочей нагрузки.
Хорошо подходит:
Плохо подходит:
Если вы не уверены, измерьте оплачиваемые входные токены с allowed_callers и без него на репрезентативной выборке вашего трафика, прежде чем включать его повсеместно.
invalid_request_error при установке tool_choice
tool_choice не может называть инструмент, чей allowed_callers не включает "direct". Либо добавьте "direct" в allowed_callers этого инструмента, либо удалите инструмент из tool_choice и позвольте Claude вызывать его из кода.Истечение срока контейнера
expires_at приостановленного ответа. Код Claude перестаёт ждать результат примерно через 4 минуты, а неактивные контейнеры в настоящее время освобождаются примерно через 5 минут.Результат инструмента не разобран корректно
caller, чтобы подтвердить программный вызовClaude обучен на больших объёмах кода, поэтому представление инструментов как вызываемых функций Python позволяет ему использовать эту сильную сторону:
Программный вызов инструментов — это обобщаемый паттерн, который также может быть реализован на вашей собственной инфраструктуре. Вот как сравниваются подходы:
Предоставьте Claude инструмент выполнения кода и опишите, какие функции доступны в этой среде. Когда Claude вызывает инструмент с кодом, ваше приложение выполняет его локально там, где определены эти функции.
Преимущества:
Недостатки:
Используйте, когда: Ваше приложение может безопасно выполнять произвольный код, вы хотите минимальную реализацию, и управляемое предложение Anthropic не соответствует вашим потребностям.
Тот же подход с точки зрения Claude, но код выполняется в изолированном контейнере с ограничениями безопасности (например, без исходящего сетевого трафика). Если ваши инструменты требуют внешних ресурсов, вам понадобится протокол для выполнения вызовов инструментов вне песочницы.
Преимущества:
Недостатки:
Используйте, когда: Безопасность критична, и управляемое решение Anthropic не соответствует вашим требованиям.
Программный вызов инструментов Anthropic — это управляемая версия изолированного выполнения с продуманной средой Python, настроенной для Claude. Anthropic обрабатывает управление контейнерами, выполнение кода и безопасную коммуникацию вызовов инструментов.
Преимущества:
Рассмотрите использование управляемого решения Anthropic, если вы используете Claude API, Claude Platform на AWS или Microsoft Foundry. В Microsoft Foundry программный вызов инструментов требует развёртывания Hosted on Anthropic.
Программный вызов инструментов построен на инфраструктуре выполнения кода и использует те же контейнеры-песочницы. Данные контейнера, включая артефакты выполнения и выводы, хранятся до 30 дней.
Информацию о соответствии ZDR для всех функций см. в API и хранение данных.
Передавайте входные данные инструментов потоком без буферизации JSON на стороне сервера для приложений, чувствительных к задержке.
Запускайте код Python и bash в изолированном контейнере для анализа данных, генерации файлов и итерации над решениями.
Подключите Claude к внешним инструментам и API. Узнайте, где выполняются инструменты, когда Claude их вызывает и какой инструмент подходит для вашей задачи.
Задавайте схемы инструментов, пишите эффективные описания и управляйте тем, когда Claude вызывает ваши инструменты.
Was this page helpful?