Назад до блогу

Оптимізація витратПосібник

Відстежуйте витрати API за проєктами та отримуйте попередження про бюджет у Python

Короткий скрипт Python перетворює ваш журнал використання на звіт про витрати за проєктами та попереджає на 50, 75, 95 і 100% місячного бюджету.

Автор: CheapTokens TeamОпубліковано 5 хв читання

Термінал зі звітом про витрати за проєктами та попередженням про бюджет
На цій сторінці
  1. Що випустив Anthropic і що ви можете скопіювати
  2. Журнал: один рядок на запит
  3. Скрипт: вартість за проєктом і попередження за порогами
  4. Запустіть і прочитайте результат
  5. Як виглядає місяць на дешевих моделях
  6. Де це йде не так

Додавайте один рядок JSON у файл після кожного виклику API, позначайте його назвою проєкту, і нехай 30-рядковий скрипт Python перетворить цей файл на звіт про витрати за проєктами та попередження на 50, 75, 95 і 100% вашого місячного бюджету. Це той самий вигляд, який Anthropic щойно надав командам Claude Enterprise, зібраний з вашого власного журналу.

Припустімо, один баланс живить агента, скрипт для чернеток блогу та невеликого бота підтримки. Настає кінець місяця, баланс нижчий, ніж ви сподівалися, і ніщо не підказує, хто з трьох у цьому винен. Саме цю прогалину це закриває.

Що випустив Anthropic і що ви можете скопіювати#

Оголошення Anthropic (28 жовтня 2026) охоплює розумні звіти, опитування в застосунку та спільні групові бюджети, загальнодоступні лише на планах Claude Enterprise (source). Тут важливі дві частини. Звіт групує роботу команди в робочі потоки та показує витрати кожного. Спільний бюджет — це одне спільне місячне число, і адміністратори білінгу отримують лист на 50%, 75%, 95% і 100% від нього. Anthropic додає, що звіти призначені для планування інвестицій, а не для оцінювання окремих людей.

Вам не потрібен корпоративний план для тієї самої форми. Робочий потік — це просто мітка, яку ви обираєте, а чотири пороги — це один список у коді. Групуйте за проєктом, а не за людиною, з тієї причини, яку наводить Anthropic.

Швидка перевірка

Ваш передплачений баланс уже зупиняє запити на нулі. Навіщо додавати попередження на 50% і 75%?

Показати відповідь

Відповідь: Бо нуль — це запізно: ви хочете помітити цикл, що вийшов з-під контролю, поки ще є гроші, щоб у нього зазирнути

Баланс — це жорстка зупинка, а не сигнал тривоги. Ранні пороги перетворюють несподіванку на 100% на питання дев'ятого дня.

Журнал: один рядок на запит#

Кожна відповідь chat completion містить об'єкт usage з prompt_tokens і completion_tokens. Це все, що потрібно звіту, плюс мітка проєкту, яку ви додаєте самі. Ця обгортка надсилає запит і дописує один рядок у місячний файл (ім'я файлу змінюється щомісяця, тож новий місяць починається з нуля):

python
import json, os, time
from openai import OpenAI

client = OpenAI(base_url="https://api.cheaptokens.dev/v1",
                api_key=os.environ["CHEAPTOKENS_API_KEY"])

def ask(project, model, messages):
    r = client.chat.completions.create(model=model, messages=messages)
    with open(time.strftime("usage-%Y-%m.jsonl"), "a") as f:
        f.write(json.dumps({"project": project, "model": model,
                            "prompt_tokens": r.usage.prompt_tokens,
                            "completion_tokens": r.usage.completion_tokens}) + "\n")
    return r

ask("support-bot", "zai-org/GLM-5.3-Flash",
    [{"role": "user", "content": "Where is my order?"}])

Використовуйте повний id моделі з документації CheapTokens (deepseek-ai/DeepSeek-V4-Flash-0731, zai-org/GLM-5.3-Flash); короткі назви з таблиць цін API не приймає. Ключ береться зі змінної середовища, ніколи з файлу.

Потік від кожного запиту до журналу використання, звіту за проєктами та попереджень
Як запит стає рядком у журналі, потім звітом і попередженням

Скрипт: вартість за проєктом і попередження за порогами#

Збережіть це як report.py. Ціни — це заповнювачі: скопіюйте поточні з таблиці цін (обидві моделі мають тут одну прикладну ціну лише для того, щоб арифметика залишалася читабельною).

python
import json, os, sys, time
from collections import defaultdict

LOG = time.strftime("usage-%Y-%m.jsonl")
BUDGET = float(os.environ.get("BUDGET_USD", "10"))  # example, substitute your own
STATE = LOG + ".alert"
LEVELS = [50, 75, 95, 100]
PRICES = {  # USD per 1M tokens (input, output): example, substitute current prices
    "deepseek-ai/DeepSeek-V4-Flash-0731": (1.0, 2.0),
    "zai-org/GLM-5.3-Flash": (1.0, 2.0),
}

spend = defaultdict(float)
with open(LOG) as f:
    for line in f:
        r = json.loads(line)
        p_in, p_out = PRICES[r["model"]]
        spend[r["project"]] += (r["prompt_tokens"] * p_in
                                + r["completion_tokens"] * p_out) / 1_000_000

total = sum(spend.values())
if total == 0:
    sys.exit("log is empty")

for name, usd in sorted(spend.items(), key=lambda kv: -kv[1]):
    print(f"{name:<8} ${usd:6.2f} {usd / total:5.0%}")
