رفتن به محتوا

ردگیریِ هزینه و مصرف

Claude Agent SDK برای هر تعاملِ تو با Claude اطلاعاتِ دقیقی درباره‌ی مصرفِ توکن فراهم می‌کند. این راهنما توضیح می‌دهد چطور مصرف را درست ردگیری کنی و گزارشِ هزینه را بفهمی — به‌ویژه وقتی با استفاده‌ی موازی از ابزارها و گفتگوهای چندمرحله‌ای سروکار داری.

برای مستنداتِ کاملِ API، به مرجعِ TypeScript SDK و مرجعِ Python SDK نگاه کن.

هر دو SDKِ TypeScript و Python همان داده‌ی مصرف را با نام‌فیلدهای متفاوت در دسترس می‌گذارند:

  • TypeScript تفکیکِ توکنِ هر مرحله را روی هر پیامِ assistant فراهم می‌کند (message.message.id, message.message.usage)، هزینه‌ی به‌ازای هر مدل را از طریقِ modelUsage روی پیامِ نتیجه، و جمعِ تجمعی را روی پیامِ نتیجه.
  • Python تفکیکِ توکنِ هر مرحله را روی هر پیامِ assistant فراهم می‌کند (message.usage, message.message_id)، هزینه‌ی به‌ازای هر مدل را از طریقِ model_usage روی پیامِ نتیجه، و جمعِ انباشته را روی پیامِ نتیجه (total_cost_usd و دیکشنریِ usage).

هر دو SDK از همان مدلِ هزینه‌ی زیرین استفاده می‌کنند و همان دانه‌بندی را در دسترس می‌گذارند. تفاوت در نام‌گذاریِ فیلدها و جایی است که مصرفِ هر مرحله در آن تودرتو شده.

ردگیریِ هزینه به فهمِ این بستگی دارد که SDK چطور داده‌ی مصرف را scope می‌کند:

  • فراخوانِ query(): یک‌بار صدا زدنِ تابعِ query() در SDK. یک فراخوان می‌تواند چند مرحله را دربر بگیرد (Claude پاسخ می‌دهد، ابزار به کار می‌برد، نتیجه می‌گیرد، دوباره پاسخ می‌دهد). هر فراخوان در پایان یک پیامِ result تولید می‌کند.
  • Step (مرحله): یک چرخه‌ی درخواست/پاسخ درونِ یک فراخوانِ query(). هر مرحله پیام‌های assistant همراه با مصرفِ توکن تولید می‌کند.
  • Session (نشست): مجموعه‌ای از فراخوان‌های query() که با یک session ID به هم پیوند خورده‌اند (با استفاده از گزینه‌ی resume). هر فراخوانِ query() درونِ یک نشست هزینه‌ی خودش را مستقل گزارش می‌دهد.

نمودارِ زیر جریانِ پیام را از یک فراخوانِ query() نشان می‌دهد، با مصرفِ توکن که در هر مرحله گزارش شده و تخمینِ تجمعی در پایان:

Diagram showing a query producing two steps of messages. Step 1 has four assistant messages sharing the same ID and usage (count once), Step 2 has one assistant message with a new ID, and the final result message shows the estimated total_cost_usd.

هر مرحله پیام‌های assistant تولید می‌کند

وقتی Claude پاسخ می‌دهد، یک یا چند پیامِ assistant می‌فرستد. در TypeScript، هر پیامِ assistant یک 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ِ تجمعی منتشر می‌کند. این هم در TypeScript (SDKResultMessage) و هم در Python (ResultMessage) در دسترس است. اگر چند فراخوانِ query() انجام دهی (مثلاً در یک نشستِ چندنوبتی)، هر نتیجه فقط هزینه‌ی همان فراخوانِ منفرد را بازتاب می‌دهد. اگر فقط به تخمینِ کل نیاز داری، می‌توانی مصرفِ هر مرحله را نادیده بگیری و همین یک مقدار را بخوانی.

هزینه‌ی کلِ یک query را بگیر

Section titled “هزینه‌ی کلِ یک query را بگیر”

پیامِ نتیجه (TypeScript، Python) پایانِ حلقه‌ی ایجنت را برای یک فراخوانِ query() نشان می‌دهد. این پیام شاملِ total_cost_usd است، یعنی هزینه‌ی تخمینیِ تجمعی در همه‌ی مراحلِ آن فراخوان. این برای نتیجه‌های موفق و خطا هر دو کار می‌کند. اگر برای انجامِ چند فراخوانِ query() از نشست‌ها استفاده کنی، هر نتیجه فقط هزینه‌ی همان فراخوانِ منفرد را بازتاب می‌دهد.

