Skip to main content
Каждый ответ LLM содержит объект usage, сообщающий о токенах, которые израсходовал запрос. Sunra сообщает об использовании в семантике того endpoint, который вы вызвали: ответ Messages следует контракту Anthropic, а ответ Chat Completions или Responses — контракту OpenAI. Эти структуры различаются, и это сделано намеренно. OpenAI SDK, читающий ответ Chat Completions, предполагает семантику OpenAI, а Anthropic SDK, читающий ответ Messages, предполагает семантику Anthropic. Каждый endpoint соблюдает то, что обещает его собственная спецификация, вместо того чтобы принудительно приводиться к одной общей структуре.
/v1/messages и /v1/responses используют одно и то же имя поля input_tokens, но означает оно на них не одно и то же. В Messages это только свежий ввод. В Responses это весь промпт, включая кэшированные токены.

Messages

В /v1/messages три входные корзины взаимоисключающие. Ни один токен не учитывается дважды, поэтому итог по промпту — их сумма:
integer
Только свежие входные токены. Исключает обе корзины кэша.
integer
Токены, записанные в кэш этим запросом.
integer
Токены, переданные этому запросу из кэша.
integer
Токены, сгенерированные моделью.
integer
Три входные корзины плюс output_tokens. Присутствует в непотоковых ответах.
Отсутствующая корзина или корзина со значением null считается нулём.

Разобранный пример

Один и тот же префикс в 19 000 токенов, отправленный дважды к claude-opus-4-8. Первый запрос записывает кэш, второй — читает его.
Холодный запрос (запись в кэш)
Тёплый запрос (чтение из кэша)
input_tokens остаётся равным 8 в обоих запросах, потому что 8 — это действительно новый ввод в каждом случае. Префикс в 19 349 токенов перемещается из корзины создания в корзину чтения. Оба запроса дают в сумме одинаковые 19 359 токенов, но стоят они не одинаково: запись в кэш и чтение из кэша тарифицируются по своим собственным ставкам за токен, поэтому они и указываются как отдельные корзины.

Chat Completions и Responses

Эти endpoint сообщают семантику OpenAI без изменений. Количество токенов промпта — это весь промпт, а кэшированные токены являются его подмножеством, указываемым отдельно.
/v1/chat/completions
Суммирование prompt_tokens и cached_tokens приводит к двойному учёту. Чтобы получить свежий ввод на этих endpoint, вычтите:
То же правило применимо к /v1/responses с input_tokens и input_tokens_details.cached_tokens.

Маркер sunra_usage_semantics

Ответы, которые Sunra нормализовала, несут маркер внутри usage:
Маркер — это обещание об ответе, а не о каком-либо отдельном событии или поле. В непотоковом ответе он находится в корневом объекте usage; в потоковом ответе он появляется в message_start — событии, которое несёт входные корзины. Когда он присутствует с этим значением, гарантии, описанные на этой странице, действуют: три входные корзины взаимоисключающие, а total_tokens — там, где он присутствует, — равен их сумме плюс output_tokens. Его отсутствие — тоже обещание. Sunra нормализует только те структуры ответов, которые она измерила. Всё остальное передаётся от вышестоящего провайдера без изменений и остаётся без маркера, а ответ без маркера — это ответ, за корзины которого Sunra не ручается. Проверяйте маркер, а не изучайте числа, чтобы угадать, какому соглашению следует ответ. Именно определение соглашения по структуре это поле и призвано заменить: эвристика вроде «корзины должны быть взаимоисключающими, потому что их сумма больше количества токенов промпта» удовлетворяется более чем одним соглашением и рано или поздно прочитает ответ неверно.
Маркер несут только ответы /v1/messages. Chat Completions и Responses следуют спецификации OpenAI и не маркируются. Значение версионировано. Ломающее изменение смысла этих полей выйдет под новым значением, поэтому проверка на равенство с anthropic.exclusive.v1 не начнёт незаметно читать другой контракт.

Streaming

В потоковом запросе Messages данные usage приходят в двух событиях. message_start несёт входную сторону и маркер. Завершающее message_delta несёт только output_tokens. Проверяйте маркер в message_start, а затем выполните обычное слияние двух событий — наложите usage более позднего события поверх более раннего — чтобы получить значения, описанные выше. total_tokens не включается в потоковые ответы. Ни одно отдельное событие не знает одновременно входную и выходную сторону, поэтому любой итог, вычисленный в середине потока, будет неверным. Просуммируйте корзины самостоятельно после завершения потока.

Переход с прежнего поведения

Раньше Sunra передавала на /v1/messages объект usage от вышестоящего провайдера дословно. Слой преобразования перед некоторыми провайдерами включает токены создания кэша внутрь input_tokens, поэтому вызывающая сторона, которая следовала контракту Anthropic и суммировала три корзины, учитывала токены создания кэша дважды.
  • Если вы суммируете три корзины, как описано в контракте Anthropic, теперь вы считаете правильно. Изменений с вашей стороны не требуется.
  • Если вы компенсировали старое поведение — самостоятельно вычитая cache_creation_input_tokens из input_tokens или иным образом восстанавливая логику этого включения — прекратите. Теперь эта поправка вычитает токены, которые уже исключены, и занизит ваш ввод.
  • Если вы читаете total_tokens, он по-прежнему сообщает полное количество: свежий ввод, обе корзины кэша и вывод.
Привязывайте это изменение к маркеру, а не к дате развёртывания, чтобы один и тот же путь кода был корректен и для маркированных, и для немаркированных ответов.