print(f"{'total':<8} ${total:6.2f} of ${BUDGET:.2f} ({total / BUDGET:.0%})")

last = int(open(STATE).read()) if os.path.exists(STATE) else 0
crossed = [l for l in LEVELS if total >= BUDGET * l / 100 and l > last]
if crossed:
    print(f"WARNING: budget passed {crossed[-1]}%")
    open(STATE, "w").write(str(crossed[-1]))

Останні чотири рядки — це те, що люди забувають. Без маленького файлу стану скрипт кричав би "перевищено 50%" під час кожного запуску до кінця місяця. З ним кожен рівень спрацьовує один раз.

Запустіть і прочитайте результат#

Візьміть іграшковий журнал із чотирьох рядків (справжній має рядок на запит, тобто тисячі):

text
{"project": "agent", "model": "deepseek-ai/DeepSeek-V4-Flash-0731", "prompt_tokens": 2400000, "completion_tokens": 300000}
{"project": "agent", "model": "deepseek-ai/DeepSeek-V4-Flash-0731", "prompt_tokens": 1000000, "completion_tokens": 100000}
{"project": "blog", "model": "zai-org/GLM-5.3-Flash", "prompt_tokens": 800000, "completion_tokens": 400000}
{"project": "bot", "model": "zai-org/GLM-5.3-Flash", "prompt_tokens": 500000, "completion_tokens": 100000}

З прикладними цінами та бюджетом 10, python report.py виводить:

text
agent    $  4.20   65%
blog     $  1.60   25%
bot      $  0.70   11%
total    $  6.50 of $10.00 (65%)
WARNING: budget passed 50%

Агент — це майже дві третини рахунку, і попередження прийшло на 50%, а не в кінці. Запустіть ще раз, і попередження мовчатиме, доки загальна сума не досягне 75%.

Термінал із звітом за проєктами та попередженням на 50%
Вивід звіту на іграшковому журналі: частки за проєктами та перше попередження

Щоб це працювало щомісяця, потрібні три кроки:

Крок за кроком

Підключіть це в три кроки

Логуйте кожен виклик

Спрямуйте всі свої виклики через ask(project, model, messages) і оберіть коротку, стабільну мітку проєкту. Перейменування міток посеред місяця розділяє один проєкт на два рядки.

Задайте ціни та бюджет

Вставте поточні ціни з таблиці цін у PRICES і експортуйте свій ліміт: export BUDGET_USD=25.

Запускайте за розкладом

Щогодинного рядка cron достатньо: 0 * * * * cd ~/ai && python3 report.py. Надсилайте вивід у команду пошти чи чату, якщо хочете, щоб попередження приходило вам.

Як виглядає місяць на дешевих моделях#

Числа стають корисними, коли вони ваші. Припустімо, агент з іграшкового журналу в середньому використовує 30 000 вхідних і 2 000 вихідних токенів на крок, 20 кроків на завдання, два завдання на день. Один крок на DeepSeek-V4-Flash коштує $0.00065; на GLM-5.3-Flash — $0.00068. День — це 40 кроків, місяць — 1 200. Посуньте повзунки, щоб відповідати вашому власному агенту:

Калькулятор вартості

Один день агента: кроки на завдання, помножені на завдання на день

Вхідні токени на запит: 30 000 · Вихідні токени на запит: 2 000 · Запитів на день: 40

МодельЗа деньЗа місяць
GLM-5.3-Flash$0.0272$0.816
DeepSeek-V4-Flash$0.026$0.78
MiniMax-M2.7$0.072$2.16

А місяць на 1 200 кроків, з урахуванням вхідних і вихідних разом:

Модель За запит 1 200 запитів OpenRouter, 1 200 запитів
GLM-5.3-Flash $0.00068 $0.816 $1.41
DeepSeek-V4-Flash $0.00065 $0.78 $2.86
MiniMax-M2.7 $0.0018 $2.16 $25.92

30 000 вхідних і 2 000 вихідних токенів на запит. Ціни за 1 млн токенів актуальні та змінюються разом із нашими тарифами; стовпець OpenRouter показує довідкові ціни для того самого навантаження.

Загалом, з урахуванням вхідних і вихідних разом, обидві моделі виходять дешевшими за довідкові ціни OpenRouter у тій таблиці, з однією ціною в будь-яку годину і без пікової надбавки. DeepSeek-V4-Flash також дозволяє до 32 768 вихідних токенів на відповідь і контекст 380K; GLM-5.3-Flash має контекст 390K. Щойно звіт покаже, який проєкт є важким, перемикання лише рядка model цього проєкту — це зміна в один рядок, і один баланс покриває кожну модель. Про те, скільки токенів насправді використовує один запит, дивіться скільки токенів використовує запит API; про зупинку одного запуску агента посередині дивіться відстеження вартості токенів AI-агента. Ціни та моделі — на сторінці моделей CheapTokens.

Де це йде не так#

  • Моделі немає в PRICES. Скрипт зупиняється з KeyError, який називає модель. Додайте її; не ставте за замовчуванням нуль, інакше проєкт виглядатиме безкоштовним.
  • Стрімінгові виклики. Останній фрагмент містить usage, лише якщо ви його попросите (stream_options={"include_usage": True} в OpenAI SDK). Інакше у вашому журналі будуть прогалини.
  • Невдалі запити. Логуйте лише відповіді, що мають об'єкт usage; запит, який завершився помилкою, нема чого рахувати.
  • Звіти за людьми. Тримайте мітку як назву проєкту або агента. Звіт про людей спонукає до хибних висновків.