Оптимизация стоимости: как считать токены и экономить
Где утекают деньги на LLM и как их вернуть. Подсчёт токенов, выбор модели под задачу, кэширование и обрезка контекста. 1 кредит = 1 ₽.
Команда Yenisei
Оптимизация стоимости: как считать токены и экономить
Счёт за LLM почти всегда растёт не там, где ждёшь. Люди оптимизируют модель, а деньги утекают на раздутый контекст и лишние вызовы. Разберём, как считать и где резать. Напомню: 1 кредит = 1 ₽, так что весь расчёт — прямо в рублях.
Из чего складывается цена
Платите за токены: входные (промпт, история, контекст) и выходные (ответ, а для reasoning-моделей — ещё и размышления). Выход обычно в разы дороже входа. Начните с фактов, а не с догадок:
u = resp.usageprint(u.prompt_tokens, u.completion_tokens)Логируйте usage по каждому вызову с тегом сценария (бот, автодополнение, отчёт). Без этой разбивки вы не знаете, что оптимизировать.
Где утекают деньги
- Раздутый контекст. В RAG кладут 30 чанков «на всякий случай». Восемь точных дают тот же ответ вчетверо дешевле.
- Вся история диалога каждый раз. Длинный чат отправляет всю переписку в каждом запросе. Обрезайте до последних N реплик плюс саммари старого.
- Флагман на простой задаче. Классификация тикета на
deepseek-proвместоqwen-flash— переплата на порядок при том же результате. - Reasoning там, где не надо.
highгенерирует тысячи оплачиваемых токенов размышления впустую. - Длинные ответы. Не ограничили
max_tokens— модель пишет простыню, вы платите за каждый токен.
Выбор модели под задачу — главный рычаг
Разница в цене между Flash и Pro моделями — обычно 5–20x. Правильный маппинг задач на модели экономит больше, чем любая микрооптимизация промпта:
- Массовый инференс (классификация, извлечение, боты) → Flash.
- Сложная логика, важные тексты, рефакторинг → Pro.
- Эмбеддинги → отдельная дешёвая модель (
bge-m3), не тратьте на них chat-модель.
Кэширование
Два уровня. Свой кэш по хешу промпта — для повторяющихся запросов (одинаковые вопросы в боте, одинаковые префиксы в автодополнении) возвращайте сохранённый ответ, не дёргая модель вовсе. И prompt caching на стороне API, если поддерживается: длинный неизменный system-промпт кэшируется и считается дешевле на повторных вызовах — держите статичную часть в начале.
Обрезка контекста
def trim_history(messages, keep=8): system = [m for m in messages if m["role"] == "system"] rest = [m for m in messages if m["role"] != "system"] return system + rest[-keep:]Простая обрезка последних реплик покрывает большинство чатов. Для длинных — саммаризируйте отсечённое одной дешёвой моделью раз в N реплик и держите саммари в system.
Ограничивайте выход
max_tokens — самый недооценённый рычаг. Выходные токены дорогие; поставьте разумный потолок под задачу (для бота 300, для отчёта 1500) и просите модель быть краткой в промпте. «Ответь одним абзацем» экономит реально.
Считайте на реальной нагрузке
Прикидки «в среднем» врут. Возьмите сутки продакшн-логов с usage, посчитайте стоимость по сценариям и найдите топ-3 статьи расхода. Почти всегда 80% счёта дают 2–3 сценария — их и оптимизируйте, остальное не трогайте. 1 кредит = 1 ₽ — так что по логам сразу видно рубли, без пересчёта.