مثال‌های زیر روی جریانِ پیامِ یک فراخوانِ query() پیمایش می‌کنند و وقتی پیامِ result می‌رسد هزینه‌ی کل را چاپ می‌کنند:

import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type === "result") {
console.log(`Total cost: $${message.total_cost_usd}`);
}
}
from claude_agent_sdk import query, ResultMessage
import asyncio
async def main():
async for message in query(prompt="Summarize this project"):
if isinstance(message, ResultMessage):
print(f"Total cost: ${message.total_cost_usd or 0}")
asyncio.run(main())

مصرفِ هر مرحله و هر مدل را ردگیری کن

Section titled “مصرفِ هر مرحله و هر مدل را ردگیری کن”

مثال‌های این بخش از نام‌فیلدهای TypeScript استفاده می‌کنند. در Python، فیلدهای معادل عبارت‌اند از AssistantMessage.usage و AssistantMessage.message_id برای مصرفِ هر مرحله، و ResultMessage.model_usage برای تفکیکِ هر مدل.

مصرفِ هر مرحله را ردگیری کن

Section titled “مصرفِ هر مرحله را ردگیری کن”

هر پیامِ assistant یک BetaMessageِ تودرتو دارد (از طریقِ message.message دسترس‌پذیر) با یک id و شیءِ usage همراه با شمارشِ توکن‌ها. وقتی Claude ابزارها را به‌صورت موازی به کار می‌برد، چند پیام همان id را با داده‌ی مصرفِ یکسان به اشتراک می‌گذارند. ردگیری کن کدام IDها را قبلاً شمرده‌ای و دوتایی‌ها را رد کن تا جمع‌ها متورم نشوند.

مثالِ زیر توکن‌های ورودی و خروجی را در همه‌ی مراحل انباشته می‌کند و هر ID پیامِ یکتا را فقط یک‌بار می‌شمارد:

import { query } from "@anthropic-ai/claude-agent-sdk";
const seenIds = new Set<string>();
let totalInputTokens = 0;
let totalOutputTokens = 0;
for await (const message of query({ prompt: "Summarize this project" })) {
if (message.type === "assistant") {
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;
totalOutputTokens += message.message.usage.output_tokens;
}
}
}
console.log(`Steps: ${seenIds.size}`);
console.log(`Input tokens: ${totalInputTokens}`);
console.log(`Output tokens: ${totalOutputTokens}`);

مصرف را بر حسبِ مدل تفکیک کن

Section titled “مصرف را بر حسبِ مدل تفکیک کن”

پیامِ نتیجه شاملِ modelUsage است، یعنی نگاشتی از نامِ مدل به شمارشِ توکن و هزینه‌ی هر مدل. این وقتی مفید است که چند مدل را اجرا می‌کنی (مثلاً Haiku برای ساب‌ایجنت‌ها و Opus برای ایجنتِ اصلی) و می‌خواهی ببینی توکن‌ها کجا می‌روند.

مثالِ زیر یک query اجرا می‌کند و هزینه و تفکیکِ توکن را برای هر مدلِ استفاده‌شده چاپ می‌کند:

