Стоимость LLM-системы нельзя оценивать по одному тестовому запросу. На тесте виден один аккуратный вызов, а в месячный счёт попадают длинные входы, повторные попытки, evals и весь production-трафик.
Ситуация из реальной команды
Команда запускает суммаризацию звонков для отдела продаж. На демо один звонок стоит «копейки»: кто-то один раз посмотрел в биллинг и увидел $0.02. Фичу раскатывают на всех менеджеров. Через месяц приходит счёт, в котором стоимость фичи сопоставима с зарплатой джуна.
Разбор показывает то, что можно было посчитать заранее:
- средний звонок оказался не 10 минут, а 40: транскрипт в 4 раза длиннее;
- суммаризация делалась по каждому обновлению записи, а не один раз по завершении;
- retry на ошибках формата добавлял 12% вызовов;
- к суммаризации незаметно приклеились «ещё и action items» и «ещё и оценка настроения клиента»: три вызова вместо одного;
- никто не заложил evals, которые тоже гоняют модель.
Ни один пункт не был сюрпризом технически. Сюрпризом был только счёт: потому что никто не считал.
Формула, с которой всё начинается
monthly_cost = events_per_month × avg_cost_per_eventСредняя стоимость события раскладывается:
avg_cost_per_event =
Σ по шагам пайплайна (
input_tokens × input_price
+ output_tokens × output_price
)
× (1 + retry_rate)Плюс слагаемые, которые забывают почти все:
- embeddings и reranking, если есть retrieval;
- tool calls: каждый круг «модель → инструмент → модель»: это новый input со всей историей;
- проверяющие вызовы: judge, quality check, репарация формата;
- evals: регрессионные прогоны при каждом изменении prompt-а;
- стоимость человеческой проверки там, где она обязательна;
- latency cost: не в долларах, а в конверсии, если пользователь ждёт.
Важная асимметрия: output-токены у большинства провайдеров в 3–5 раз дороже input. Болтливая модель создаёт не эстетическую, а финансовую проблему. Самая дешёвая оптимизация здесь — ограничить длину ответа схемой и max_output_tokens.
Событие: это не запрос
Считать надо стоимость business event, а не API-вызова. «Обработать тикет» может включать классификацию, извлечение, генерацию черновика и проверку: четыре вызова, два из которых иногда ретраятся. Бизнес спрашивает «сколько стоит обработка тикета», и у вас должен быть ответ именно на этот вопрос.
from dataclasses import dataclass
@dataclass
class StepEstimate:
name: str
input_tokens: int
output_tokens: int
retry_rate: float = 0.0
calls_per_event: float = 1.0
@dataclass
class PriceUSD:
input_per_1m: float
output_per_1m: float
def cost_per_event(steps: list[tuple[StepEstimate, PriceUSD]]) -> float:
total = 0.0
for step, price in steps:
one_call = (
step.input_tokens * price.input_per_1m
+ step.output_tokens * price.output_per_1m
) / 1_000_000
total += one_call * step.calls_per_event * (1 + step.retry_rate)
return totalТакой калькулятор занимает 30 строк и окупается в первый же день. Числа для него берутся не с потолка:
input_tokens/output_tokens: прогоните 50–100 реальных или реалистичных примеров и возьмите не среднее, а p50 и p95. Хвост распределения: длинные документы, многословные клиенты: определит ваш худший месяц.retry_rate: из логов прототипа; если их нет, заложите 10% и уточните после первой недели.- Цены: из прайса провайдера на сегодня (актуальные цены и модели: в Приложении А).
Три сценария вместо одного числа
Оценка «фича будет стоить $800 в месяц»: это не оценка, это ставка. Считайте три сценария:
- базовый: p50 токенов, ожидаемый объём;
- тяжёлый: p95 токенов, объём +50%, retry ×2;
- катастрофный: что будет, если фичу полюбят: объём ×5.
Если катастрофный сценарий убивает экономику, у вас нет фичи. У вас есть демо, которое опасно показывать начальству.
Правило главы
Стоимость AI-фичи считается до написания кода, на трёх сценариях, в терминах business event. Если кажется, что считать нечего, потому что «мы ещё не знаем токены», прогоните 50 примеров и узнайте. Час работы с калькулятором дешевле месяца работы фичи, которую придётся выключить.
Чеклист главы
- Стоимость посчитана per business event, а не per API call.
- Учтены retry, tool calls, проверяющие вызовы, embeddings и evals.
- Токены оценены по p50 и p95 на реальных примерах, а не «на глаз».
- Посчитаны три сценария: базовый, тяжёлый, катастрофный.
- Учтена асимметрия цен input/output, длина ответа ограничена.
- Оценка записана и будет сверена с фактом через месяц после запуска.
Практикум
Задача 43.1: калькулятор стоимости пайплайна. ⭑⭑
Напишите калькулятор из этой главы и посчитайте им типовой кейс: пайплайн обработки тикета поддержки (классификация маленькой моделью → извлечение полей маленькой → генерация черновика большой → проверка черновика маленькой) при 100 000 тикетов в месяц. Профили токенов оцените, прогнав 30 сгенерированных тикетов через реальный токенайзер.
Критерии приёмки:
- Калькулятор принимает список шагов и цены, выдаёт стоимость события и месяца по трём сценариям.
- Токены взяты из измерений (p50/p95), а не выдуманы.
- Найден самый дорогой шаг пайплайна и посчитано, что даст его перевод на модель дешевле / сокращение контекста / кэширование.
- Результат оформлен как одна страница, которую можно показать бизнесу: три числа, главный драйвер стоимости, главный рычаг экономии.
Подсказки:
- Скорее всего окажется, что 70%+ стоимости съедает один шаг. Это нормально: теперь у вас есть цель для главы 45.
Задача 43.2: прогноз против факта. ⭑⭑⭑
Возьмите свой сервис из задачи 24.1 и добавьте в llm_call_log тег business event. Сделайте прогноз стоимости на неделю вперёд калькулятором, затем прогоните реалистичную нагрузку (можно скриптом) и сравните прогноз с фактом из базы.
Критерии приёмки:
- SQL-запрос выдаёт фактическую стоимость per event и per день.
- Расхождение прогноза с фактом объяснено по компонентам: где ошиблись в токенах, где в retry rate, где в структуре вызовов.
- Калькулятор откалиброван по факту; второй прогноз попадает в ±20%.
Подсказки:
- Главный источник расхождений обычно не цены и не токены, а «незапланированные» вызовы: репарации, повторные проверки, отладочные прогоны в прод-окружении.