Куди йшов наш рахунок за LLM API і які архітектурні зміни його зменшили
Облік токенів за кроками, розподіл моделей за рівнями, скорочення промптів і backoff із jitter знизили витрати кодинг-агента на API; усередині формули вартості й типові помилки оптимізації.
Рахунок за LLM може бути високим, навіть якщо самі моделі не надто дорогі. У нашому випадку винними були звички: той самий системний промпт на 1800 токенів ішов із кожним викликом, збої повторювалися одразу, без жодного backoff, а кожен крок процесу за замовчуванням ішов на флагманську модель, потрібна вона там чи ні. За нашою оцінкою, для цього навантаження ціна за токен пояснювала приблизно 20% проблеми, а архітектура — решту 80%. Це співвідношення стосується саме цієї системи й не є загальним бенчмарком. Але урок застосовний скрізь: прайсова ціна токена каже про тариф, а не про те, наскільки ефективно ваш застосунок його витрачає.
Перш ніж міняти провайдера чи торгуватися про ціну, ми оснастили витрати метриками, і кожне подальше рішення спиралося на дані, а не на чуття. Не можна оптимізувати те, чого не логуєш.
Прив’яжіть токени до кроків процесу
Перша вимога — облік на рівні кроків. Для кожного виклику API записуйте крок процесу, модель, вхідні й вихідні токени, а щоночі агрегуйте за кроком і моделлю. Якщо ціни вказано за мільйон токенів, вартість кроку рахується так:
step cost =
number of calls × [
(average input tokens ÷ 1,000,000 × input price per 1M tokens)
+
(average output tokens ÷ 1,000,000 × output price per 1M tokens)
]
Тиждень даних дав показову картину для навантаження кодинг-агента, і головний висновок виявився несподіваним: крок планування становив лише 8% викликів, але 41% усіх витрат. Дорогим його робило поєднання найдовших контекстів із найдорожчою моделлю. До вимірювань вважалося, що найдорожча — генерація коду, і дані показали, що це не так. Сама собою кількість запитів була хибною метрикою. Правильною були сумарні витрати на крок.
Мінімальна реалізація
Усе виявилося просто, бо відповіді API вже містять дані про витрату токенів:
import logging
from openai import OpenAI
client = OpenAI(
api_key="KEY",
base_url="https://api.cometapi.com/v1",
)
def tracked_call(step_name, model, messages):
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0,
)
usage = response.usage
logging.info(
"llm_call step=%s model=%s prompt=%d completion=%d",
step_name,
model,
usage.prompt_tokens,
usage.completion_tokens,
)
return response
Коли такі логи є, звіт про вартість — по суті один GROUP BY. Мета не в навороченій платформі спостережуваності, а в тому, щоб кожен токен можна було простежити до кроку процесу й моделі.
Візьміть знижку шлюзу, але вважайте її мінімумом
Наші запити йдуть через CometAPI, і за нашого профілю використання підсумкова вартість виходила приблизно на 20% нижчою, ніж під час оплати тих самих моделей напряму в провайдерів. Це була економія майже без зусиль: клієнтський код і вибір моделей лишилися тими самими, а рахунок зменшився за всіма вже використовуваними моделями. Ми взяли її одразу, бо вона майже не потребувала архітектурної роботи.
Але головним важелем шлюз не став. Подальші архітектурні зміни заощадили більше, щоправда, ціною справжньої інженерної роботи. Порядок упровадження й фінансовий ефект не завжди збігаються, тож дешеву цінову економію беріть одразу, а інженерний час витрачайте на маршрутизацію моделей, накладні витрати промптів і поведінку повторів. Немає сенсу відкладати миттєву економію, поки будуєш щось вигадливе, але низький тариф не компенсує неефективної будови запитів. Деталі тарифікації — у документації CometAPI щодо цін.
Спрямовуйте кожен крок на модель потрібного рівня
Розподіл за рівнями означає, що різні кроки процесу отримують різні моделі залежно від того, яка якість потрібна кожному. Плануванню флагманська модель справді була потрібна. Викликів там мало, а вплив великий: поганий план може зіпсувати всі подальші дії. У масових правок і виправлень лінтера інші потреби: великий обсяг, жорсткі рамки, легко повторити чи перевірити. Логіка маршрутизації змінилася відповідно:
def choose_model(step):
if step in ("plan", "hard_refactor"):
return "claude-sonnet-4-6" # High-value reasoning steps
if step in ("bulk_edit", "lint_fix"):
return "gemini-2.5-flash" # Lower-cost, fast, retry failures
return "gpt-5-mini" # Middle-tier default
У результаті 46% викликів пішли на дешевшу й швидшу модель, а дорога лишилася для планування та складної генерації. Розподіл за рівнями дав найбільше скорочення однієї статті рахунку, бо був націлений на кроки з великим обсягом, а не ганявся за дрібною економією на рідкісних. Принцип простий: найсильнішу модель ставте там, де помилки найдорожче коштують далі ланцюжком, а не всюди за замовчуванням.
Зріжте повторювані накладні витрати промпта
Системний промпт на 1800 токенів їхав із кожним запитом. Більшу його частину становив захисний шаблонний текст, що накопичувався місяцями: кожна інструкція під час додавання здавалася нешкідливою, але разом вони перетворилися на великі постійні витрати на кожен виклик. Рішення — прибрати надлишкові інструкції, залишити лише суттєві обмеження й винести стабільну частину в кешований префікс усюди, де провайдер підтримує кешування промптів.
Масштаб легко недооцінити. На мільйоні викликів лише незмінний системний промпт на 1800 токенів дає:
1,000,000 calls × 1,800 tokens
= 1.8 billion input tokens
і це ще без контексту конкретного завдання. Токени промпта — такі самі токени, як і всі інші. Роздутий промпт підвищував вартість API й на додачу з’їдав ліміт токенів на хвилину на кожному запиті, тож чищення допомогло двічі: знизило регулярні витрати на вхід і дало змогу вмістити більше корисної роботи в ті самі ліміти. Скорочення йшло раніше за кешування, адже кешування зайвого тексту лише законсервувало б початкову проблему проєктування.
Повтори — з backoff і jitter
Повтори становили 12% викликів. Багато з них ішли за відповіддю HTTP 429 про перевищення ліміту: система одразу повторювала запит майже в тих самих умовах, отримувала черговий 429 і часом, схоже, лише розтягувала період обмеження. Миттєвий повтор замінили експоненційним backoff і jitter. Backoff поступово збільшує затримку між спробами, а jitter додає трохи випадковості, щоб паралельні запити не повторювалися в ту саму мить. Обсяг повторів упав більш ніж удвічі.
Відхилені запити тарифікуються по-різному, але сліпі повтори все одно збільшують обсяг запитів і можуть запускати повторну платну роботу, якщо запит доходить до виконання моделлю. Тут контроль повторів підвищив надійність і заразом утримав витрати. Загальне правило: повтор має враховувати причину збою, а миттєве надсилання того самого запиту — це не відновлення.
Яка зміна найважливіша
Чотири зміни били по різних частинах рівняння вартості:
- Розподіл моделей за рівнями дав найбільше скорочення однієї статті: 46% викликів пішли на дешевшу модель, а дорога зберегла найважливішу роботу. На впровадження пішло близько дня.
- Маршрутизація через шлюз стала найпростішою миттєвою економією: вартість того самого набору моделей знизилася приблизно на 20% майже без інженерної роботи.
- Скорочення й кешування промпта прибрали регулярні накладні витрати на вхід, адже навіть найпростіше завдання тягло за собою промпт на 1800 токенів.
- Backoff і jitter скоротили зайвий обсяг запитів: частка повторів упала з 12% викликів до менш ніж половини від цього.
Разом вони дали більше, ніж будь-яка зміна окремо. Не складайте економію так, ніби це незалежні знижки. Ціни шлюзу змінюють тариф за токен, розподіл за рівнями — середньозважений тариф за кроками, скорочення промпта — кількість вхідних токенів, а контроль повторів — кількість запитів. Кожна зміна до того ж змінює базу, з якою працює наступна.
Як порахувати місячну вартість
Припустімо, система обробляє мільйон запитів на місяць, у середньому по 2000 вхідних і 500 вихідних токенів на запит. Місячний обсяг токенів:
Input:
1,000,000 × 2,000
= 2 billion tokens
Output:
1,000,000 × 500
= 500 million tokens
За цін за мільйон токенів базова місячна вартість така:
monthly cost =
2,000 × input price per 1M tokens
+
500 × output price per 1M tokens
У нас шлюз зрізав цю базу приблизно на 20% ще до архітектурних змін. Потім розподіл за рівнями знизив середньозважений тариф, бо 46% запитів перейшли на модель, токен якої коштує в рази дешевше. Скорочення промпта зменшило кількість вхідних токенів у кожному зачепленому запиті, а контроль повторів прибрав непотрібні запити. Тому для коректного розрахунку потрібні чотири змінні: обсяг запитів, співвідношення вхідних і вихідних токенів, розподіл моделей за кроками та актуальні ціни кожної моделі. Ось чому універсальної цифри «ви заощадите X%» не буває. Корисна оцінка виходить лише з вашого власного навантаження.
Три способи провалити роботу над вартістю
Оптимізувати рідкісні кроки, бо це легко. Спокусливо вичавити копійки з дрібного кроку, поки крок із великим обсягом з’їдає майже весь бюджет. Сортуйте цілі за сумарними витратами, а не за простотою зміни, — саме тому облік має бути першим.
Знижувати вартість, не перевіряючи якості. Крок переводять на дешевшу модель, рахунок падає, зміна виглядає перемогою. Через три тижні хтось помічає, що результат погіршився. Кожну заміну моделі пропускайте через оцінювальний набір — репрезентативну добірку завдань, яка ловить регресії. Економія, що не пройшла планку якості, — не оптимізація.
Будувати кеш до вимірювання повторного використання. Кеш допомагає лише там, де контент справді повторюється. Наворочений кеш, збудований до перевірки повторюваності промптів, може спалити інженерний час і не зачепити головного джерела витрат. Спершу з’ясуйте, скільки там повторів, і лише потім кешуйте ті префікси чи відповіді, які справді повертаються. Робота над вартістю без вимірювань може покращити рахунок і водночас погіршити якість, затримку чи надійність.
Не вимикайте метрики
Не вимикайте інструментування після першого проходу: витрати повзуть угору. Системний промпт потроху довшає, новий крок процесу стартує на дорогій моделі, повертається старий баг із повторами, або трафік перетікає на крок, який раніше був другорядним. Дашборд, що виявив початкову проблему, — це й те, що не дає їй тихо повернутися. Щомісячний розбір таблиці вартості за кроками займає хвилин десять і вже впіймав дві регресії.
Справа в архітектурі, а не в цінах
Ціна за токен — лише тариф. Скільки ви реально витрачаєте, залежить від архітектури: скільки токенів ви купуєте, які моделі їх обробляють і скільки роботи повторюється. Для навантаження нашого кодинг-агента найефективнішою виявилася така послідовність:
- Інструментувати кожен виклик за кроком процесу й моделлю.
- Узяти економію шлюзу, що не потребує зусиль.
- Спрямувати кожен крок на найдешевшу модель, яка відповідає його вимогам до якості.
- Прибрати повторювані накладні витрати промпта й кешувати стабільні префікси там, де це підтримується.
- Замінити сліпі повтори на backoff і jitter.
- Залишити моніторинг назавжди, щоб витрати не підкралися назад.
Найбільший виграш — розподіл за рівнями. Найшвидший — шлюз, майже 20%. Скорочення промпта прибрало постійні витрати з кожного запиту, а розумні повтори скоротили трафік повторів більш ніж удвічі. Полювання за найнижчою рекламною ціною токена важить значно менше, ніж розуміння того, куди йдуть ваші власні токени. Саме вимірювання роблять архітектуру видимою.