Как посчитать стоимость запроса заранее через count_tokens

Перед тем как жечь баланс на длинный промпт, можно бесплатно узнать, во сколько токенов он обойдётся. Разбираем, как это сделать одним запросом.

4 мин · · Обновлено · API · экономия

Длинный системный промпт, история переписки, десяток файлов в контексте — и непонятно, сколько это будет стоить, пока не отправишь запрос и не увидишь списание. Есть способ узнать это заранее, бесплатно и без обращения к модели.

Зачем считать токены до запроса

Каждый вызов /v1/messages или /v1/chat/completions списывает деньги по факту использованных токенов — это видно в заголовке ответа X-Zukko-Cost-Micros уже постфактум. Но если у вас большой батч запросов, RAG с длинным контекстом или просто привычка проверять смету перед стартом, ждать факта списания неудобно. Для этого есть отдельный эндпоинт, который не трогает модель вообще.

POST /v1/messages/count_tokens

Эндпоинт принимает то же тело, что и обычный запрос к /v1/messages — модель, сообщения, системный промпт, — но не выполняет генерацию, а только считает токены входа. Стоит это ноль, потому что до модели запрос не доходит.

bash
curl https://api.zukko.pro/v1/messages/count_tokens \
  -H "Authorization: Bearer fetch_ваш_ключ" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-5",
    "messages": [
      {"role": "user", "content": "Перескажи содержание приложенного файла в трёх пунктах"}
    ],
    "system": "Ты помощник, который отвечает кратко и по делу."
  }'

Ответ — просто число:

bash
{"input_tokens": 42}

Обратите внимание: заголовок anthropic-version: 2023-06-01 обязателен, как и для основного /v1/messages — это тот же протокол, просто другой путь.

Считаем на Python

Для батча из нескольких промптов удобнее сделать функцию:

bash
import requests

API_KEY = "fetch_ваш_ключ"
BASE_URL = "https://api.zukko.pro"

def count_tokens(messages, model="claude-sonnet-5", system=None):
    payload = {"model": model, "messages": messages}
    if system:
        payload["system"] = system
    resp = requests.post(
        f"{BASE_URL}/v1/messages/count_tokens",
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "anthropic-version": "2023-06-01",

Так можно прогнать весь список промптов перед батч-обработкой и отсеять те, что случайно раздулись — например, из-за забытого дебажного вывода, вставленного в контекст целиком.

От токенов к деньгам

count_tokens считает только входные токены — это ожидаемая часть расхода, известная до старта. Итоговая стоимость запроса добавит ещё токены выхода, которые заранее неизвестны (зависят от max_tokens и того, что реально сгенерирует модель). Точные тарифы по каждой модели — в GET /v1/models/info, это тоже открытый эндпоинт, ключ не нужен:

bash
curl https://api.zukko.pro/v1/models/info

Оттуда берём цену за миллион входных токенов для нужной модели и умножаем на число из count_tokens — это даст нижнюю границу стоимости запроса, без учёта генерации.

Если нужен OpenAI-совместимый режим

У /v1/chat/completions и /v1/responses отдельного эндпоинта подсчёта токенов нет — считать нужно через Anthropic-путь /v1/messages/count_tokens, даже если сам запрос вы потом отправите в OpenAI-совместимом формате на /v1/chat/completions. Токенизация не идентична между семействами моделей один в один, но для оценки порядка величины (важно вписаться в лимит контекста — 1 000 000 токенов у Claude и GPT, 128K у GLM — или прикинуть бюджет) этого достаточно — просто соберите то же сообщение в формате messages и посчитайте.

Практический сценарий: проверка перед батчем

Если вы прогоняете, скажем, тысячу документов через модель, разумно сначала посчитать токены по каждому и отсеять выбросы:

bash
docs = load_documents()  # список текстов
oversized = []

for doc in docs:
    tokens = count_tokens([{"role": "user", "content": doc}])
    if tokens > 50000:
        oversized.append((doc, tokens))

print(f"Документов длиннее 50k токенов: {len(oversized)}")

Это займёт секунды и не спишет ни цента, а сэкономит время на отладке, если один из документов окажется на порядок длиннее остальных из-за, например, склеенного бинарного мусора в тексте.

Не путайте с обычным списанием

count_tokens не тратит бюджет ключа и не отображается в истории GET /v1/usage, потому что это не оплачиваемый вызов — только подсчёт. Так же ведут себя и попадания в кэш (X-Zukko-Cache: hit): они тоже не пишутся в /v1/usage. Если нужно свериться с историей реальных расходов, используйте /v1/usage с курсорной пагинацией — там будут только фактические оплаченные вызовы к модели, без записей от count_tokens и кэш-попаданий.

Ещё момент: count_tokens считает входные токены ровно так же, как их посчитает сама модель при настоящем запросе, — значит, если в сообщение добавлен системный промпт или изображение, итоговое число токенов изменится соответственно. Для сообщений с картинками (изображения принимают модели Claude и GPT; glm-5.3 и glm-5.3-flash — нет) в тело count_tokens нужно передавать ту же структуру content с блоком изображения, что пойдёт в реальный запрос, иначе оценка выйдет заниженной и разойдётся с фактическим списанием.

Итого

count_tokens — это бесплатная проверка размера запроса перед тем, как платить за него. Полезно для оценки бюджета, отладки промптов, которые неожиданно выросли, и фильтрации входных данных перед батч-обработкой. Для точной сметы стоимости добавьте к результату цену модели из /v1/models/info, а после реального запроса сверьте с X-Zukko-Cost-Micros в ответе (он есть у обычных, не потоковых ответов) — это фактическое списание.

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.