Программный вызов инструментов
- Понять, что на самом деле происходит, когда Claude вызывает ваш инструмент изнутри песочницы — и почему ваш инструмент по-прежнему выполняется на вашей собственной машине
- Правильно включить это с помощью allowed_callers и знать, почему это не является границей безопасности
- Знать реальные цифры: что это экономит, на каких рабочих нагрузках и где обходится вам дороже
- Избегать пяти режимов отказа, которые приводят к 400-м ошибкам и TimeoutError в продакшене
Проблема, которую это решает
Классическое использование инструментов — это разговор. Claude запрашивает один вызов инструмента, вы отвечаете, весь результат попадает в контекстное окно, Claude читает его и запрашивает следующий. Двадцать поисков означают двадцать проходов инференса и двадцать сырых полезных нагрузок, навсегда оседающих в контексте.
Большая часть этой полезной нагрузки — мусор. Если вы хотите узнать, кто из двадцати сотрудников превысил свой бюджет расходов, Claude не нужны все позиции — ему нужна лишь горстка имён. Но в классическом использовании инструментов позиции должны пройти через модель, чтобы быть отфильтрованными ею.
Программный вызов инструментов инвертирует это. Claude пишет Python-скрипт, скрипт вызывает ваши инструменты в цикле, фильтрует результаты, и обратно к модели возвращается только то, что скрипт напечатал. Сырые данные вообще никогда не попадают в контекстное окно.
Что на самом деле происходит
Вот часть, которую почти все обзоры этой функции понимают неверно: ваш инструмент не выполняется внутри песочницы. Контейнер Anthropic не имеет доступа к вашей базе данных.
На самом деле происходит следующее: Python-код Claude приостанавливается на середине выполнения, API передаёт вызов обратно вам, и интерпретатор возобновляет работу, как только вы ответите:
- Он выполняется внутри контейнера code-execution. Ваши инструменты видны этому коду как асинхронные Python-функции — по одной на каждый инструмент, каждая принимает единственный словарь аргументов и возвращает строку.
- API возвращает обычный tool_use блок для query_database, точно как в классическом использовании инструментов — за исключением того, что теперь он несёт поле caller, указывающее обратно на запуск code-execution, который сделал вызов.
- Как всегда: выполните запрос, отправьте обратно tool_result блок. ID контейнера ОБЯЗАТЕЛЕН в этом ответном запросе, а не опционален — API отвергает запрос без него, потому что ему нужно найти приостановленный интерпретатор.
- Ваш результат становится возвращаемым значением того самого await-выражения. Цикл продолжается. Claude не выборочно опрашивается между этим — никакого прохода инференса, никаких токенов.
- Когда скрипт завершается, Claude получает code_execution_tool_result, содержащий stdout, stderr и return_code. Всё, что скрипт получил, но не напечатал, просто исчезает.
Поскольку функции async, Claude может распараллеливаться с помощью asyncio.gather и обращаться к десяти инструментам одновременно — то, что классическое использование инструментов может лишь приблизительно эмулировать с помощью параллельных tool-блоков.
Как на самом деле выглядит сгенерированный код Claude
import json
rows = json.loads(await query_database({"sql": "<sql>"}))
top = sorted(rows, key=lambda r: r["revenue"], reverse=True)[:5]
print(f"Top 5 customers: {top}")Обратите внимание на json.loads. Функция инструмента возвращает строку — буквальный текст tool_result, который вы отправляете обратно. Если в описании вашего инструмента не сказано "возвращает список строк как JSON-объекты", у Claude нет способа узнать, что можно десериализовать эту штуку, и он будет обрабатывать ваши данные как непрозрачный blob. Предложение о формате вывода в описании вашего инструмента перестаёт быть документацией и становится несущим кодом. Это единственная строка с наибольшим рычагом воздействия, которую вы напишете при принятии этой функции.
Как это включить
Одно поле у инструмента, который вы хотите вызывать из кода, плюс инструмент 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" } }, "required": ["sql"] },
"allowed_callers": ["code_execution_20260120"]
}allowed_callers принимает три формы:
| Значение | Смысл |
|---|---|
["direct"] | Классическое использование инструментов. Это значение по умолчанию, когда поле опущено. |
["code_execution_20260120"] | Claude направляется вызывать его только изнутри кода. |
["direct", "code_execution_20260120"] | И то, и другое. Документация советует против этого — выберите одно, чтобы Claude получал однозначный сигнал. |
Каждый tool_use блок в ответе теперь несёт caller: либо {"type": "direct"}, либо code-execution caller, чей tool_id совпадает с server_tool_use блоком, запустившим скрипт. Именно так вы атрибутируете вызов скрипту, который его сделал.
Это не граница безопасности
Документация необычно откровенна в этом вопросе, и это стоит повторить, потому что легко предположить обратное: allowed_callers контролирует то, как инструмент представлен Claude. Это не жёсткая блокировка на уровне API. Claude настоятельно направляется соблюдать это — но ваш клиент всё равно должен быть готов получить прямой tool_use для любого инструмента, который он определяет, и вы не должны использовать это поле как механизм авторизации. Авторизация принадлежит вашему обработчику инструмента, где она всегда и была.
Цифры
Собственные заявленные цифры Anthropic, чтобы вы могли судить, стоит ли эта сложность того:
- На сложных исследовательских задачах среднее использование упало с 43 588 до 27 297 токенов — сокращение на 37%.
- На бенчмарках GIA точность выросла с 46,5% до 51,2%; на внутреннем поиске знаний — с 25,6% до 28,5%. Меньше токенов и лучшие ответы, потому что модель рассуждает над выводами вместо того, чтобы тонуть в сырых полезных нагрузках.
- На бенчмарках агентного поиска (BrowseComp, DeepSearchQA) наложение программного вызова поверх базовых инструментов поиска улучшило производительность в среднем на 11% при использовании на 24% меньше входных токенов.
- Латентность: оркестрация 20+ вызовов инструментов в одном блоке кода устраняет 19+ проходов инференса.
Форма выигрыша — это ключ. Это окупается, когда у вас есть 3+ зависимых вызова, цикл, фильтр или fan-out. Это ничего не окупает — и обходится вам в контейнер — когда Claude нужен ровно один вызов инструмента и он в любом случае хочет прочитать весь ответ.
- Claude Haiku 4.5 принимает новые типы инструментов, но НЕ поддерживает программный вызов инструментов или сохранение состояния REPL, от которого он зависит. Более новые версии там ведут себя молча как code_execution_20250825. Если вы маршрутизируете на Haiku ради стоимости, вы не получаете эту функцию — и не получите ошибку, сообщающую вам об этом.
Сколько это стоит
Программный вызов инструментов тарифицируется как code execution, а code execution тарифицируется по контейнер-часу, а не по вызову:
- 1 550 бесплатных часов в месяц на организацию.
- Сверх этого — $0,05 в час за контейнер.
- Время выполнения имеет минимум 5 минут — двухсекундный скрипт всё равно тарифицируется как пять минут контейнера.
- Если вы прикрепляете файлы к запросу, время выполнения тарифицируется, даже если инструмент никогда не вызывается, потому что файлы предзагружаются на контейнер в любом случае.
- Это бесплатно, когда тот же запрос также использует web search или web fetch (
web_search_20260209/web_fetch_20260209или новее).
Два следствия, которые стоит усвоить. Во-первых, порог в 5 минут означает, что много короткоживущих контейнеров — это дорогой паттерн; повторное использование одного контейнера на протяжении сессии — дешёвый. Во-вторых, эта функция не подходит для Zero Data Retention — если ZDR является контрактным требованием для вас, это жёсткая остановка, а не тюнинговая ручка.
Пять способов, которыми это ломается
- Когда есть незавершённые программные вызовы инструментов, ваше ответное сообщение должно содержать ТОЛЬКО tool_result блоки. Не текст плюс результаты инструментов. Не результаты инструментов, за которыми следует вежливое предложение. Только tool_result блоки.
- Незавершённый программный вызов инструмента таймаутится примерно через четыре минуты и вызывает TimeoutError внутри выполняющегося кода Claude (пример stderr в документации гласит 'no response after 270s'). Claude видит это в stderr и обычно повторяет попытку. Установите таймаут на выполнение вашего собственного инструмента, чтобы падать быстро, а не подвешивать контейнер.
- input_schema с самоссылающимся $ref не может быть включена для программного вызова — даже несмотря на то, что точно та же схема принимается для прямого вызова. Разверните рекурсию до фиксированной глубины и опишите более глубокую вложенность во внутреннем description, либо оставьте этот один инструмент только для прямого вызова.
- Вы не можете принудить программный вызов конкретного инструмента. Именование инструмента в tool_choice, чей allowed_callers не содержит 'direct', — это invalid_request_error. Также не поддерживается: strict: true (структурированные выходы) и disable_parallel_tool_use: true.
- Инструменты, предоставленные MCP-коннектором, не могут быть вызваны программно. Если вы хотите MCP-обеспеченную возможность внутри песочницы, вам придётся самостоятельно выставить её как обычный пользовательский инструмент.
Строки версий, расшифрованные
Все три версии code-execution общедоступны и не требуют beta-заголовка:
| Версия | Что она добавляет |
|---|---|
code_execution_20250825 | Базовая линия. Bash + Python + файловые операции. Поддерживается на каждой текущей модели. |
code_execution_20260120 | Добавляет сохранение состояния REPL и программный вызов инструментов. Это та, что вам нужна. |
code_execution_20260521 | Идентичный рантайм с 20260120. Единственное различие в том, что описание инструмента сообщает Claude о лимите wall-clock в 90 секунд на Python-ячейку, чтобы он мог бюджетировать долго выполняющиеся ячейки. Ячейка, которая превышает лимит, возвращает ненулевой return_code со статусом detection_timeout. |
Последняя строка — это приятный элемент дизайна API, который стоит заметить: бамп версии, чья полная полезная нагрузка — это лучший промпт для модели. Обе строки взаимозаменяемы внутри allowed_callers, и ответы всегда тегируют caller как code_execution_20260120 независимо от того, что вы объявили.
Сам контейнер не имеет доступа в интернет — Claude не может pip install во время выполнения, поэтому вы получаете предустановленный набор библиотек (pandas, numpy, scipy, scikit-learn, statsmodels и им подобные) и ничего больше. Контейнеры чекпоинтятся примерно после пяти минут неактивности, восстанавливаются по ID и истекают через 30 дней после создания.
Когда к этому обращаться
Обращайтесь к программному вызову инструментов, когда модель используется как цикл и фильтр, а не как рассуждающий: пакетные поиски по N сущностям, ранняя терминация по достижении условия, условный выбор инструмента на основе промежуточного результата или свёртывание 200-КБ дампа логов до десяти строк, которые имеют значение.
Обращайтесь к Tool Search Tool вместо этого, когда ваша проблема в том, что определения поглощают ваш контекст до того, как сделан хотя бы один вызов — пометьте инструменты defer_loading: true, и Claude загрузит их по запросу. Эти два — дополнения, а не альтернативы: tool search находит правильный инструмент, программный вызов выполняет его дёшево. Если ваши определения инструментов превышают примерно 10K токенов, вам, вероятно, нужны оба.
А если вы упираетесь в это с другой стороны — агент, чей контекст тонет в результатах MCP-инструментов — начните с стоимости токенов MCP и Инжиниринга контекста, потому что самые дешёвые токены — это всё ещё те, которые вы никогда не отправляете.
Check yourself
0/5Источники и дальнейшее чтение
- Programmatic tool calling — документация Claude Platform —
allowed_callers, полеcaller, поток pause/resume, ограничения форматирования и список ограничений. - Code execution tool — документация Claude Platform — версии инструментов, жизненный цикл контейнера и истечение, предустановленные библиотеки и ценообразование 1 550 бесплатных часов / $0,05 в час.
- Introducing advanced tool use on the Claude Developer Platform — цифра 43 588 → 27 297 токенов, прирост точности GIA и knowledge-retrieval, и как Tool Search Tool сочетается с этим.
- Improved web search with dynamic filtering — результат +11% / −24% входных токенов на агентном поиске и как динамическая фильтрация запускает code execution за вас.
- BrowseComp и DeepSearchQA — бенчмарки агентного поиска, стоящие за этими цифрами.
- Связанное на AILmanac: Использование инструментов / Function Calling · MCP · Стоимость токенов MCP · Инжиниринг контекста · Токены и цены