Когда туда-сюда убивает отзывчивость
Ты собрал агента на Bedrock, который вызывает пять инструментов подряд: проверить баланс, найти рейс, забронировать, отправить уведомление. Что происходит? Каждый вызов - отдельный round-trip к LLM. Модель возвращает JSON с именем функции и аргументами, твой код исполняет функцию, отдает результат обратно, модель снова думает. И так пять раз. Латенси растет как снежный ком: от 2-3 секунд на простой запрос до 15-20 на многошаговый.
В 2025 году AWS наконец-то выкатили Programmatic Tool Calling (PTC) для агентов Bedrock. Это не эволюция - это слом парадигмы. Вместо того чтобы возвращать JSON с одним вызовом, модель генерирует Python-скрипт, который сам зовет все нужные инструменты внутри себя. А ты просто дергаешь этот скрипт в изолированной песочнице и получаешь финальный ответ.
Programmatic Tool Calling (PTC) - режим работы агента, при котором модель генерирует код на Python вместо последовательности JSON-вызовов. Выполнение происходит в безопасной среде (sandbox). Позволяет сократить количество шагов до 1.
Звучит логично, но есть нюанс: код может быть кривым, песочница может упасть, а модель - сгенерировать бесконечный цикл. Поэтому PTC - это не магическая таблетка, а мощный инструмент для тех, кто готов тестировать и контролировать. Давай разберем, как он работает и почему стоит перейти.
Под капотом: генерация кода и песочница
В обычном режиме (ReAct) схема такая:
- Пользователь: "Забронируй билет на 25 июня"
- Модель: думает, выдает JSON: {"tool": "searchFlights", "params": {"date": "2026-06-25"}}
- Агент: выполняет searchFlights, возвращает результат
- Модель: думает снова, JSON: {"tool": "bookTicket", "params": {"flight": "SU123"}}
- Агент: бронирует, возвращает статус
- Модель: формирует ответ пользователю
Пять шагов, четыре обращения к LLM, минимум 8-12 секунд чистой работы модели (без учета времени на сами API). А теперь PTC:
- Пользователь: "Забронируй билет на 25 июня"
- Модель: генерирует Python-код, который вызывает searchFlights, bookTicket, sendEmail внутри одного скрипта
- Агент: передает код в sandbox-среду (изолированный Docker-контейнер), выполняет, получает финальный результат
- Модель: один раз до-формулирует ответ на основе результата выполнения
Время сокращается до 2-4 секунд. Разница в 3-5 раз. И это еще не все: PTC экономит токены, потому что модель не генерирует повторные цепочки вызовов. Одно длинное рассуждение вместо нескольких коротких.
Как это выглядит в коде (без кода, но с логикой)
Допустим, у тебя агент для финопс-задач. Ты хочешь: получить текущий расход по сервису EC2, умножить на прогнозируемый рост, сравнить с бюджетом. В обычном режиме - три вызова. В PTC модель сгенерирует скрипт:
import boto3, json
from utils import get_bedrock_cost, get_budget
# 1. Получаем данные
cost_data = get_bedrock_cost(service='ec2', period='MTD')
budget_data = get_budget(name='Production')
# 2. Расчет
current_spend = cost_data['total']
forecast = current_spend * 1.15
alert = forecast - budget_data['limit']
# 3. Вывод
result = {
'current': current_spend,
'forecast': forecast,
'over_budget': alert > 0,
'difference': alert
}
print(json.dumps(result))
Агент берет этот код, запускает в песочнице Bedrock Sandbox (изолированная среда с ограниченными правами), и возвращает финальный JSON. Никаких промежуточных шагов. Одна генерация, один запуск, один ответ.
⚠️ Важно: песочница не имеет доступа к сети, к файловой системе хоста, к секретам. Только те инструменты, что ты явно передал агенту. Если код попытается открыть сокет или прочитать /etc/passwd - получишь SecurityException. AWS серьезно относится к изоляции.
Когда PTC дает максимальный профит
Выигрыш заметен не всегда. Если у тебя агент делает один вызов - смысла нет (оверхед на генерацию кода может даже увеличить latency). Но если в workflow больше двух последовательных вызовов, особенно с ветвлениями или циклами - PTC незаменим.
| Сценарий | Обычный режим | PTC | Экономия |
|---|---|---|---|
| Один вызов (простые Q&A) | 1.5 сек | 2.2 сек | -47% (хуже) |
| 2-3 последовательных вызова | 5.0 сек | 3.1 сек | +38% |
| 5+ многошаговых с ветвлением | 14.2 сек | 4.5 сек | +68% |
Цифры экспериментальные, сняты на Claude 4.5 Opus (последняя версия на май 2026). Результат зависит от сложности задачи и размера промпта. Но тренд очевиден: чем длиннее цепочка, тем выгоднее PTC.
Практический гайд: включаем PTC в Bedrock Agent
Все действия делаются через AWS Console или SDK (boto3). Покажу настройку на Python, потому что в консоли все тривиально.
1 Создай инструменты с правильным типом
Для PTC инструменты должны быть описаны как JSON Schema, а не как лямбды. Песочница будет вызывать их прямо из кода через функцию call_tool(name, args). Вот пример для boto3:
import boto3
from typing import Dict, Any
client = boto3.client('bedrock-agent')
# Агент с PTC включенным
response = client.create_agent(
agentName='ptc-assistant',
foundationModel='anthropic.claude-4-5-opus-20260524',
instruction='Ты - агент с PTC. Генерируй Python-код для выполнения задач.',
actionGroups=[
{
'actionGroupName': 'tools',
'description': 'Инструменты для работы',
'actionGroupExecutor': {
'customControl': 'RETURN_CONTROL' # критично!
},
'functionSchema': {
'functions': [
{
'name': 'get_usage',
'description': 'Получить использование сервиса',
'parameters': {
'service': {'type': 'string'},
'period': {'type': 'string', 'enum': ['MTD', 'YTD']}
}
},
{
'name': 'send_notification',
'description': 'Отправить уведомление',
'parameters': {
'message': {'type': 'string'},
'channel': {'type': 'string'}
}
}
]
}
}
],
codeInterpreterEnabled=True # включает PTC
)
agent_id = response['agent']['agentId']
Ключевые моменты: customControl: 'RETURN_CONTROL' - агент не выполняет инструменты сам, а возвращает код. codeInterpreterEnabled: True - включает песочницу. Без этих двух флагов PTC не работает.
2 Настрой инструкцию для генерации кода
Промпт агента должен явно просить генерировать код. Пример:
Ты - агент с Programmatic Tool Calling. Когда получаешь запрос:
1. Разбей задачу на шаги.
2. Напиши Python-код, который использует функцию call_tool(name, args) для вызова инструментов.
3. Код должен работать в изолированной среде без доступа к сети.
4. Возвращай только код в тегах ```python ... ```.
5. Не используй сторонние библиотеки кроме json, math, datetime.
6. Обрабатывай ошибки инструментов через try-except.
Я настоятельно рекомендую запретить генерацию кода с бесконечными циклами - добавь в промпт что-то вроде "не используй while True, ставь ограничение на 100 итераций". Иначе получишь таймаут в 30 секунд и пустой ответ.
3 Выполни и проверь результат
После отправки запроса, агент вернет объект response, в котором будет поле intermediateSteps. В этом поле найдешь сгенерированный код и результат его выполнения. Если возникла ошибка - в логах будет traceback.
response = client.invoke_agent(
agentId=agent_id,
agentAliasId='TSTALIAS_ID',
sessionId='test-session',
inputText='Покажи текущие расходы на EC2 и если они превышают 1000$, отправь уведомление'
)
# Читаем поток ответа
for event in response['completion']:
if 'chunk' in event:
text = event['chunk']['bytes'].decode()
print(text)
if 'trace' in event:
trace = event['trace']
# Здесь будет код и результат выполнения
print(trace)
Шесть граблей, на которые я наступил
Первый месяц работы с PTC - чистый ад. Но потом стало кайфово. Вот что может пойти не так:
- Модель генерирует синтаксически невалидный код. Особенно часто с Claude 3.5 Sonnet - он любит забывать закрывающие скобки. Переход на Claude 4.5 Opus эту проблему почти убил, но не до конца. Решение: включи автоматический ретрай с повторной генерацией кода.
- Таймаут песочницы. По умолчанию 30 секунд. Если агент зациклится или полезет в датасет из 1000 строк - получишь таймаут. Ставь лимит на размер вывода (maxTokens) и время выполнения через
codeInterpreterTimeoutSeconds. - Инструменты с побочными эффектами. В коде может быть вызван
deleteResource()случайно. PTC не защищает от глупых вызовов - только от злонамеренных. Поэтому перед запуском в продакшн обязательно тестируй все возможные сценарии. - Размер кода. Модель может сгенерировать километровый скрипт. Песочница ограничена 8192 символами на код. Если больше - упадет с ошибкой.
- Смешение data и function calling. Если в инструментах есть и query, и mutation, модель может вызвать их в неправильном порядке. В явном виде пропиши порядок в инструкции.
- Отсутствие мониторинга. PTC генерирует код динамически - стандартные метрики вызовов инструментов перестают работать. Используй новые CloudWatch метрики TimeToFirstToken и EstimatedTPMQuotaUsage для отслеживания задержек. Без этого ты ослепнешь при росте нагрузки.
Еще одна типичная ошибка: после включения PTC забывают настроить теги для контроля затрат. Полное руководство по тегам и анализу в Bedrock поможет не прогореть на счете, когда PTC начнет генерировать много кода.
Когда PTC не нужен (честно)
Бывают кейсы, где PTC только мешает:
- Задачи с одним инструментом. Например, просто перевести текст. JSON-вызов быстрее и дешевле.
- Взаимодействие с реальным временем. Если нужны стриминговые данные (цены акций) - код в песочнице не может держать открытое соединение.
- Высокая частота ошибок в инструментах. Если API часто падает, лучше обрабатывать ошибки по одному, а не внутри сгенерированного кода. PTC предполагает, что инструменты надежные.
FAQ по PTC
Какие модели поддерживают PTC?
На май 2026: Claude 4.5 Opus, Claude 4 Sonnet, Mistral Large 2, Llama 4 (все с Amazon Bedrock только). Модели AWS (Titan) пока не поддерживают.
Можно ли передать секреты в песочницу?
Нет. Песочница изолирована намеренно. Для доступа к конфиденциальным данным нужно вызывать инструменты через call_tool, а уже инструмент может иметь доступ к Secrets Manager.
Как отладить код, если он упал?
В trace ответа придет stderr. Также можно включить enableTrace в запросе, чтобы получить полный лог выполнения. Иногда проще дать модели второй шанс с сообщением об ошибке.
PTC увеличивает стоимость?
Входные токены остаются примерно теми же (инструкция + промпт). Выходные - код обычно короче, чем последовательность JSON-вызовов. Плюс меньше round-trips, что экономит общее время инференса. Чистый выигрыш 15-30% по токенам.
А что с ошибкой 429 (Throttling)?
PTC не спасает от троттлинга - он сам может попасть под лимит. Решение - ретраи и экспоненциальная задержка. Подробно разобрано в статье Когда Bedrock говорит «нет».
Прогноз: через год все будут так делать
Сейчас PTC - опция, которую включают фанаты скорости. Но посмотри на тренды: AWS инвестирует в песочницу, модели лучше кодируют, а сложность агентов растет. Уже к концу 2026 года PTC станет режимом по умолчанию для всех multi-tool агентов.
Почему? Потому что это не просто оптимизация - это смена парадигмы. Вместо того чтобы учить LLM быть "дирижером" оркестра вызовов, мы говорим ей "напиши партитуру и отдай роботу". Робот (песочница) сыграет быстрее и точнее. А LLM останется только оценить результат.
Совет на будущее: если ты строишь агента с более чем двумя последовательными вызовами - сразу переходи на PTC. Да, первые две недели будешь материть кривой код. Но когда наладишь - срежешь latency вдвое. А в мире AI-агентов скорость - это валюта.
И да, если думаешь, что географическая маршрутизация может еще ускорить - почитай как это сделали в Bedrock Окленда. Комбинируя PTC с умным роутингом, можно получить агента, который отвечает быстрее, чем ты моргаешь.