import { query } from "@anthropic-ai/claude-agent-sdk";
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}`);
}
}

هزینه‌ها را در چند فراخوان انباشته کن

Section titled “هزینه‌ها را در چند فراخوان انباشته کن”

هر فراخوانِ 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) {
for await (const message of query({ prompt })) {
if (message.type === "result") {
totalSpend += message.total_cost_usd;
console.log(`This call: $${message.total_cost_usd}`);
}
}
}
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:
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}")
print(f"Total spend: ${total_spend:.4f}")
asyncio.run(main())

خطاها، کش‌کردن، و ناهماهنگیِ توکن را مدیریت کن

Section titled “خطاها، کش‌کردن، و ناهماهنگیِ توکن را مدیریت کن”

برای ردگیریِ دقیقِ هزینه، گفتگوهای ناموفق، قیمت‌گذاریِ توکنِ کش، و ناسازگاری‌های گاه‌به‌گاهِ گزارش را در نظر بگیر.

ناهماهنگیِ توکنِ خروجی را حل کن

Section titled “ناهماهنگیِ توکنِ خروجی را حل کن”

در مواردِ نادر، ممکن است برای پیام‌هایی با همان ID مقادیرِ متفاوتِ output_tokens ببینی. وقتی این اتفاق می‌افتد:

  1. بالاترین مقدار را استفاده کن: آخرین پیام در یک گروه معمولاً جمعِ دقیق را دارد.
  2. پیامِ نتیجه را ترجیح بده: total_cost_usd در پیامِ نتیجه، تخمینِ انباشته‌ی SDK را در همه‌ی مراحل بازتاب می‌دهد، پس از جمع‌زدنِ دستیِ مقادیرِ هر مرحله توسطِ خودت قابل‌اعتمادتر است. این هنوز یک تخمین است و ممکن است با صورت‌حسابِ واقعی‌ات فرق کند.
  3. ناسازگاری‌ها را گزارش کن: ایشوها را در مخزنِ GitHub Claude Code ثبت کن.

هزینه‌ها را روی گفتگوهای ناموفق ردگیری کن

Section titled “هزینه‌ها را روی گفتگوهای ناموفق ردگیری کن”

پیام‌های نتیجه‌ی موفق و خطا هر دو شاملِ usage و total_cost_usd هستند. اگر گفتگویی در میانه‌ی راه ناموفق شود، تو همچنان تا نقطه‌ی شکست توکن مصرف کرده‌ای. همیشه داده‌ی هزینه را از پیامِ نتیجه بخوان، فارغ از subtypeِ آن.

توکن‌های کش را ردگیری کن

Section titled “توکن‌های کش را ردگیری کن”

Agent SDK به‌طور خودکار از prompt caching استفاده می‌کند تا هزینه‌ی محتوای تکراری را کاهش دهد. لازم نیست خودت کش‌کردن را پیکربندی کنی. شیءِ usage دو فیلدِ اضافی برای ردگیریِ کش دارد:

  • cache_creation_input_tokens: توکن‌های مصرف‌شده برای ساختنِ ورودی‌های جدیدِ کش (با نرخی بالاتر از توکن‌های ورودیِ استاندارد محاسبه می‌شوند).
  • cache_read_input_tokens: توکن‌های خوانده‌شده از ورودی‌های موجودِ کش (با نرخی کاهش‌یافته محاسبه می‌شوند).

این‌ها را جدا از input_tokens ردگیری کن تا صرفه‌جوییِ کش‌کردن را بفهمی. در TypeScript، این فیلدها روی شیءِ Usage تایپ شده‌اند. در Python، به‌صورتِ کلید در دیکشنریِ ResultMessage.usage ظاهر می‌شوند (مثلاً message.usage.get("cache_read_input_tokens", 0)).

TTLِ کشِ پرامپت را به یک ساعت گسترش بده

Section titled “TTLِ کشِ پرامپت را به یک ساعت گسترش بده”

ورودی‌های کشی که SDK می‌نویسد، وقتی با API key احراز هویت می‌کنی یا روی Amazon Bedrock، Google Cloud Vertex AI، یا Microsoft Foundry اجرا می‌شوی، به‌طور پیش‌فرض یک TTLِ ۵ دقیقه‌ای دارند. اگر بارِ کاریِ تو نشست‌های کوتاهِ زیادی را علیهِ همان system prompt و کانتکست با فاصله‌هایی بیش از ۵ دقیقه میانِ آن‌ها اجرا می‌کند، کش میانِ نشست‌ها منقضی می‌شود و هر نشستِ جدید قیمتِ کاملِ ورودی را می‌پردازد.

برای درخواستِ TTLِ ۱ساعته روی نوشتنِ کش، متغیرِ محیطیِ ENABLE_PROMPT_CACHING_1H را تنظیم کن. می‌توانی آن را در shell یا محیطِ کانتینرت export کنی، یا از طریقِ options.env پاس بدهی.

مثالِ زیر TTLِ ۱ساعته را برای یک ایجنت که روی 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ِ ۱ساعته با نرخی بالاتر از نوشتن‌های ۵دقیقه‌ای محاسبه می‌شود، پس فعال‌کردنِ این، هزینه‌ی بالاترِ نوشتن را با خواندن‌های بیشترِ کش مبادله می‌کند. برای جزئیات به قیمت‌گذاریِ prompt caching نگاه کن. کاربرانِ اشتراکِ Claude همین حالا هم به‌طور خودکار TTLِ ۱ساعته دریافت می‌کنند و لازم نیست این متغیر را تنظیم کنند.