Отслеживание затрат и использования
Узнайте, как отслеживать использование токенов, оценивать затраты и настраивать кэширование подсказок с помощью Claude Agent SDK.
Claude Agent SDK предоставляет подробную информацию об использовании токенов для каждого взаимодействия с Claude. Это руководство объясняет, как правильно отслеживать использование и понимать отчеты о затратах, особенно при работе с параллельным использованием инструментов и многошаговыми диалогами.
Полную документацию API см. в справочнике TypeScript SDK и справочнике Python SDK.
Поля total_cost_usd и costUSD являются оценками на стороне клиента, а не авторитетными данными для выставления счетов. SDK вычисляет их локально из таблицы цен, встроенной во время сборки, если только не действует таблица modelPricing. Они могут отличаться от того, что вам фактически выставляется счет, когда:
- изменяются цены
- установленная версия SDK не распознает модель
- применяются правила выставления счетов, которые клиент не может смоделировать
Одно правило выставления счетов, которое моделирует SDK, — это ценообразование на основе местоположения данных. Когда usage ответа сообщает inference_geo: "us", SDK умножает цену списка токенов этого ответа на 1,1. Плата за запрос, такая как веб-поиск, не умножается. Требуется TypeScript Agent SDK версии 0.3.239 или более поздней, либо Python Agent SDK версии 0.2.144 или более поздней.
Используйте эти поля для получения информации о разработке и приблизительного бюджетирования. Для авторитетного выставления счетов используйте API использования и затрат или страницу использования в Claude Console. Не выставляйте счета конечным пользователям и не принимайте финансовые решения на основе этих полей.
Понимание использования токенов
TypeScript и Python SDK предоставляют одни и те же данные об использовании с разными названиями полей:
- TypeScript предоставляет разбивку токенов по шагам для каждого сообщения ассистента (
message.message.id,message.message.usage), стоимость для каждой модели черезmodelUsageв результирующем сообщении и совокупный итог в результирующем сообщении. - Python предоставляет разбивку токенов по шагам для каждого сообщения ассистента как
message.usageиmessage.message_id, стоимость для каждой модели черезmodel_usageв результирующем сообщении и совокупный итог в результирующем сообщении какtotal_cost_usd.
Оба SDK используют одну и ту же базовую модель расчета стоимости и предоставляют одинаковую детализацию. Разница заключается в названии полей и в том, где вложено использование по шагам.
Отслеживание стоимости зависит от понимания того, как SDK определяет область действия данных об использовании:
- Вызов
query(): одно вызывание функцииquery()SDK. Один вызов может включать несколько шагов: Claude отвечает, использует инструменты, получает результаты и отвечает снова. Каждый вызов создает одно сообщениеresultв конце, за исключением режима потоковой передачи входных данных, где один вызовquery()содержит несколько ходов пользователя и каждый ход выдает свое собственное сообщениеresult. - Шаг: один цикл запроса/ответа в рамках вызова
query(). Каждый шаг создает сообщения ассистента с использованием токенов. - Сеанс: серия вызовов
query(), связанных идентификатором сеанса (с использованием опцииresume). Каждый вызовquery()в рамках сеанса сообщает о своей стоимости независимо.
На следующей диаграмме показан поток сообщений от одного вызова query() с использованием токенов, указанным на каждом шаге и совокупной оценкой в конце:
Каждый шаг создает сообщения ассистента
Когда Claude отвечает, он отправляет одно или несколько сообщений ассистента. В TypeScript каждое сообщение ассистента содержит вложенный BetaMessage (доступный через message.message) с id и объектом usage с подсчетом токенов (input_tokens, output_tokens). В Python класс данных AssistantMessage предоставляет одни и те же данные непосредственно через message.usage и message.message_id. Когда Claude использует несколько инструментов в одном ходе, все сообщения в этом ходе имеют одинаковый ID, поэтому дедублируйте по ID, чтобы избежать двойного подсчета.
Результирующее сообщение предоставляет совокупную оценку
Когда вызов query() завершается, SDK выдает результирующее сообщение с total_cost_usd и совокупным usage, типизированное как SDKResultMessage в TypeScript и ResultMessage в Python. Если вы делаете несколько вызовов query(), например в многоходовом сеансе, каждый результат отражает только стоимость этого отдельного вызова. Если вам нужна только предполагаемая сумма, вы можете игнорировать использование по шагам и прочитать это единственное значение.
В режиме потоковой передачи входных данных каждый ход выдает свое собственное результирующее сообщение. См. Отслеживание стоимости в режиме потоковой передачи входных данных для получения информации о том, как читать итоги вызовов в этом режиме.
Отслеживание затрат в режиме потоковой передачи входных данных
В режиме потоковой передачи входных данных один вызов query() содержит несколько ходов пользователя, и каждый ход выдает собственное сообщение результата. Поля результата различаются по области действия:
usage: охватывает только этот ход и в его пределах только основной цикл агента, а не какие-либо подагенты, которые он запустил.total_cost_usdиmodelUsage, илиmodel_usageв Python: содержат текущий итог для всего вызова на данный момент.
В вызове, где ваше приложение никогда не отправляет /clear, /reset или /new, прочитайте последний результат для итогов вызова, а не суммируйте результаты.
Текущие итоги начинаются заново каждый раз, когда ваше приложение отправляет одну из этих трех команд, и внутри вызова query() ничто другое их не сбрасывает. Три результата имеют значение для вашего учета:
- Собственный результат хода
/clear: охватывает только то, что было запущено с момента сброса, и содержит новыйsession_id. - Каждый последующий результат: продолжает отсчет с этого сброса.
- Последний результат перед каждым
/clear: содержит итог для ходов с момента предыдущего сброса.
Чтобы получить итог всего вызова, добавьте последний результат перед каждым /clear к финальному результату вызова. Все остальные результаты, включая собственный результат хода /clear, заменяются более поздним.
В TypeScript SDK также выдает SDKConversationResetMessage при каждом сбросе, поэтому вы можете обнаружить сбросы из потока. В Python SDK аналогично выдает ConversationResetMessage. До версии Python SDK v0.2.137 итератор Python отбрасывал это сообщение, поэтому в этих версиях считайте сбросы самостоятельно из ходов /clear, которые отправляет ваше приложение.
maxBudgetUsd (TypeScript) или max_budget_usd (Python) сравнивается с тем же текущим итогом, поэтому /clear также начинает бюджет заново.
Получить общую стоимость запроса
Результирующее сообщение, типизированное как SDKResultMessage в TypeScript и ResultMessage в Python, отмечает конец цикла агента для вызова query(). Оно включает total_cost_usd, совокупную предполагаемую стоимость всех шагов в этом вызове. В Python это поле типизировано как опциональное, поэтому проверьте, что оно не равно None перед его чтением. Результаты успеха и ошибки оба содержат его, хотя финальный результат сбоя сеанса может содержать его обнуленным.
Если вы используете сеансы для выполнения нескольких вызовов query(), каждый результат отражает только стоимость этого отдельного вызова. В режиме потоковой передачи входных данных читайте итоги вызовов, как описано в Отслеживание затрат в режиме потоковой передачи входных данных.
Три поля на уровне результата отличаются тем, что они считают, когда агент порождает подагентов. Используйте modelUsage или model_usage в Python для учета токенов всего дерева; поле usage недосчитывает, как только происходит вложение.
| Поле | Активность подагента |
|---|---|
usage |
Исключено. Считает только цикл агента верхнего уровня, поэтому токены, потребленные внутри подагентов, не добавляются |
total_cost_usd |
Включено. Считает запросы подагентов наряду с циклом верхнего уровня |
modelUsage / model_usage |
Включено. Считает запросы подагентов наряду с циклом верхнего уровня, разбитые по моделям |
В режиме ввода одного сообщения, когда фоновые подагенты все еще работают в конце финального хода, Claude Code ждет их, вплоть до лимита, описанного в фоновых задачах при выходе, перед отправкой результата. total_cost_usd, duration_api_ms и modelUsage результата, или model_usage в Python, включают работу, выполненную во время этого ожидания.
Следующие примеры перебирают поток сообщений из вызова query() и выводят общую стоимость, когда приходит сообщение result:
import { query } from "@anthropic-ai/claude-agent-sdk";
try {
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type === "result") {
console.log(`Total cost: $${message.total_cost_usd}`);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, it still carried total_cost_usd and the
// branch above has already run; connection or process failures yield
// no result message.
console.error(`Session ended with an error: ${error}`);
}
from claude_agent_sdk import query, ResultMessage
import asyncio
async def main():
try:
async for message in query(prompt="Summarize this project"):
if isinstance(message, ResultMessage):
print(f"Total cost: ${message.total_cost_usd or 0}")
except Exception as error:
# A single-shot query() raises after yielding an error result. If the
# failure was an error result, the branch above has already run;
# connection or process failures yield no result message.
print(f"Session ended with an error: {error}")
asyncio.run(main())
Чтобы ограничить, сколько подагенты могут добавить к total_cost_usd, установите лимиты глубины, параллелизма и расходов на запросе.
Отслеживание использования на каждом шаге и для каждой модели
Примеры в этом разделе используют имена полей TypeScript. В Python эквивалентные поля — это AssistantMessage.usage и AssistantMessage.message_id для использования на каждом шаге, а также ResultMessage.model_usage для разбивки по моделям.
Отслеживание использования на каждом шаге
Каждое сообщение ассистента содержит вложенный BetaMessage (доступный через message.message) с id и объектом usage с подсчётом токенов. Когда Claude использует инструменты параллельно, несколько сообщений имеют одинаковый id с идентичными данными использования. Отслеживайте, какие ID вы уже подсчитали, и пропускайте дубликаты, чтобы избежать завышенных итогов.
Дедублицированные значения на каждом шаге точны для входных и кэшированных токенов. Per-step output_tokens — это заполнитель, поэтому читайте выходные токены из сообщения результата.
Следующий пример накапливает входные токены на всех шагах, подсчитывая каждый уникальный ID сообщения основного цикла только один раз и пропуская сообщения подагентов, а также читает выходной итог из сообщения результата, который охватывает основной цикл:
import { query } from "@anthropic-ai/claude-agent-sdk";
const seenIds = new Set<string>();
let totalInputTokens = 0;
let resultOutputTokens = 0;
try {
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type === "assistant" && !message.parent_tool_use_id) {
const msgId = message.message.id;
// Parallel tool calls share the same ID, only count once
if (!seenIds.has(msgId)) {
seenIds.add(msgId);
totalInputTokens += message.message.usage.input_tokens;
}
}
if (message.type === "result") {
// Per-step output_tokens is a placeholder; the result message
// carries the accumulated output total.
resultOutputTokens = message.usage.output_tokens;
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result, so the
// input total below still reflects the steps that ran before the failure.
console.error(`Session ended with an error: ${error}`);
}
console.log(`Steps: ${seenIds.size}`);
console.log(`Input tokens: ${totalInputTokens}`);
console.log(`Output tokens: ${resultOutputTokens}`);
Разбивка использования по моделям
Сообщение результата включает modelUsage, карту имён моделей на подсчёты токенов для каждой модели и стоимость. Это полезно, когда вы запускаете несколько моделей (например, Haiku для подагентов и Opus для основного агента) и хотите увидеть, куда идут токены.
Поле costBasis каждой записи указывает, какая таблица цен определила цену последнего запроса этой модели: list для цены списка, managed для таблицы modelPricing, или unknown, когда ни одна из них не совпала с ID модели. Это поле требует Claude Code версии 2.1.246 или позже.
Следующий пример запускает запрос и выводит разбивку стоимости и токенов для каждой используемой модели:
import { query } from "@anthropic-ai/claude-agent-sdk";
try {
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type !== "result") continue;
for (const [modelName, usage] of Object.entries(message.modelUsage)) {
console.log(`${modelName}: $${usage.costUSD.toFixed(4)}`);
console.log(` Input tokens: ${usage.inputTokens}`);
console.log(` Output tokens: ${usage.outputTokens}`);
console.log(` Cache read: ${usage.cacheReadInputTokens}`);
console.log(` Cache creation: ${usage.cacheCreationInputTokens}`);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, the per-model breakdown above has already
// printed; connection or process failures yield no result message.
console.error(`Session ended with an error: ${error}`);
}
Накопление затрат при нескольких вызовах
Каждый вызов query() возвращает свой собственный total_cost_usd. SDK не предоставляет общую сумму на уровне сеанса, поэтому если ваше приложение выполняет несколько вызовов query(), например в многоходовом сеансе или для разных пользователей, накапливайте итоги самостоятельно. В режиме потоковой передачи входных данных прочитайте общую сумму каждого вызова, как описано в разделе Отслеживание затрат в режиме потоковой передачи входных данных. Для вызова, который завершился сбоем, см. раздел Восстановление итогов после сбоя сеанса.
В следующих примерах выполняются два вызова query() последовательно, каждый total_cost_usd вызова добавляется к текущему итогу, и выводятся как стоимость для каждого вызова, так и общая стоимость:
import { query } from "@anthropic-ai/claude-agent-sdk";
// Track cumulative cost across multiple query() calls
let totalSpend = 0;
const prompts = [
"Read the files in src/ and summarize the architecture",
"List all exported functions in src/auth.ts"
];
for (const prompt of prompts) {
try {
for await (const message of query({ prompt })) {
if (message.type === "result") {
totalSpend += message.total_cost_usd;
console.log(`This call: $${message.total_cost_usd}`);
}
}
} catch (error) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, this call's cost was already counted;
// connection or process failures yield no result message. Continue
// with the next prompt.
console.error(`Call failed: ${error}`);
}
}
console.log(`Total spend: $${totalSpend.toFixed(4)}`);
from claude_agent_sdk import query, ResultMessage
import asyncio
async def main():
# Track cumulative cost across multiple query() calls
total_spend = 0.0
prompts = [
"Read the files in src/ and summarize the architecture",
"List all exported functions in src/auth.ts",
]
for prompt in prompts:
try:
async for message in query(prompt=prompt):
if isinstance(message, ResultMessage):
cost = message.total_cost_usd or 0
total_spend += cost
print(f"This call: ${cost}")
except Exception as error:
# A single-shot query() raises after yielding an error result. If
# the failure was an error result, this call's cost was already
# counted; connection or process failures yield no result message.
# Continue with the next prompt.
print(f"Call failed: {error}")
print(f"Total spend: ${total_spend:.4f}")
asyncio.run(main())
Обработка ошибок, кеширование и подсчет выходных токенов
Для точного отслеживания затрат учитывайте количество выходных токенов-заполнителей в сообщениях ассистента, токены, потребленные неудачным разговором, и цены на токены кеша.
Чтение выходных токенов из результирующего сообщения
Claude Code создает каждое сообщение ассистента на основе использования, которое API сообщил при начале ответа, поэтому output_tokens сообщения — это только количество, которое API сообщил в message_start, до того как был сгенерирован ответ. Один ответ API может создать несколько сообщений ассистента, и каждое из них содержит этот же заполнитель.
API сообщает реальное количество выходных данных в конце ответа, и Claude Code добавляет его в результирующее сообщение. Читайте выходные токены из usage результата или из modelUsage для разбивки по моделям.
Чтобы наблюдать, как растет количество выходных данных ответа во время потоковой передачи, установите includePartialMessages или include_partial_messages в Python и читайте usage из каждого события потока message_delta, типизированного как SDKPartialAssistantMessage в TypeScript и StreamEvent в Python.
Отслеживание затрат при неудачных разговорах
Оба результирующих сообщения об успехе и ошибке включают usage и total_cost_usd; в Python оба поля типизированы как необязательные, поэтому проверьте, что они не равны None перед их чтением.
Если разговор прерывается на полпути, вы все равно потребили токены до момента сбоя. Читайте данные о затратах из каждого результирующего сообщения, независимо от того, является ли его subtype success или одним из подтипов ошибок. На некоторых результатах ошибок usage сообщает меньше, чем потратил вызов:
error_during_executionпосле сбоя сеанса: каждое поле затрат может быть обнулено.error_max_budget_usd:usageисключает ответ, который превысил бюджет, в то время какtotal_cost_usdиmodelUsageвключают его.
Где у вас есть выбор, учитывайте данные из total_cost_usd или modelUsage вместо usage.
Восстановление итогов после сбоя сеанса
Когда процесс Claude Code падает, он выдает финальный результат error_during_execution и выходит как в режиме одноразового ввода, так и в режиме потокового ввода. Этот результат может содержать обнуленные usage, total_cost_usd и modelUsage, поэтому восстановите итоги вызова из того, что пришло до него. Шаг 1 восстанавливает полные итоги всякий раз, когда существует более ранний результат; резервный вариант на шаге 2 восстанавливает только входные токены и токены кеша основного цикла.
- Используйте результат хода перед сбоем. В режиме потокового ввода он содержит текущий итог с начала вызова или с момента последнего
/clear. Перейдите к шагу 2, если этот результат не может вам помочь:- Вызов был одноразовым, поэтому более ранний результат не существует.
- Сбой произошел на первом ходу.
- Ход перед сбоем был самим
/clear, поэтому его результат охватывает только сброс.
- Вместо этого суммируйте
usageв сообщениях ассистента, считая каждый ответ API один раз, как это делает пример Track per-step usage. В режиме одноразового ввода суммируйте все из них; в режиме потокового ввода суммируйте те, которые пришли после последнего результата. Это дает вам входные токены и токены кеша основного цикла. Использование подагента не восстанавливается таким образом, и выходные токены или стоимость в USD тоже, потому что выходные токены на шаг — это заполнитель.
Отслеживание токенов кеша
Agent SDK автоматически использует prompt caching для снижения затрат на повторяющееся содержимое. Вам не нужно самостоятельно настраивать кеширование. Объект использования включает два дополнительных поля для отслеживания кеша:
cache_creation_input_tokens: токены, используемые для создания новых записей кеша (взимаются по более высокой ставке, чем стандартные входные токены).cache_read_input_tokens: токены, прочитанные из существующих записей кеша (взимаются по сниженной ставке).
Отслеживайте их отдельно от input_tokens, чтобы понять экономию кеша. В TypeScript эти поля типизированы на объекте Usage. В Python они появляются как ключи в словаре ResultMessage.usage (например, message.usage.get("cache_read_input_tokens", 0)).
Расширение TTL кеша подсказок до одного часа
Ваши собственные ходы попадают в основной сегмент TTL разговора, вместе с помощниками, которые Claude Code запускает встроенными с ними. Запросы, которые Claude Code делает вне этого разговора, такие как подагенты, имеют отдельное управление TTL.
Записи кеша для ваших собственных ходов используют TTL по умолчанию 5 минут, когда вы аутентифицируетесь с помощью ключа API или запускаете на Amazon Bedrock, платформе агентов Google Cloud, Microsoft Foundry или Claude Platform on AWS. Если ваша рабочая нагрузка запускает много коротких сеансов с одной и той же системной подсказкой и контекстом с промежутками более 5 минут между ними, кеш истекает между сеансами и каждый новый сеанс платит полную входную цену.
Чтобы запросить TTL в 1 час при записи кеша, установите переменную окружения ENABLE_PROMPT_CACHING_1H. Вы можете экспортировать ее в окружение вашей оболочки или контейнера или передать ее через options.env.
Следующий пример включает TTL в 1 час для агента, работающего на Amazon Bedrock. Поскольку он устанавливает CLAUDE_CODE_USE_BEDROCK, он требует рабочих учетных данных AWS для Amazon Bedrock; без них запрос не выполняется.
from claude_agent_sdk import ClaudeAgentOptions, query
import asyncio
async def main():
options = ClaudeAgentOptions(
env={
"CLAUDE_CODE_USE_BEDROCK": "1",
"ENABLE_PROMPT_CACHING_1H": "1",
},
)
async for message in query(prompt="Summarize this project", options=options):
print(message)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
const options = {
env: {
...process.env,
CLAUDE_CODE_USE_BEDROCK: "1",
ENABLE_PROMPT_CACHING_1H: "1",
},
};
for await (const message of query({ prompt: "Summarize this project", options })) {
console.log(message);
}
Записи кеша с TTL в 1 час взимаются по более высокой ставке, чем записи на 5 минут, поэтому включение этого обменивает более высокую стоимость записи на больше чтений из кеша. Подробности см. в ценах на prompt caching. На подписке Claude в рамках включенного использования вашего плана вы получаете TTL в 1 час на своих собственных ходах и на некоторых вспомогательных запросах, которые Claude Code делает рядом с ними, без установки этой переменной, и Claude Code снижает эти ходы до TTL в 5 минут, как только вы начинаете использовать кредиты использования.
ENABLE_PROMPT_CACHING_1H запрашивает TTL в 1 час для каждого запроса в обоих сегментах. Чтобы выбрать TTL для каждого сегмента отдельно, используйте эти элементы управления вместо этого. Каждый принимает 5m или 1h и имеет приоритет над ENABLE_PROMPT_CACHING_1H:
- Основной разговор: переменная окружения
CLAUDE_CODE_PROMPT_CACHE_TTLили параметрpromptCacheTtl - Все остальное: переменная окружения
CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTLили параметрsubagentPromptCacheTtl
Установка promptCacheTtl на 1h сохраняет кеш в 1 час на основном разговоре, пока вы используете кредиты использования. Для полного порядка приоритета см. выбор TTL самостоятельно.
Связанная документация
- Справочник TypeScript SDK - Полная документация API
- Обзор SDK - Начало работы с SDK
- Разрешения SDK - Управление разрешениями инструментов