SiCore TokenWorks
LLM APIAPI Gateway

Разбор token8341: счёт за чат-бота службы поддержки, превысивший бюджет втрое — куда ушли деньги

SiCore TokenWorks Team·2026-10-03

Сразу к выводу: чат-бот службы поддержки сжигает деньги в большинстве случаев не из-за высокой цены за единицу модели, а из-за проблем со способом вызова. У нашего внутреннего бота для ответов на вопросы послепродажной поддержки с ежедневной аудиторией в несколько тысяч человек счёт за первый месяц после запуска сразу вырос втрое относительно бюджета. Разобрались — цена модели ни на копейку не изменилась, всё дело в скрытых накладных расходах на уровне структуры вызовов. В этой статье описан процесс разбора; те, кого касается оптимизация затрат на API больших моделей, могут сверить со своим счётом.

Как выглядит аномальный счёт

Характерная черта аномалии — не «высокая итоговая сумма», а «странная структура». Мы выгрузили детализацию вызовов по дням и обнаружили три подозрительных момента: в дни с наибольшим числом вызовов среднее количество токенов на запрос росло; доля повторных попыток приближалась к двум десятым; на один и тот же вопрос пользователя уходило от нескольких сотен до десятков тысяч токенов — разброс огромный. Эти три вещи вместе взятые практически гарантированно указывают на то, что проблема не на стороне модели, а в нашей собственной цепочке вызовов.

Четыре скрытых расхода — один незаметнее другого

Первое: флагманская модель выполняет черновую работу. Изначально мы ради простоты пускали все запросы через флагманскую модель. Но в сценарии поддержки более семи десятых — это распознавание интентов вроде «где мой заказ» и «как вернуть товар» и ответы по фиксированным шаблонам; для таких задач вполне достаточно малой модели, а разница в стоимости — на порядок. Заставлять флагманскую модель отвечать на вопрос «во сколько вы открываетесь» — всё равно что отправлять грузовик доставлять еду.

Второе: бесконтрольное разрастание контекста. В многоходовых диалогах мы заталкивали обратно всю историю сообщений целиком; когда пользователь доходил до десятого раунда, только история занимала большую часть токенов. Хуже того, многое из истории не имело никакого отношения к текущему вопросу — чистый балласт. Контекст не становится умнее от того, что он длиннее: после определённой длины прирост точности ограничен, а стоимость растёт линейно.

Третье: шторм повторных попыток. Мы настроили простой повтор при сбое, но не сделали ни отката, ни предохранителя. Когда у вышестоящего сервиса случался эпизодический таймаут, одна и та же пачка запросов долбила снова и снова: одна неудача — один повтор, повтор снова падает — снова повтор. Все эти вызовы в счёте — чистый выброс денег, а пользователь всё равно видел ошибку.

Четвёртое: двойная оплата за потоковый и непотоковый режимы. Это самое легко упускаемое. В некоторых наших цепочках, чтобы получить полный результат для постобработки, делался непотоковый вызов; а фронтенду нужен был эффект печатной машинки — ещё один потоковый вызов. Один и тот же вопрос — две оплаты. Позже мы унифицировали всё на потоковый приём со сборкой на месте, и только тогда эти дублирующиеся расходы исчезли.

Как реализовать многоуровневую маршрутизацию

Идея несложная: разделять потоки по сложности задачи. Распознавание интентов, извлечение слотов, фиксированные шаблоны — идут на лёгкую модель; действительно требующие рассуждения, многошаговых решений и успокоения эмоций сложные сессии — только тогда отдаются флагманской модели. Между ними добавляется слой шлюза моделей, который принимает решение: запрос сначала проходит классификатор, получает метку задачи, и только потом определяется, на какую модель его маршрутизировать.

Мы используем логику автоматического выбора оптимальной модели под задачу; прогнали один раунд сравнение на многоуровневой маршрутизации SiCore TokenWorks — после переключения простых задач на лёгкую модель общая стоимость заметно пошла вниз, да и отклик стал быстрее. Ключ здесь не в том, «какую модель использовать», а в том, что таблицу соответствия «какая задача — какая модель» нужно постоянно донастраивать. На старте мы настраивали по опыту; через две недели перекалибровали по фактическому проценту попаданий — результат оказался куда лучше, чем настройка на глазок. Преимущество единого подключения множества моделей проявилось как раз тогда: для смены стратегии маршрутизации не нужно править бизнес-код, достаточно подкрутить на уровне шлюза.

Сравнение счёта до и после оптимизации

Конкретные цифры не привожу, привожу пропорции. Общее количество вызовов не изменилось, потому что не изменилось число пользователей. Общая стоимость упала примерно на шесть десятых, при этом доля вызовов флагманской модели снизилась с почти ста процентов до порядка трёх десятых, остальное ушло на лёгкие модели. Вызовы, связанные с повторами, сократились с почти двух десятых до однозначного процента. Среднее количество токенов на запрос снизилось примерно на четыре десятых — в основном за счёт обрезки контекста. Двойная оплата за потоковый режим обнулилась напрямую. В целом из превышения бюджета втрое мы вернулись в бюджет да ещё с запасом.

Как настроить мониторинг и оповещения

Сэкономленные деньги нужно удержать, и держатся они на мониторинге, а не на сознательности. Мы настроили четыре оповещения: срабатывание при превышении порога токенов на один запрос — против выхода контекста из-под контроля; срабатывание при превышении заданной доли повторов — против шторма повторных попыток; срабатывание при аномальном росте доли вызовов флагманской модели — значит, маршрутизация, возможно, отказала; срабатывание при превышении порога роста суточной стоимости относительно предыдущего дня. Эти четыре не нужно делать особо сложными: агрегация по дням и оповещение при выходе за черту — вполне достаточно. В модели оплаты по токенам стоимость накапливается в реальном времени; ждать конца месяца, чтобы посмотреть счёт и заняться оптимизацией, — деньги уже потрачены.

Если сформулировать одной фразой: основная часть затрат чат-бота службы поддержки — в структуре вызовов, а не в цене за единицу модели. Прочно сделайте эти четыре вещи — многоуровневую маршрутизацию, обрезку контекста, контроль повторов и унификацию потокового режима — и счёт сам пойдёт вниз. И на шаг дальше: если в вашем сценарии есть ещё и RAG-поиск, количество извлекаемых записей из векторной базы тоже стоит проверить по этой же логике.