Як контролювати витрати AI-агента на VPS
Дізнайтеся, як обмежити витрати unattended agent: ліміти відповідей, бюджет завдання, кешування промптів, пакетна обробка та поля usage для контролю API.
Як не дозволити постійно запущеному AI-агенту перевищити бюджет
Контроль витрат AI-агента на VPS (virtual private server) ґрунтується на обмеженнях, які ви встановлюєте до запуску агента, оскільки під час його роботи ніхто не стежить за лічильником. Обмежуйте кожну відповідь за допомогою max_tokens, обмежуйте кількість ітерацій циклу у власному коді, кешуйте незмінну частину промпту та записуйте в журнал показники використання для кожної відповіді, щоб визначити, яке завдання витрачає кошти. Оренда сервера має фіксовану місячну ціну. API моделі тарифікується за кількістю токенів, а цикл без нагляду легко витрачає токени непомітно.
Тут мається на увазі агент, який уже існує та викликає Messages API із сервера, яким ви керуєте. У матеріалі Як створити AI-агента з Claude на VPS описано саму інфраструктуру.
Чому unattended agent має іншу структуру витрат
В інтерактивній сесії бере участь людина. Якщо модель рухається неправильним шляхом або читає журнал на 40,000 рядків, користувач зупиняє її. У unattended agent такого обмеження немає: він працює, доки цикл не завершиться, а потім таймер запускає його знову.
Частота — це множник, який часто не враховують. Завдання за розкладом кожні п’ять хвилин запускається 288 разів на день і приблизно 8,640 разів на місяць. Незалежно від вартості одного запуску, саме на цю кількість її потрібно помножити. Багатьом "always-on" агентам не потрібно працювати постійно. Їм потрібно відповідати протягом певної кількості хвилин. Це означає, що достатньо розкладу.
Agent також оплачує те, за що вікно чату не стягує плату.
- Визначення інструментів передаються з кожним запитом. System prompt для використання інструментів коштує 290 токенів у Claude Opus 4.8 з
tool_choiceізautoабоnone, і 410 — ізanyабоtool. Інструмент bash додає ще 325 токенів. Кожен MCP server, який ви підключаєте, додає до цього обсягу власні схеми; MCP — це протокол контексту моделі. - Результати роботи інструментів є вхідними токенами. Команда, яка виводить 8,000 рядків, додає 8,000 рядків до наступного запиту та до кожного наступного запиту в межах цього ходу.
- Отримані сторінки є вхідними токенами. Середня вебсторінка розміром 10 kB — це приблизно 2,500 токенів, а дослідницький PDF розміром 500 kB — приблизно 125,000 токенів.
max_content_tokensобрізає лише текстові дані, оскільки цей параметр "застосовується до текстового вмісту, а не до двійкового вмісту, такого як PDF". Для PDF натомість використовуйтеmax_usesіallowed_domains, щоб обмежити його обсяг. - Пошук у вебі оплачується за кожен пошуковий запит — $10 за 1,000 пошукових запитів, незалежно від кількості отриманих результатів. Пошуковий запит із помилкою не тарифікується.
Жодна з цих статей витрат не є значною для одного запуску. Але всі вони стають значними 8,640 разів.
Жорсткі та м’які ліміти розв’язують різні проблеми
max_tokens застосовується примусово. Це жорстке обмеження на загальний обсяг одного запиту: разом на роздуми й текст відповіді. Claude ніколи не генерує понад це значення, а модель не бачить самого числа. Після досягнення ліміту з’являється stop_reason: "max_tokens", а відповідь обрізається. Для агентів важливо, що кожен запит у циклі використання інструментів має власний max_tokens. Тому цей ліміт обмежує одну відповідь, а не все завдання. Десять викликів інструментів по 4,000 дають для цього ходу ліміт 40,000 токенів.
Бюджет завдання має рекомендаційний характер. task_budget є частиною output_config і повідомляє моделі, скільки токенів доступно для всього агентного циклу, включно з роздумами, викликами інструментів, результатами інструментів і вихідними даними.
resp = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
betas=["task-budgets-2026-03-13"],
output_config={"task_budget": {"type": "tokens", "total": 64000}},
messages=messages,
)"Бюджет завдання — це м’яка підказка, а не жорсткий ліміт." Claude може перевищити його під час однієї дії, тоді як примусове обмеження вихідних даних усе одно становить max_tokens. "Зворотний відлік бачить лише модель", а відповіді не містять поля із залишком бюджету. Мінімальне прийнятне значення task_budget.total — 20,000 токенів; менше значення повертає помилку 400. Якщо бюджету недостатньо для роботи, модель може поводитися так, ніби відмовляється: звузити завдання або завершити його раніше.
Одна деталь збільшує витрати замість їх зменшення. Якщо ваш клієнт зменшує task_budget.remaining у кожному наступному запиті, змінене значення робить недійсним кешований префікс, який його містить. Встановіть це значення один раз, у першому запиті.
Бюджети завдань мають статус beta у Claude Fable 5, Claude Opus 4.8 і Claude Opus 4.7. Claude Sonnet 5 і Claude Haiku 4.5 позначені як Not supported, а бюджети завдань не застосовуються до Claude Code. Тому сесія Claude Code, від’єднана в tmux, залежить від належного керування сесіями.
Третій ліміт налаштовується в Claude Console: надайте агенту окремий workspace, потім встановіть для нього місячний ліміт витрат і обмеження швидкості запитів за хвилину. "Для Default Workspace не можна встановити ліміти", а "загальноорганізаційні ліміти застосовуються завжди, навіть якщо сума лімітів workspace більша". Додайте сповіщення про витрати, щоб отримати повідомлення про досягнення порогу до перевищення ліміту.
Вибір моделі для кожного завдання та фактичний вплив effort
Вибір моделі залежить від конкретного завдання. Станом на July 2026 вартість за мільйон токенів, спочатку вхідних, потім вихідних: Claude Fable 5 — $10 і $50, Claude Opus 4.8 та Opus 4.7 — $5 і $25, Claude Sonnet 5 — $3 і $15, Claude Haiku 4.5 — $1 і $5. Наразі Sonnet 5 коштує менше за вказану ціну, оскільки діє «вступна ціна $2/$10 за мільйон вхідних/вихідних токенів до August 31, 2026». Крок, який лише класифікує рядки журналу, не потребує Opus. Безкоштовної квоти, яка могла б покрити інтенсивний розклад, також немає, оскільки Claude API не має безкоштовного рівня поза невеликим кредитом, наданим під час реєстрації.
Effort — другий важіль керування витратами. output_config.effort приймає low, medium, high, xhigh і max, а значенням за замовчуванням є high, тому явне встановлення high еквівалентне його пропуску. Нижчий effort скорочує не лише тривалість міркування: у документації зазначено, що Claude виконує менше викликів інструментів і об’єднує операції в один виклик. Для агента це дає більшу економію, оскільки пропущений виклик інструмента означає цілий запит, який не виконується.
Проблема в тому, що effort конфліктує з кешуванням. Зміна цього значення між запитами анулює кешування prompt. У прикладі з документації для запиту 2 було вказано cache_read_input_tokens: 3546; для запиту 3, де effort змінено з high на medium, було вказано cache_creation_input_tokens із 3546 і cache_read_input_tokens із 0. Тому змінюйте effort між різними робочими навантаженнями, але не в межах одного кешованого діалогу. Щоб керувати глибиною відповіді без порушення кешу, робіть це в prompt: рядок на кшталт «Відповідай безпосередньо, без детального обмірковування.» у найновішому повідомленні користувача зберігає попередні точки кешування.
Токени міркування оплачуються за тарифом для вихідних токенів і враховуються в max_tokens. Саме тому обрізана відповідь часто означає, що бюджет витрачено на міркування. Перевіряйте usage.output_tokens_details.thinking_tokens, щоб дізнатися кількість. У матеріалі Що саме формує рахунок Claude за токени описано складові цього лічильника.
Кешуйте стабільний префікс і не руйнуйте його випадково
Запис у кеш коштує 1.25 базової ціни вхідних даних для кешу на п’ять хвилин і 2 рази більше для кешу на одну годину. Читання з кешу коштує 0.1 базової ціни, тому «кешування окупається вже після одного читання з кешу для тривалості 5 хвилин (запис за 1.25x) або після двох читань з кешу для тривалості 1 година (запис за 2x)».
Одне речення пояснює, чому це підходить для агента, який працює постійно: «Кеш оновлюється без додаткової плати щоразу, коли використовується кешований вміст». Завдання, яке запускається кожні дві хвилини й звертається до кешу на п’ять хвилин, підтримує свій префікс прогрітим увесь день за один запис.
Є три способи непомітно втратити кеш.
Префікс змінюється. «Префікси кешу створюються в такому порядку: tools, system, потім messages». Будь-яка зміна байта на початку цього порядку робить недійсним усе, що йде після нього, а редагування визначень інструментів робить недійсним увесь кеш. Класична помилка, яку спричиняють самі користувачі, — timestamp або run id у system prompt: тоді кожен запит містить інший префікс, записує новий запис за ціною 1.25x і нічого не читає з кешу. Ознака цього — usage.cache_read_input_tokens зі значенням 0 для викликів, які на вигляд однакові. Перемістіть змінний текст у найновіше user message.
Префікс надто короткий. Для кожної моделі визначено мінімальну довжину, придатну для кешування. Якщо запит коротший, його обробляють без кешування, і «жодної помилки не повертають». Зокрема, це 1,024 токени для Claude Opus 4.8 і Claude Sonnet 5 та 4,096 для Claude Haiku 4.5. Тому перенесення завдання із Sonnet на Haiku може непомітно вимкнути кешування.
Розмова виходить за межі lookback. «Вікно lookback становить 20 блоків». Система перевіряє не більше 20 позицій для кожної breakpoint, а потім припиняє перевірку. У задокументованому прикладі turn містить 35 блоків, а breakpoint встановлено на блоці 35. Система перевіряє блоки від 35 до 16, тоді як запис попереднього turn на блоці 15 виходить за межі вікна, тому cache hit не відбувається. Агент, який додає кілька блоків tool-use і tool-result за один turn, перевищує межу 20 за два або три turn. На кожен запит припадає чотири breakpoint, тому один із них варто використати для останніх повідомлень.
Передавайте все, що може зачекати, до Batches API
«Усі запити оплачуються за 50% стандартних цін API» — і для вхідних, і для вихідних даних. Обробка batch-запитів асинхронна: «більшість batch-запитів завершується менш ніж за 1 годину». Результати доступні після завершення всіх запитів або через 24 години — залежно від того, що настане раніше. Це типовий показник, а не гарантія.
Опитуйте processing_status, доки його значення не стане ended. Запити зі статусом errored, canceled або expired не оплачуються. Якщо ви використовуєте ліміт витрат, врахуйте один нюанс: «batch-запити можуть незначно перевищити налаштований ліміт витрат вашого Workspace».
Знижки сумуються. Оскільки виконання batch-запиту може тривати понад 5 хвилин, документація рекомендує одногодинне кешування для batch-запитів зі спільним контекстом. Розділіть обробку: усе, чого очікує користувач або webhook, залишайте в оперативному контурі, а нічний дайджест чи класифікацію журналів за вчора передавайте до batch за половину ціни.
Записуйте поля використання кожної відповіді у власне сховище
Неможливо віднести витрати, які ви не записували. Кожна відповідь містить дані про свою вартість.
u = resp.usage
row = {
"job": job_name,
"model": resp.model,
"uncached_input": u.input_tokens,
"cache_write": u.cache_creation_input_tokens,
"cache_read": u.cache_read_input_tokens,
"output": u.output_tokens,
"stop_reason": resp.stop_reason,
}Додавайте один рядок для кожного API-виклику до файлу у форматі JSON Lines і позначайте його назвою завдання. Через тиждень ви зможете визначити, яке завдання витрачає кошти, а яке лише створює видимість активності. Стежте за cache_read: стовпець із нульовими значеннями — найпоширеніша помилка під час обліку витрат у self-hosted агенті.
Одне поле легко неправильно інтерпретувати. input_tokens враховує лише токени після останньої точки кешування, тому фактичний розмір prompt дорівнює total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens. Якщо агент повідомляє input_tokens: 400 для великого prompt, це не означає низьку вартість: решта токенів надійшла з кешу.
Підраховуйте токени до надсилання запиту. Підрахунок токенів безкоштовний, а його rate limits окремі від лімітів створення повідомлень, тому використовуйте count_tokens, щоб відхилити вкладення, яке перевищує допустимий розмір, замість того щоб платити й лише потім виявити проблему. Результат є оцінкою, тому виконуйте повторний вимір для кожної моделі й ніколи не використовуйте підрахунок, отриманий за допомогою tokenizer іншого постачальника. Claude Opus 4.7 і новіші моделі Opus, Claude Fable 5 та Claude Sonnet 5 використовують новий tokenizer, який «генерує приблизно на 30% більше токенів для того самого тексту». Claude Sonnet 4.6 і старіші моделі, зокрема Claude Haiku 4.5, використовують попередній tokenizer.
Для отримання офіційних даних Admin API повідомляє інформацію про використання за адресою https://api.anthropic.com/v1/organizations/usage_report/messages, а дані про вартість — за адресою https://api.anthropic.com/v1/organizations/cost_report. Обидва запити використовують admin key (sk-ant-admin01-...) як x-api-key: $ANTHROPIC_ADMIN_KEY із anthropic-version: 2023-06-01, а також приймають bucket_width=1d, group_by[]=model і api_key_ids[]=. Є одне обмеження: «Admin API недоступний для індивідуальних облікових записів».
Останній параметр дає змогу недорого віднести витрати до конкретних завдань: призначте кожному завданню власний API key, фільтруйте за допомогою api_key_ids[], а звіт розділяйте за ключем за допомогою group_by[]=api_key_id. Фільтр використовує множину, а вимір групування — однину. Зберігайте ключі в environment, а не в коді, як це робить перший Claude API застосунок на VPS.
Обмежте цикл, бо більше ніхто цього не зробить
Обмежена кількість ітерацій тут обов’язкова. Цикл належить вам, тому лічильник також має бути під вашим контролем:
for step in range(MAX_STEPS): # MAX_STEPS = 12, never "while True"
resp = client.messages.create(...)
if resp.stop_reason != "tool_use":
break
else:
log.warning("job %s hit MAX_STEPS=%d, giving up", job_name, MAX_STEPS)Жоден із наведених вище лімітів не вирішує це завдання: max_tokens обмежує одну відповідь, а модель лише отримує рекомендацію щодо бюджету завдання. Hosted-продукт зупинив би виконання на цьому етапі, як ліміт Claude на виклики інструментів у межах одного turn, який зупиняє сесію після надмірної кількості викликів. Але цикл, написаний вами самостійно, не має такого запобіжника, доки ви його не додасте.
Додайте другий запобіжник за межами процесу. Запускайте завдання через systemd timer, а в його service unit задайте RuntimeMaxSec=. За допомогою RuntimeMaxSec=600 завислий запуск буде завершено через десять хвилин, а не продовжуватиметься, доки ви його не помітите. У матеріалі Запуск програми як systemd service і timer описано самі unit-файли. Переглядайте результати запуску за допомогою journalctl -u triage-agent.service --since "1 hour ago".
Також обмежте кількість повторних спроб, оскільки handler, який повторює спроби без кінця, оплачує кожну з них. Помилки 429 або 500 виправдовують кілька спроб із backoff. Для помилки 400 повторні спроби не потрібні, оскільки той самий запит завершиться так само.
Контроль витрат AI-агента починається з аналізу власних показників
Ніхто не може сказати, скільки коштує агент, що працює постійно, тому що вартість — це кількість токенів за один запуск, помножена на кількість запусків на день. Обидва показники залежать від вас. Запустіть агент один раз, перегляньте запис про використання, який ви зберегли, і помножте його на свій розклад запусків. Через два дні порівняйте звіт про витрати з цим розрахунком. Якщо значення не збігаються, причина майже завжди полягає в непрацюючому кеші або циклі, який виконувався довше, ніж ви припускали.
Це передбачає використання API key, оскільки агент є вашою власною програмою, яка викликає Messages API. Для власної інтерактивної роботи в матеріалі який план Claude відповідає вашому способу роботи описано варіанти підписки. Усі наведені тут ціни й ліміти перевірено за документацією Anthropic у July 2026, тому перед складанням бюджету ще раз перегляньте сторінку з цінами.
FAQ
Скільки коштує запуск постійно активного AI-агента на VPS?
Є два рахунки, і лише один із них передбачуваний. Сервер має фіксовану щомісячну вартість. API моделі оплачується за кількістю токенів, тому вартість одного запуску потрібно помножити на частоту запусків. Anthropic не публікує даних про вартість self-hosted постійно активного агента, тому будь-яке наведене число слід вважати приблизним. Запишіть usage під час одного реального запуску та помножте це значення на ваш розклад запусків.
У чому різниця між max_tokens і бюджетом завдання?
max_tokens застосовується примусово, але модель його не бачить. Він обмежує вихідні дані одного запиту, включно з міркуваннями, а досягнення цього ліміту повертає stop_reason: "max_tokens". Бюджет завдання працює навпаки: моделі повідомляють це число, і вона регулює агентний цикл відповідно до нього, але «Task budgets are a soft hint, not a hard cap», а фактичним примусовим обмеженням залишається max_tokens.
Чому cache_read_input_tokens завжди дорівнює нулю для мого агента?
Тому що префікс змінюється між викликами або він занадто короткий для кешування. Зазвичай причиною є timestamp або run id, інтерпольований у system prompt: кеш використовує префікс як ключ, тому будь-яка зміна байта робить увесь наступний вміст недійсним для кешу. Зміна визначень інструментів або значення effort дає такий самий результат. В іншому разі причина полягає в розмірі: коротші промпти не кешуються, і помилка не повертається.
Як зупинити AI-агента, щоб він не зациклювався назавжди?
Підраховуйте ітерації у коді циклу та зупиняйте його після досягнення фіксованого максимуму, оскільки max_tokens обмежує одну відповідь, а агент виконує багато таких відповідей. Додайте обмеження за реальним часом поза межами процесу: запускайте завдання через systemd timer із заданим RuntimeMaxSec=, щоб завислий запуск було примусово завершено за розкладом. Також обмежте кількість повторних спроб, оскільки кожна спроба в циклі повторення оплачується окремо.
Чи можна встановити ліміт витрат для одного ключа Claude API?
Задокументований ліміт витрат застосовується до workspace, а не до окремого ключа, тому створіть для агента окремий workspace і встановіть у ньому місячний ліміт витрат. «You cannot set limits on the Default Workspace». Додайте сповіщення про витрати, щоб спочатку отримати повідомлення про досягнення порогу. Для атрибуції призначте кожному завданню власний ключ, а потім згрупуйте звіт про використання за допомогою group_by[]=api_key_id.