Месяц назад мне пришёл счёт от OpenAI на сумму, которую я не ожидал. Не катастрофа, но достаточно неприятно, чтобы сесть и разобраться — куда конкретно утекают токены. Оказалось, я делал несколько очевидных глупостей, которые легко исправить.
Системный промпт — главная утечка, которую я не замечал
У меня был системный промпт на ~800 токенов. Казалось бы, мелочь. Но он отправлялся с каждым запросом. При 500 запросах в день это 400 000 лишних токенов только на системник — каждые сутки.
Я прошёлся по нему и выкинул всё, что не влияло на результат: вводные объяснения «ты — полезный ассистент», повторы, примеры, которые можно убрать. Промпт сжался до 310 токенов. Экономия — почти 60% на входящих токенах только от этого.
Отдельно я тащил в контекст весь чат целиком. Для длинных сессий это быстро превращается в тысячи токенов балласта. Проблему решил просто: обрезаю историю до последних N сообщений, а старые сворачиваю в один короткий абзац.
Кэширование — то, что я должен был сделать с самого начала
OpenAI сделали prompt caching: если начало промпта совпадает с предыдущим запросом хотя бы на 1024 токена, цена на эти токены падает в два раза. У Anthropic скидка ещё более агрессивная.
Ловушка в том, что кэшируемая часть должна идти в начале и не меняться между запросами. Я переструктурировал промпты: фиксированный системный блок вперёд, переменная часть — в конец. Это не просит никаких изменений в коде, только другой порядок содержимого.
Когда один большой контекст используется много раз — допустим, задаёшь разные вопросы по одному документу — экономия заметная. У меня на одном пайплайне вышло минус 40% на входящих токенах.
Выбор модели — здесь я долго упирался
Я по привычке гнал всё через GPT-4o. Потому что он лучший, и я привык к его качеству. Но «лучший» не значит «нужный для каждой задачи».
Я прогнал 200 реальных запросов через GPT-4o mini. Для 70% задач результат был неотличим — классификация, короткие извлечения, форматирование, простые трансформации. Разница в цене — в 15 раз.
Теперь у меня роутинг: простые задачи идут на mini, сложные — на 4o. Логика такая: если в запросе нет многоступенчатого рассуждения, кода или нюансированного анализа — mini справится. Ошибиться несложно, и я пару раз отправлял сложное на дешёвую модель — видно сразу, легко поправить правило.
Структурированный вывод вместо «напиши в формате JSON»
Раньше я писал в промпте: «верни ответ в JSON с полями X, Y, Z — убедись, что это валидный JSON». Модель иногда добавляла объяснения вокруг, иногда делала опечатки в ключах. Я парсил с try/except и иногда повторял запрос.
Переключился на Structured Outputs — через параметр response_format с JSON Schema. Теперь модель гарантированно возвращает валидный JSON без лишних слов. Промпт стал короче: не нужно объяснять формат словами, схема говорит сама за себя. Плюс пропали повторные запросы из-за кривого парсинга.
Это не про экономию токенов напрямую, но убирает дорогостоящие retry.
Батчинг — когда не нужно отвечать прямо сейчас
У OpenAI есть Batch API: отправляешь пачку, они обрабатываются в течение суток, цена — вдвое дешевле.
Я не сразу это использовал, потому что казалось — «мне нужно всё быстро». Но посмотрел честно на свои пайплайны: добрая половина задач не требует мгновенного ответа. Ночная обработка данных, генерация черновиков, обогащение датасетов — всё это спокойно уходит в batch.
Настройка несложная: формируешь JSONL-файл с запросами, отправляешь одним вызовом, через несколько часов забираешь результаты. Единственное — если логика у тебя синхронная, придётся переписать под асинхронный режим. У меня ушло пара часов.
Что в итоге
Месячный счёт упал примерно втрое. Не потому что я стал меньше использовать API — нагрузка та же. Просто перестал платить за то, что не давало результата.
Самое забавное: большинство изменений заняли по 20–30 минут. Обрезка промпта, например — я просто перечитал его как редактор и удалил воду. Странно, что не сделал это раньше.
Если запускаете что-то новое — заложите роутинг по моделям с самого начала. Потом переделывать сложнее, чем сделать сразу.
