В прошлый раз я разбирал, куда именно ходит Claude Code и какие бывают ключи. Логичное продолжение — куда уходят деньги. Потому что первый вопрос, который возникает после недели работы с агентом: почему счёт растёт быстрее, чем кажется по объёму кода.

Ниже — разбор по полям usage, механика кэша и правила, которые у меня реально срезали расход. Без магии, всё проверяется в ответе API.

Из чего состоит счёт

Токены, за которые вы платите, делятся не на два типа, а минимум на пять:

Тип

Что это

Порядок цены

Input (miss)

Обычный ввод, который модель видит впервые

базовая

Cache write

Ввод, который провайдер положил в кэш

дороже базовой

Cache read

Ввод, найденный в кэше

примерно на порядок дешевле базовой

Output

То, что модель написала

в разы дороже ввода

Reasoning

Внутренние рассуждения модели

тарифицируется как output

Два последних пункта — главная ловушка. Reasoning-токены вы не видите в ответе, но платите за них по цене output. У моделей с высоким reasoning effort их бывает в несколько раз больше, чем полезного текста.

Точные множители смотрите в тарифах своего провайдера, они меняются. Важна не цифра, а порядок: чтение из кэша стоит копейки, запись в кэш — дороже обычного ввода, рассуждения стоят как ответ.

Как посмотреть это у себя

Anthropic-протокол возвращает в usage отдельные поля:

"usage": {
  "input_tokens": 37,
  "output_tokens": 211,
  "cache_creation_input_tokens": 0,
  "cache_read_input_tokens": 192
}

OpenAI-совместимый протокол прячет то же самое в details:

"usage": {
  "prompt_tokens": 90,
  "completion_tokens": 234,
  "total_tokens": 324,
  "prompt_tokens_details": {"cached_tokens": 0},
  "completion_tokens_details": {"reasoning_tokens": 230}
}

Обратите внимание на второй пример: из 234 токенов ответа 230 — это рассуждения. Полезного текста четыре токена, слово «работает». Заплатили вы за 234.

Первое, что стоит сделать, — начать логировать usage по каждому запросу. Без этого разговор о стоимости превращается в гадание.

Как на самом деле работает кэш

Провайдеры кэшируют не «похожие запросы», а совпадающий префикс. Правила простые и жёсткие:

  1. Совпадать должно начало запроса, байт в байт. System prompt, описания инструментов, правила проекта — всё, что идёт первым.

  2. Расхождение в одном символе в начале обнуляет весь кэш дальше.

  3. У кэша есть TTL. По умолчанию он короткий, порядка нескольких минут; у некоторых провайдеров есть опция продлить его за отдельную цену.

  4. Кэш привязан к организации и конкретной модели. Сменили модель — греете заново.

Отсюда типичные способы сжечь деньги на ровном месте:

  • Таймстемп или случайный request id в начале system prompt. Каждый запрос — холодный старт.

  • Динамическая сборка списка инструментов: сегодня в одном порядке, завтра в другом. Для кэша это разные префиксы.

  • Вставка нового контекста в середину, а не в конец.

  • Долгая пауза в сессии: подумали двадцать минут, вернулись — префикс протух.

Семь правил, которые я применяю

  1. Стабильный префикс. Системный промпт, инструменты и правила проекта не меняются в течение сессии. Всё изменяемое — в конец.

  2. Никаких таймстемпов, счётчиков и случайных id выше по тексту.

  3. Фиксированный порядок инструментов. Если список собирается кодом, сортируйте его детерминированно.

  4. Длинные документы — целиком и один раз, а не кусками в каждом сообщении.

  5. Reasoning effort под задачу. Для «переименуй переменные» высокий effort — это деньги на ветер. Для архитектурных вопросов наоборот.

  6. Уточняющие вопросы вместо переделок. Одна строчка «если что-то неясно, задай три вопроса перед началом» дешевле, чем два круга правок.

  7. Claude — только через Anthropic-протокол. Через OpenAI-совместимый endpoint часть реализаций теряет поля кэша, и вы платите полную цену за то, что могло читаться из кэша.

Минимальный скрипт для замера

Складывайте usage в jsonl и считайте два числа: долю чтения из кэша и долю рассуждений в ответе.

import json, sys

ci = cr = out = rs = 0
for line in open(sys.argv[1]):
    u = json.loads(line).get("usage", {})
    ci += u.get("input_tokens", u.get("prompt_tokens", 0))
    cr += u.get("cache_read_input_tokens",
                u.get("prompt_tokens_details", {}).get("cached_tokens", 0))
    out += u.get("output_tokens", u.get("completion_tokens", 0))
    rs += u.get("completion_tokens_details", {}).get("reasoning_tokens", 0)

print(f"cache hit: {cr / (ci + cr) * 100:.1f}%")
print(f"reasoning: {rs / out * 100:.1f}% от output")

У меня ориентир такой: на длинной сессии с агентом доля чтения из кэша должна быть высокой. Если она у вас около нуля, ищите, что ломает префикс, — это почти всегда даёт больше экономии, чем переход на модель подешевле.

Чего я не проверял

Поведение кэша под высокой параллельностью и точные TTL у разных провайдеров — это стоит мерить самому, цифры в документации и на практике иногда расходятся. Если у вас есть замеры, напишите в комментариях, добавлю в статью.

А ещё интересно: у кого какая доля reasoning-токенов на реальных задачах? У меня на рефакторинге доходило до 90% от output.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какая у вас доля reasoning-токенов от вывода на реальных задачах?
0%Меньше 20%0
0%20–50%0
0%50–80%0
0%Больше 80%0
100%Никогда не смотрел2
Проголосовали 2 пользователя. Воздержавшихся нет.