
Когда разработчик впервые подключает tool calling к LLM, он обычно смотрит на качество ответов: правильно ли модель выбрала функцию, корректно ли передала параметры. Расход токенов остаётся за кадром — до первого счёта от API-провайдера.
Проблема не в том, что tool calling «дорогой». Проблема в том, что его стоимость плохо предсказуема. Одно и то же действие может стоить 200 токенов или 2000 — в зависимости от того, как сформирован промпт, какие инструменты зарегистрированы и как обрабатывается цикл вызова.
Эта статья — не общий обзор tool calling, а практический чеклист для тех, кто уже использует функции в LLM и хочет понять, куда уходят токены.
Что именно расходует токены при tool calling
Tool calling — это не один запрос, а как минимум два раунда: первый, в котором модель решает, какой инструмент вызвать, и второй, в котором она получает результат вызова и формирует финальный ответ. Если инструментов несколько или модель ошибается, циклов становится больше.
Основные статьи расхода:
- Описание инструментов (tools) в системном промпте. Каждая функция, переданная в API, занимает токены. Чем подробнее описание параметров, тем больше расход на каждом запросе.
- Результат вызова инструмента (tool result). Модель получает сырой вывод функции. Если функция возвращает 10 КБ JSON, модель «прочитает» его как часть контекста.
- Повторные попытки. Если модель выбрала неверный инструмент или передала некорректные параметры, цикл повторяется — каждый раз с полным контекстом предыдущих шагов.
- Стриминг и кэширование. При стриминге токены считаются так же, как при обычном запросе. Промис-кэширование (prompt caching) может снизить расход, но работает только для идентичных префиксов.
По данным тестов Anthropic, добавление одного инструмента с тремя параметрами увеличивает расход на системный промпт примерно на 80–120 токенов. Десять инструментов — уже 800–1200 токенов на каждый запрос, независимо от того, вызван хотя бы один из них.
Метрика, которую стоит добавить в CI/CD
Большинство разработчиков меряют latency и успешность вызова. Этого недостаточно. Нужна метрика token cost per tool call — отношение количества потраченных токенов к числу успешных вызовов инструментов.
Формула простая:
`token_cost_per_tool = total_tokens_consumed / successful_tool_calls`
Где `total_tokens_consumed` — сумма prompt_tokens и completion_tokens за весь сеанс (или за N запросов), а `successful_tool_calls` — количество вызовов, которые привели к корректному выполнению функции.
Почему это важно? Потому что модель может сделать три вызова инструмента, из которых два — ошибочные, и всё равно вернуть правильный ответ. С точки зрения пользователя всё хорошо. С точки зрения расходов — вы заплатили за три вызова вместо одного.
В CI/CD эту метрику можно проверять как регрессионный тест: если после изменения промпта или добавления нового инструмента `token_cost_per_tool` вырос более чем на 20%, стоит пересмотреть описание или структуру вызова.
Где чаще всего теряются токены: три типовых сценария
Слишком раздутые описания инструментов
Разработчики часто копируют JSDoc или Python-докстринги в описание tool. Проблема в том, что модель читает весь текст буквально. Если описание параметра содержит примеры, пояснения или примечания — каждый запрос платит за эти токены.
Пример из реального проекта: функция поиска по базе знаний имела описание параметра `query` на 400 токенов с примерами запросов. После сокращения до 50 токенов расход на системный промпт снизился на 12% без потери качества вызовов.
Что делать: проверять длину каждого описания инструмента. Для параметров достаточно типа, краткого назначения и допустимого диапазона. Примеры — только если модель систематически ошибается.
Циклические вызовы без завершения
Модель может войти в цикл, если результат вызова инструмента снова триггерит тот же инструмент. Например, функция `search_database` возвращает список ID, и модель решает вызвать `search_database` для каждого ID, вместо того чтобы передать список в один вызов.
Каждый дополнительный виток — это полный контекст предыдущих шагов плюс новый запрос. При 5–6 итерациях расход может вырасти в 3–4 раза по сравнению с оптимальным сценарием.
Что делать: устанавливать максимальное количество последовательных вызовов инструментов (max_tool_rounds). OpenAI и Anthropic позволяют ограничить число шагов через параметр `max_tool_calls` или логику на стороне приложения. Если лимит превышен — возвращать пользователю сообщение о недоступности результата, а не продолжать тратить токены.
Передача сырых результатов без фильтрации
Функция может возвращать 1000 строк из базы данных. Модель получит их все, даже если для ответа нужна только одна. Каждая строка — токены.
Что делать: оборачивать вызовы инструментов в слой, который фильтрует или агрегирует результат перед передачей модели. Если функция вернула массив объектов, передавайте только первые 5 и общее количество. Если нужен конкретный объект — пусть модель уточнит запрос через дополнительный параметр.
Как измерить утечку: пошаговый чеклист
Зафиксируйте baseline. Запустите 10–20 тестовых запросов с текущей конфигурацией tool calling. Запишите общее количество потреблённых токенов и число успешных вызовов. Вычислите `token_cost_per_tool`.
Проверьте каждый инструмент по отдельности. Уберите все функции, кроме одной, и повторите тест. Если `token_cost_per_tool` для одного инструмента значительно выше, чем для других — проблема в его описании или логике.
Измерьте расход на холостые вызовы. Добавьте в логгирование случаи, когда модель вызывает инструмент, но не использует результат. Это чистые потери: токены потрачены, пользы ноль.
Проверьте длину системного промпта. Суммируйте токены всех описаний инструментов. Если они занимают больше 30% от лимита контекста — стоит оптимизировать.
Настройте алерт на аномальный расход. Если за одну сессию модель делает больше 5 вызовов инструментов — это повод проверить, не ушла ли она в цикл.
Инструменты для мониторинга
Большинство API-провайдеров возвращают статистику по токенам в ответе. У OpenAI это поле `usage` в объекте ответа, у Anthropic — `usage` с разбивкой на `input_tokens` и `output_tokens`. Этого достаточно для базового сбора.
Для постоянного мониторинга можно использовать:
- LangSmith — трекинг каждого шага цепочки с разбивкой по токенам.
- Helicone — прокси-слой, который логирует все запросы к API и считает стоимость.
- Self-hosted решение — запись `usage` в Prometheus через кастомный middleware.
Важно: не все провайдеры возвращают разбивку по инструментам. OpenAI показывает только общий `prompt_tokens`, куда входят и описания tools, и история вызовов. Anthropic даёт более детальную статистику в ответе при использовании `stream: true`.
Когда tool calling оправдан, а когда нет
Tool calling имеет смысл, когда модель должна выбирать между несколькими дискретными действиями на основе контекста. Если задача сводится к одному предсказуемому вызову — дешевле и быстрее вызвать функцию напрямую, без LLM.
Пример: приложение для поиска авиабилетов. Если пользователь явно указал дату и направление, нет смысла гонять их через модель — можно сразу вызвать API поиска. Tool calling нужен, когда запрос сформулирован неоднозначно («найди рейс на следующей неделе в Европу») и модель должна уточнить параметры.
Решение о том, где провести границу, принимается на основе метрик. Если `token_cost_per_tool` для простых запросов превышает стоимость прямого API-вызова — значит, tool calling используется там, где он не нужен.
Что остаётся за рамками
Расход токенов — не единственная метрика. Tool calling влияет на latency (каждый цикл — дополнительный round-trip к API), на стабильность (модель может ошибиться в выборе инструмента) и на безопасность (вредоносные данные в результате вызова могут повлиять на последующие решения модели).
Перед внедрением tool calling в production стоит провести нагрузочное тестирование: как поведёт себя система при 100 одновременных запросах с пятью инструментами каждый. Счёт за токены может вырасти нелинейно.
Для дальнейшего изучения — документация OpenAI по функциям, гайд Anthropic по streaming tool use и cookbook с примерами от сообщества. Там же — примеры обработки ошибок и ограничения, которые не вошли в этот чеклист.









