پرش به محتوا
16/30فصل 16 از 30

Context Window، tokenها و صورت‌حساب؛ با عدد و اندازه‌گیری

یک گفت‌وگوی 40 نوبتی 22 برابر طول خودش input token هزینه دارد؛ cache آن را 68٪ کم می‌کند و timestamp بد 20٪ اضافه می‌کند.

در این صفحه

اینجا یک گفت‌وگوی پشتیبانی چهل‌نوبتی را می‌بینید که نوبت‌به‌نوبت صورت‌حساب شده است. هیچ چیز غیرعادی در آن نیست: یک توسعه‌دهنده دربارهٔ یک API می‌پرسد و یک assistant در یک یا دو پاراگراف پاسخ می‌دهد. کل تبادل 5,090 token متن است — حدود هشت صفحه.

turnprompt tokensnew textoutputcost of this turnrunning total
121318183$0.002622$0.002622
589214123$0.003260$0.014354
101,65619114$0.004680$0.035530
202,86818103$0.006972$0.094426
303,9412099$0.009070$0.174170
404,94717142$0.011598$0.274386

ستون‌های دوم و سوم را با هم بخوانید. در نوبت 40، کاربر هفده token تایپ کرد و برای 4,947 token هزینه پرداخت. پرسش از پرسش اول سخت‌تر نبود؛ کوتاه‌تر هم بود. چیزی که تغییر کرد این بود که درخواست، کل گفت‌وگو را برای بار چهلم دوباره با خودش حمل می‌کرد.

مجموع input tokenهایی که در این چهل call صورت‌حساب شدند: 112,617. طول خود گفت‌وگو 5,090 token است. شما هزینهٔ آن را بیست‌ودو بار پرداخت کرده‌اید.

این فصل دربارهٔ این است که چرا چنین اتفاقی می‌افتد، در صورت‌حساب هر provider چه نامی دارد، و از میان پنج چیزی که بابتشان پول می‌دهید روی کدام‌ها می‌توانید اثر بگذارید.

نمایش جزئیات

این فصل از بخش II به چه چیزهایی نیاز دارد.

  • فصل 7 tokenizer را ساخت. اینجا هم token همان واحد است — همان واحد، حالا با قیمت.
  • فصل 9 self-attention و هزینهٔ O(n2)O(n^2) آن را در کادر نمادگذاری مجانبی استخراج کرد. آن هزینه دلیل وجود داشتن یک limit است، و اینجا به‌جای توضیح دوباره به آن ارجاع داده می‌شود.
  • فصل 13 prefill را در برابر decode اندازه گرفت و محاسبه کرد یک KV cache چه فضایی اشغال می‌کند. ستون‌های input و output بالا در عمل همین دو فاز را می‌خرند.

باقی ماجرا TypeScript است، چون این حسابداریِ یک call راه‌دور است، نه ریاضیات دربارهٔ یک مدل.

گران‌ترین سوءبرداشت در این کسب‌وکار این است که مدل یک گفت‌وگو را به خاطر می‌سپارد.

این‌طور نیست، و مکانیزم فصل 13 دقیقاً می‌گوید چرا. وضعیت یک transformer هنگام generation همان KV cache است: کلیدها و مقدارهایی که برای هر token در دنباله محاسبه شده‌اند. این cache فقط برای مدت یک request زنده است. وقتی request تمام می‌شود، فرایندی که آن را نگه داشته آزاد است به شخص دیگری سرویس بدهد، و cache از بین می‌رود. آن طرف هیچ ذخیرهٔ per-user و هیچ sessionی وجود ندارد.

پس request بعدی باید همراه با هر چیزی برسد که مدل قرار است بداند، و مدل پیش از آنکه حتی یک token تازه منتشر کند، با اجرای یک forward pass روی کل prompt آن وضعیت را از نو می‌سازد. فصل 15 prompt را «کل وضعیت» نامید. دلیل فیزیکی‌اش این است: prompt وضعیت کامل است، چون هیچ چیز دیگری از call جان سالم به در نمی‌برد.

context window حداکثر طول آن prompt به‌علاوهٔ پاسخ آن است. سقفی است برای اینکه چقدر وضعیت می‌توانید از نو بسازید، نه ظرفی که چیزی را بین requestها نگه دارد. نامیدن آن به «حافظهٔ مدل» جهت علیت را برعکس می‌کند — شما حافظه‌ای را پر نمی‌کنید، دارید برای بازبرقرار کردن آن پول می‌دهید.

عدد بیست‌ودو از همین‌جا می‌آید. نوبت nn همهٔ n1n-1 نوبت قبلی را حمل می‌کند، پس کل input در یک گفت‌وگوی nn نوبتی برابر مجموع یک سریِ رو‌به‌رشد است، که درجه‌دو می‌شود:

total input  =  i=1n(s+hi)  =  Θ(n2)\text{total input} \;=\; \sum_{i=1}^{n} \big(s + h_i\big) \;=\; \Theta(n^2)

که در آن ss system prompt است و hih_i تاریخچه در نوبت ii. برازش input تجمعیِ اندازه‌گیری‌شده به an2+bnan^2 + bn در طول چهل نوبت، 60.22n2+432.25n60.22\,n^2 + 432.25\,n می‌دهد؛ این مقدار برای نوبت 40 عدد 113,645 token را پیش‌بینی می‌کند، در برابر 112,617 اندازه‌گیری‌شده. جملهٔ درجه‌دو غالب است و جملهٔ خطی همان چیزی است که کاربر واقعاً تایپ کرده.

نتیجه، جمله‌ای است که باید از این فصل با خود ببرید: صورت‌حساب شما با مربع طول گفت‌وگو رشد می‌کند، نه با پرسش آخر. همان چهل پرسش اگر بدون هیچ history پرسیده می‌شدند $0.066036 هزینه داشتند. نگه داشتن history هزینه را به $0.274386 رساند. History صورت‌حساب را 4.2 برابر کرد، و همچنان به ضرب کردن ادامه می‌دهد، چون ضریب همان طول گفت‌وگو است.

Window به دو دلیل هم‌جهت محدود است. دلیل اول همان دلیل فصل 9 است: attention هر token را با هر token دیگر مقایسه می‌کند، بنابراین کار آن لایه با مربع طول دنباله رشد می‌کند. دلیل دوم حافظه است: KV cache با طول دنباله خطی رشد می‌کند، و فصل 13 این حساب را انجام داد — در دنباله‌های بلند، از وزن‌ها هم بزرگ‌تر می‌شود.

به هر دو محدودیت حمله شده و هیچ‌کدام حذف نشده‌اند. FlashAttention1 محاسبه را طوری بازآرایی می‌کند که خواندن و نوشتن بسیار کمتری روی حافظهٔ با پهنای‌باند بالا انجام شود؛ این کار دنباله‌های بلند را بدون تغییر هزینهٔ مجانبی عملی می‌کند. Position Interpolation2 و YaRN3 با بازتنظیم positional encodingهای فصل 9، به‌جای آموزش دوباره، window قابل‌استفادهٔ یک مدل آموزش‌دیده را گسترش می‌دهند. این‌ها با هم دلیل‌اند که windowها در پنج سال از 2K به 1M رسیدند.

کاری که نکردند رایگان کردن contextهای بلند بود. سقف را بالاتر بردند و شیب را ملایم‌تر کردند. شیب هنوز وجود دارد، و همان چیزی است که tierهای قیمت در ادامهٔ این فصل اندازه می‌گیرند.

تقریباً هر ماشین‌حساب هزینه در اینترنت یک API call را به‌صورت input tokens ضرب‌در قیمت input به‌علاوهٔ output tokens ضرب‌در قیمت output مدل می‌کند. این در سال 2023 درست بود. حالا به‌شکلی غلط است که صورت‌حساب‌ها را در هر دو جهت با ضریب دو یا بیشتر از واقعیت دور می‌کند.

پنج دستهٔ token قابل‌صورت‌حساب وجود دارد:

bucketwhat it istypical price, relative to input
uncached inputprompt tokens که مدل مجبور بود تازه پردازش کند
cache readprompt tokens سرویس‌شده از یک prefix ذخیره‌شده0.1×
cache writeprompt tokens ذخیره‌شده در cache در این call1.25× تا 2×
outputtokenهایی که مدل تولید کرده و برای شما فرستاده5× تا 6×
reasoningtokenهایی که مدل تولید کرده و برای شما نفرستادهنرخ output

سه مورد از این پنج مورد دو سال پیش به‌صورت line جدا وجود نداشتند، و دو خط cache همان‌هایی‌اند که مردم اشتباه می‌گیرند، چون cache write بیشتر از input معمولی هزینه دارد، نه کمتر. شما برای ذخیره کردن چیزی premium می‌پردازید تا بعداً برای خواندن دوباره‌اش discount بگیرید، و اینکه این معامله خوب باشد کاملاً به تعداد دفعاتی بستگی دارد که آن را می‌خوانید.

سبد reasoning متعلق به فصل 12 است، حالا با قیمت روی آن، و نکته‌ای دارد که باید صریح گفته شود: مستندات Google می‌گوید pricing «بر اساس همهٔ thought tokenهایی است که مدل برای generate کردن نیاز دارد، هرچند فقط summary از API خروجی داده می‌شود.»4 شما برای tokenهایی صورت‌حساب می‌شوید که هرگز به شما منتقل نمی‌شوند. این تنها سبدی است که محتویاتش را نمی‌توانید بشمارید، inspect کنید یا verify کنید.

حالا بخشی که این را به مسئلهٔ normalisation تبدیل می‌کند، نه مسئلهٔ multiplication. هر provider این bucketها را با نام‌های متفاوت گزارش می‌کند، و — این تله است — دو تای آن‌ها از یک واژه برای دو کمیت متفاوت استفاده می‌کنند.

یک call را در نظر بگیرید: 4,837 token خوانده‌شده از cache، 110 token تازه، 142 output token قابل‌مشاهده، 300 reasoning token.

three usage payloads, one callJSON
// OpenAI-compatible
{ "usage": { "prompt_tokens": 4947,
             "prompt_tokens_details": { "cached_tokens": 4837 },
             "completion_tokens": 442,
             "completion_tokens_details": { "reasoning_tokens": 300 } } }

// Anthropic
{ "usage": { "input_tokens": 110,
             "cache_read_input_tokens": 4837,
             "cache_creation_input_tokens": 0,
             "output_tokens": 442 } }

// Gemini
{ "usageMetadata": { "promptTokenCount": 4947,
                     "cachedContentTokenCount": 4837,
                     "candidatesTokenCount": 142,
                     "thoughtsTokenCount": 300 } }

به prompt_tokens: 4947 و input_tokens: 110 نگاه کنید. هر دو field شمارش input token برای همان prompt هستند. عدد OpenAI شامل tokenهای cached است؛ عدد Anthropic آن‌ها را مستثنا می‌کند — مستنداتش identity را صریح بیان می‌کند، total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens.5 مقدار input_tokens در Anthropic یعنی «tokenهای بعد از آخرین cache breakpoint شما».

و به output نگاه کنید. OpenAI و Anthropic هر دو 442 گزارش می‌کنند، که همین حالا 300 reasoning token را در خود دارد. Gemini عدد 142 را گزارش می‌کند و 300 را در field جداگانهٔ خودش می‌گذارد. فصل 12 این را به‌عنوان ناسازگاری بین دو روش شمارش یک کار واحد علامت‌گذاری کرد؛ اینجا می‌بینید هزینه‌اش چیست.

یک normaliser سی خط است و اختیاری نیست:

normalise.tsTS
export interface Usage {
  promptTokens?: number;        // input, NOT cached
  cachedInputTokens?: number;   // read from cache
  cacheWriteTokens?: number;    // written to cache on this call
  completionTokens?: number;    // output
  reasoningTokens?: number;     // billed apart from output (Gemini only)
}

const num = (v: unknown) => (typeof v === "number" && isFinite(v) ? v : 0);

export const fromOpenAI = (raw: any): Usage => {
  const u = raw.usage ?? {}, d = u.prompt_tokens_details ?? {};
  const cached = num(d.cached_tokens), write = num(d.cache_write_tokens);
  return {
    promptTokens: Math.max(0, num(u.prompt_tokens) - cached - write), 
    cachedInputTokens: cached,
    cacheWriteTokens: write,
    completionTokens: num(u.completion_tokens),   // reasoning already inside
    reasoningTokens: 0,
  };
};

export const fromAnthropic = (raw: any): Usage => {
  const u = raw.usage ?? {};
  return {
    promptTokens: num(u.input_tokens),            // already excludes cache
    cachedInputTokens: num(u.cache_read_input_tokens),
    cacheWriteTokens: num(u.cache_creation_input_tokens),
    completionTokens: num(u.output_tokens),
    reasoningTokens: 0,
  };
};

export const fromGemini = (raw: any): Usage => {
  const m = raw.usageMetadata ?? {}, cached = num(m.cachedContentTokenCount);
  return {
    promptTokens: Math.max(0, num(m.promptTokenCount) - cached),
    cachedInputTokens: cached,
    cacheWriteTokens: 0,
    completionTokens: num(m.candidatesTokenCount), // EXCLUDES thinking
    reasoningTokens: num(m.thoughtsTokenCount),    // billed at output rate
  };
};

سه payload بالا را از سه reader عبور دهید و هر سه همان Usage را تولید می‌کنند، و بنابراین همان عدد را: $0.006491. کل هدف نوشتن این لایه همین توافق است.

اگر اشتباه کنید، روی همان call این‌قدر هزینه دارد:

mistakebillederror
برخورد با cached_tokens به‌عنوان چیزی اضافی نسبت به prompt_tokens$0.0161652.49× — prompt را دوبار charge می‌کنید
رایگان گرفتن cache readها به‌جای 0.1×$0.0055240.85× — 15٪ را خودتان می‌خورید
خواندن candidatesTokenCount و نادیده گرفتن thoughtsTokenCount$0.00289155٪ از call ناپدید می‌شود

سومی خطرناک است، چون بی‌صدا و در جهت خبر خوب fail می‌کند. داشبورد شما نشان می‌دهد یک reasoning model کمتر از نصف هزینهٔ واقعی‌اش هزینه دارد، و هیچ‌جا هیچ errorی بالا نمی‌آید.

وقتی bucketها normalised شدند، cost function کوتاه است. تنها بخش غیرآشکار tier lookup است، که بخش بعد توضیح می‌دهد:

cost.tsTS
export interface Tier { maxPromptTokens: number | null; price: number }
export interface Pricing {
  input: Tier[]; output: Tier[];
  cachedInput?: Tier[]; cacheWrite?: Tier[]; reasoning?: Tier[];
}

const tierPrice = (tiers: Tier[] | undefined, contextSize: number, fallback?: Tier[]) => {
  const table = tiers ?? fallback;
  if (!table?.length) return 0;
  const sorted = [...table].sort(
    (a, b) => (a.maxPromptTokens ?? Infinity) - (b.maxPromptTokens ?? Infinity));
  for (const t of sorted)
    if (t.maxPromptTokens === null || contextSize <= t.maxPromptTokens) return t.price;
  return sorted[sorted.length - 1].price;
};

export function computeCost(pricing: Pricing, usage: Usage): number {
  const fresh = usage.promptTokens ?? 0;
  const read  = usage.cachedInputTokens ?? 0;
  const write = usage.cacheWriteTokens ?? 0;
  const out   = usage.completionTokens ?? 0;
  const think = usage.reasoningTokens ?? 0;
  const contextSize = fresh + read + write;   // the tier depends on the WHOLE prompt
  return fresh * tierPrice(pricing.input, contextSize)
       + read  * tierPrice(pricing.cachedInput, contextSize, pricing.input)
       + write * tierPrice(pricing.cacheWrite,  contextSize, pricing.input)
       + out   * tierPrice(pricing.output, contextSize)
       + think * tierPrice(pricing.reasoning, contextSize, pricing.output);
}

دو تصمیم طراحی در آنجا ارزش دفاع کردن دارند. fallbackها — قیمت‌های cache که به input برمی‌گردند، و reasoning که به output برمی‌گردد — معنای یک جدول ناقص را encode می‌کنند: reasoning tokenها در Gemini با نرخ output صورت‌حساب می‌شوند، پس نبودن قیمت reasoning صفر نیست، قیمت output است. و contextSize هر سه bucket ورودی را جمع می‌کند، نه فقط freshها را، چون tier بر اساس طول prompt انتخاب می‌شود، نه بر اساس اینکه از چه مقدار آن full price گرفته شده.

prompt cache وضعیت محاسبه‌شدهٔ مدل را برای یک prefix از prompt شما ذخیره می‌کند، تا request بعدی با همان prefix از محاسبهٔ دوبارهٔ آن عبور کند. چهار ویژگی از واژهٔ «prefix» نتیجه می‌شود و هر چهار مورد مردم را غافلگیر می‌کنند.

cache از ابتدای prompt رندرشده به جلو match می‌کند و در اولین byte متفاوت متوقف می‌شود. برای محتوایی که بعداً در ترتیب دیگری ظاهر می‌شود امتیاز جزئی وجود ندارد. OpenAI صاف می‌گوید: «cache reuse نیاز دارد کل rendered prefix match شود.»6

کمتر از آن، هیچ چیز cache نمی‌شود و هیچ errorی برنمی‌گردد. در OpenAI حداقل برای GPT-5.6 و بعد از آن 1,024 token است و برای مدل‌های قدیمی‌تر 2,048. در Anthropic بسته به مدل از 512 تا 4,096 متغیر است — 1,024 برای Claude Sonnet 4.5، و 4,096 برای Claude Haiku 4.5. اگر هر دو cache field صفر برگشتند، معمولاً دلیلش همین است.

نوشتن از خواندن گران‌تر است، و از cache نکردن هم گران‌تر

لینک به بخش: نوشتن از خواندن گران‌تر است، و از cache نکردن هم گران‌تر

در OpenAI و Anthropic، cache write برای cache کوتاه‌عمر 1.25× نرخ uncached input است، و cache یک‌ساعتهٔ Anthropic برابر 2×. خواندن 0.1× است. Google برای نوشتن هزینه‌ای نمی‌گیرد اما storage را اجاره می‌دهد: $4.50 به‌ازای هر میلیون token در ساعت روی Gemini 2.5 Pro.

منقضی می‌شود، و روی یک ماشین زندگی می‌کند

لینک به بخش: منقضی می‌شود، و روی یک ماشین زندگی می‌کند

entry پیش‌فرض Anthropic پنج دقیقه زنده می‌ماند و با هر hit رایگان refresh می‌شود. OpenAI حداقل سی دقیقه پس از آخرین write یا reuse است. و OpenAI اشاره می‌کند که cached stateها روی ماشین‌های جداگانه زندگی می‌کنند، پس یک request فقط وقتی hit می‌شود که به ماشینی route شود که entry را نگه داشته — چیزی که prompt_cache_key روی آن اثر می‌گذارد، بدون تضمین.

break-even آن‌قدر کوچک است که می‌شود در ذهن نگه داشت، و مستندات OpenAI خودش حساب را انجام می‌دهد: یک‌بار نوشتن prefix و یک‌بار reuse کردنش 1.35× هزینهٔ input معمولی آن را دارد، در برابر 2× برای پردازش دوبارهٔ آن بدون cache؛ در ده request، یک write و نه read برابر 2.15× هزینه دارد، در برابر 10×. یک reuse هزینهٔ write را جبران می‌کند. Anthropic هم به همان‌جا می‌رسد: یک read برای cache پنج‌دقیقه‌ای، دو read برای cache یک‌ساعته.

حالا دوباره همان گفت‌وگوی چهل‌نوبتی، با caching روشن و prefix پایدار:

uncached inputcache readscache writestotal
no cache112,617$0.274386
caching2,887104,7834,947$0.088250

شصت‌وهشت درصد ارزان‌تر، و سه عدد در این جدول ارزش توجه دارند.

cache تا نوبت 6 فعال نمی‌شود. prompt تا آن موقع به 1,024 token نمی‌رسد، پس پنج نوبت اول دقیقاً مثل قبل صورت‌حساب می‌شوند — و ششم بدتر صورت‌حساب می‌شود، با premium نوشتن 1.25×، چون همان نوبتی است که cache را پر می‌کند. اولین read در نوبت 7 می‌آید. عدد 2,887 uncached token در جدول همین حساب است: ارزش پنج نوبت، نه شش نوبت. Caching discount روی promptهای بلند است، و گفت‌وگوی کوتاه چیزی از آن نمی‌گیرد.

premium نوشتن $0.002474 است، یعنی 2.8٪ از صورت‌حساب cached. هر نوبت tail تازهٔ خودش را می‌نویسد، چهل بار، و کل premium نوشتن در برابر چیزی که readها ذخیره کردند خطای گرد کردن است. ارزش دارد write charge را دقیق بفهمید تا دیگر نگرانش نباشید.

فقط 2,887 token با قیمت کامل input charge شد از 112,617. شکل یک cache سالم همین است: تقریباً همه چیز read است.

ترتیب prompt تعیین می‌کند آیا اصلاً این اتفاق می‌افتد یا نه

لینک به بخش: ترتیب prompt تعیین می‌کند آیا اصلاً این اتفاق می‌افتد یا نه

اینجا failureی است که پول واقعی هزینه می‌کند، و یک باگ یک‌خطی است.

چیزی را که در هر call تغییر می‌کند نزدیک ابتدای prompt بگذارید — timestamp، request id، نام کاربر، یک خط «امروز ... است»، یک سند تازه retrieve‌شده — و prefix از byte اول متفاوت می‌شود. هیچ چیز match نمی‌شود. هر call یک miss است. و چون هر call یک prefix جدید ارائه می‌کند، هر call همچنین می‌نویسد.

همان گفت‌وگو، همان چهل نوبت، caching روشن، با timestamp مخصوص هر call در بالای system prompt:

totalversus
no caching at all$0.274386
caching, stable prefix$0.088250−67.8٪
caching, volatile prefix$0.329251+20.0٪

روشن کردن prompt caching گفت‌وگو را بیست درصد گران‌تر از روشن نکردنش کرد. شما premium نوشتن 1.25× را روی 109,730 token پرداخت کردید و صفر read گرفتید. هیچ error، هیچ warning، و feature روشن است.

پس rule، و کل prompt caching در یک خط، این است: محتوای پایدار جلو، محتوای متغیر عقب. ابتدا system instructions، tool definitions و reference material؛ timestampها، user identity و پرسش فعلی در آخر. Anthropic سلسله‌مراتب را صریح می‌کند — cache از toolssystemmessages پیروی می‌کند، و تغییر در هر سطح همان سطح و همهٔ بعد از آن را invalid می‌کند، پس ویرایش یک tool description واحد کل cache را invalid می‌کند.5

دو پیامد هست که مردم در آن گیر می‌کنند. تغییر اینکه کدام tools enabled هستند tool definitions را تغییر می‌دهد، پس feature flagی که برای بعضی کاربران tool اضافه می‌کند cache شما را دو قسمت می‌کند. و در Anthropic، روشن و خاموش کردن web search یا citations system prompt را تغییر می‌دهد، که بدون دست زدن شما به یک خط از متن خودتان، system و message cacheها را invalid می‌کند.

Truncate کردن history راه‌حل نیست

لینک به بخش: Truncate کردن history راه‌حل نیست

پاسخ بدیهی به صورت‌حساب درجه‌دو این است که ارسال کل history را متوقف کنید: دوازده message آخر را نگه دارید و بقیه را بیندازید. این کار صورت‌حساب را کم می‌کند، و معمولاً حرکت اشتباهی است، و اندازه‌گیری می‌گوید چرا.

strategytotalversus full history + cache
full history, no cache$0.274386+211٪
full history, caching$0.088250
last 12 messages, no cache$0.118712+35٪
last 12 messages, caching on$0.122546+39٪

Truncate کردن به یک window دوازده‌messageی 57٪ ارزان‌تر از ارسال همه‌چیز بدون cache است — مقایسه‌ای که همه انجام می‌دهند و دلیل محبوبیت تکنیک. اما 39٪ گران‌تر از ارسال همه‌چیز با cache سالم است، و روشن کردن caching کنار truncation آن را کمی بدتر می‌کند، نه بهتر.

mechanism دوباره همان prefix است. sliding window در هر نوبت قدیمی‌ترین message را حذف می‌کند، پس prompt دیگر از همان‌جایی شروع نمی‌شود که دفعهٔ قبل شروع شده بود و هر نوبت prefix تازه‌ای ارائه می‌کند. راهنمای OpenAI دقیقاً همین را می‌گوید: «summarisation، compaction یا context truncation می‌تواند prefix را تغییر دهد و cache reuse را reset کند.»6 تا نوبت 40، prompt پنجره‌ای 813 token است، کمتر از حداقل 1,024-token، پس اصلاً نمی‌تواند cache شود.

و پول، نیمهٔ ارزان هزینه است. چیزی که حذف کردید instructionی است که کاربر در نوبت 2 داده بود و مدل در نوبت 40 به آن نیاز داشت. Truncation صورت‌حسابی را که می‌بینید با failureی که نمی‌بینید معاوضه می‌کند، و درست انجام دادنش — compaction، یادداشت‌های structured بیرون از window، retrieve کردن history بر اساس نیاز — موضوع فصل 24 است.

عبور از tier کل request را دوباره قیمت‌گذاری می‌کند

لینک به بخش: عبور از tier کل request را دوباره قیمت‌گذاری می‌کند

contextهای بلند فقط به این دلیل گران‌تر نیستند که بلندترند. بعد از یک threshold، به‌ازای هر token گران‌تر می‌شوند، و threshold به‌صورت retroactive روی کل prompt اعمال می‌شود.

صفحهٔ مدل OpenAI برای gpt-5.6-terra در یک جمله می‌گوید: «Promptهایی با بیش از 272K input token برای کل request با 2x input و 1.5x output قیمت‌گذاری می‌شوند.»7 نه فقط برای مازاد. برای کل چیز.

the most expensive token you will ever sendTEXT
prompt 271,999 + 500 output  ->  $0.5500
prompt 272,000 + 500 output  ->  $0.5500
prompt 272,001 + 500 output  ->  $1.0970

یک token، پنجاه‌وپنج سنت. اگر سرویس شما promptها را از اسناد retrieve‌شده‌ای می‌سازد که اندازه‌شان در کنترل شما نیست، در cost model خودتان یک پرتگاه دارید در مرزی که هیچ‌کس در تیم شما جایی ننوشته است.

قیمت‌گذاری Google هم با threshold 200,000-token همین‌طور کار می‌کند: Gemini 2.5 Pro برای promptهای تا 200K برابر $1.25 به‌ازای هر میلیون input token است و بالاتر از آن $2.50، و output از $10.00 به $15.00 می‌رود.8 Anthropic مسیر دیگری رفت — تا 6 سپتامبر 2026، مستنداتش می‌گوید Claude 4.6 و بعد از آن کل window یک‌میلیون-token را با قیمت استاندارد شامل می‌شوند، بنابراین «یک request 900k-token با همان نرخ per-token یک request 9k-token صورت‌حساب می‌شود.»9 مدل‌های قدیمی‌تر surcharge را نگه داشتند.

برای همین price یک عدد نیست. price جدولی از tierهاست که با طول prompt کلید می‌شود، و Tier[] در cost function برای همین است، و به همین دلیل computeCost tier را با کل prompt انتخاب می‌کند، نه هر bucket به‌صورت جداگانه.

Prefill، decode، و اینکه چرا output شش برابر input هزینه دارد

لینک به بخش: Prefill، decode، و اینکه چرا output شش برابر input هزینه دارد

پنج bucket روی دو فاز فصل 13 map می‌شوند، و وقتی mapping را ببینید نسبت‌های قیمت دیگر دل‌بخواهی به نظر نمی‌رسند.

Input tokenها prefill هستند. کل prompt در یک pass از مدل عبور می‌کند، به‌صورت parallel پردازش می‌شود — ضرب‌های ماتریسی بزرگ، compute-bound. هزینه به‌ازای هر token پایین است، و این همان فازی است که time to first token را تعیین می‌کند: یک prompt با 4,947 token باید 4,947 token prefill انجام دهد پیش از آنکه اولین کلمه ظاهر شود.

Output tokenها decode هستند. آن‌ها یکی‌یکی تولید می‌شوند، هر کدام یک forward pass کامل که کل KV cache را می‌خواند، در حالی که GPU بیشتر منتظر حافظه است تا مشغول محاسبه. این همان فازی است که tokens per second را تعیین می‌کند، درون یک response قابل parallel شدن نیست، و دلیل این است که output روی مدلی که اینجا قیمت‌گذاری شده حدود شش برابر input هزینه دارد: $12.00 در برابر $2.00 به‌ازای هر میلیون token.

سه پیامد مستقیم دارد. cache read جایگزین کار prefill می‌شود، پس هم‌زمان latency و پول می‌خرد — همان discount به‌صورت صورت‌حساب کمتر و انتظار کوتاه‌تر برای first token ظاهر می‌شود. Reasoning tokenها decodeی هستند که هرگز نمی‌بینید، برای همین reasoning model چند ثانیه هیچ چیز stream نمی‌کند و بعد سریع جواب می‌دهد: فصل 12 دربارهٔ پیامد interface هشدار داد، و اینجا پیامد invoice آن است. و abort کردن stream generation را متوقف نمی‌کندفصل 14 cancellation را ساخت و قیمت را به این فصل واگذار کرد، و قیمت همان output count کامل است، چون tokenها تولید و صورت‌حساب می‌شوند چه کسی گوش بدهد چه ندهد. پاسخ‌هایی که کسی نگه نمی‌دارد هم همین‌اند: regenerate کردن پاسخ نوبت 40 پنج بار، برای همان یکی که روی صفحه می‌ماند $0.057990 هزینه دارد.

tokenizer فصل 7 Python بود و همان‌جا ماند. Budgeting در serverی اتفاق می‌افتد که request را می‌سازد، پس باید اینجا انجام شود، و دقیقاً سه سطح accuracy در دسترس است.

سطح یک: محلی بشمارید. js-tiktoken همان BPE merge tableهای tiktoken در Python را دارد، بنابراین برای encodingهای OpenAI شمارشی byte-for-byte identical، بدون network call:

count.tsTS
import { getEncoding } from "js-tiktoken";

const enc = getEncoding("o200k_base");
const PER_MESSAGE = 4;   // role and delimiters added by the chat template
const PER_REPLY = 3;     // priming for the assistant turn

export function promptTokens(messages: { role: string; content: string }[]) {
  return messages.reduce(
    (sum, m) => sum + enc.encode(m.content).length + PER_MESSAGE, PER_REPLY);
}

دو constant مهم‌اند و همان‌جایی‌اند که شمارش‌های محلی drift می‌کنند. متن شما آن چیزی نیست که tokenize می‌شود — chat template فصل 11 ابتدا هر message را در role markerها wrap می‌کند، و آن‌ها tokenهایی هستند که بابتشان پول می‌دهید. چهار token به‌ازای هر message و سه token برای reply priming تقریب رایج برای مدل‌های chat در OpenAI است؛ در طول هشتاد و یک message گفت‌وگوی بالا، جمعاً 324 token می‌شود، یعنی 6.4٪ طول آن. شمارش‌های اینجا با tiktoken در Python از فصل 7 روی همهٔ هشتاد و یک string cross-check شدند و identical هستند.

سطح دو: از provider بپرسید. Anthropic، /v1/messages/count_tokens را expose می‌کند و Google، count_tokens را؛ هر دو همان شکل request یک call واقعی را می‌پذیرند و یک شمارش input token رایگان برمی‌گردانند. وقتی نمی‌توانید محلی بشمارید از آن‌ها استفاده کنید — و برای Anthropic نمی‌توانید محلی بشمارید، چون tokenizer آن published نیست. مستندات Anthropic دربارهٔ چیزی که می‌دهد محتاط است: count «یک estimate» است، و «ممکن است tokenهایی را شامل شود که Anthropic برای system optimizations به‌طور خودکار اضافه می‌کند»، که «برای آن‌ها صورت‌حساب نمی‌شوید».10

سطح سه: usage را در response بخوانید. حقیقت همان است، و بعد از خرج شدن پول می‌رسد. دقیقاً برای همین دو سطح اول وجود دارند — برای تصمیم اینکه request را بفرستید یا نه، نه برای bill کردن آن.

چیزهایی که برایشان پول می‌دهید و هیچ‌کس نشانشان نمی‌دهد

لینک به بخش: چیزهایی که برایشان پول می‌دهید و هیچ‌کس نشانشان نمی‌دهد

چهار line item که به‌صورت line item ظاهر نمی‌شوند.

system prompt، در هر call پرداخت می‌شود. مورد بالا با template overhead خودش 192 token است. در چهل call می‌شود 7,680 token — 5.6٪ از کل صورت‌حساب این گفت‌وگو، برای هشت خطی که یک‌بار نوشته شده. همچنین بهترین candidate ممکن برای cache است، چون هم stable است هم first.

Tool definitions. نام، description و JSON schema هر tool در هر request ارسال می‌شود، و providerها scaffolding هم اضافه می‌کنند. Anthropic عدد را منتشر می‌کند: صرف enabled کردن tools یک hidden system prompt با 496 token روی Claude Sonnet 4.5 اضافه می‌کند وقتی tool_choice روی auto باشد، یا 588 با any یا یک named tool.9 این پیش از schemaهای خودتان است. فصل 18 catalogue را می‌سازد؛ فصل 24 اندازه می‌گیرد چه می‌خورد.

هر generation، از جمله آن‌هایی که دور می‌اندازید. پنج regeneration پنج برابر هزینه دارد. chat یکی را نشان می‌دهد.

Thoughtهایی که به شما نشان داده نمی‌شوند. Billing بر اساس full thought tokens است، هرچند فقط summary برمی‌گردد، و هیچ accountingی از سمت شما نمی‌تواند آن عدد را audit کند.

داشتن 200K token یعنی استفاده کردن از آن‌ها نیست

لینک به بخش: داشتن 200K token یعنی استفاده کردن از آن‌ها نیست

یک warning برای پایان، چون فکر طبیعی بعدی همین است و پاسخ آن جواب بدیهی نیست.

window یک‌میلیون-token به‌معنای یک‌میلیون token قابل‌استفاده نیست. دقت retrieval با position افت می‌کند: Liu و همکاران دریافتند مدل‌ها اطلاعات را در ابتدا و انتهای input بلند reliably پیدا می‌کنند و در میانه بسیار کمتر reliably.11 window بزرگ‌تر توانایی ارسال بیشتر را می‌خرد، نه قطعیت خوانده شدن.

این پدیده یک‌بار در این دوره اندازه‌گیری شده — نرخ retrieval در نه position در همان prompt با 853 token — و جای آن در فصل 24 است، جایی که کاری را که یک agent انجام می‌دهد تغییر می‌دهد. اینجا cite شده چون چیزی را که باید بخرید تغییر می‌دهد: ارزان‌ترین token همان tokenی است که نفرستادید.

حالا می‌توانید پیش از انجام یک call هزینه‌اش را predict کنید، بعد از آن هزینهٔ واقعی‌اش را بخوانید، و تفاوت این دو را تشخیص دهید. این همهٔ request را پوشش می‌دهد، جز بخشی که هنوز لمس نکرده‌اید: knobها.

فصل 17 sampling است — temperature، top-p، top-k، penaltyها، و determinismی که ندارید. با dismantle کردن رایج‌ترین خطای این حوزه شروع می‌کند: اینکه temperature یک creativity dial است. نیست: temperature مقدار logitها از فصل 4 را پیش از softmax تقسیم می‌کند، و بالا بردنش مدل را imaginative نمی‌کند؛ احتمال tokenهایی را بالا می‌برد که خود مدل بدتر score کرده. از آنجا، اینکه چرا greedy decoding متنی measurably بدتر از sampling تولید می‌کند، چرا top-k و top-p روی شکل‌های مخالف distribution شکست می‌خورند، و آزمایشی که فصل را تمام می‌کند: بیست forward pass identical در temperature 0 وقتی مدل تنها اجرا می‌شود bit-for-bit identical برمی‌گردند، و گذاشتن همان prompt در یک batch کنار requestهای دیگران 97٪ از logitهایش را جابه‌جا می‌کند.

همه‌شان match نمی‌شوند. دلیلش با کادر floating-point از فصل 2 شروع می‌شود.


همهٔ priceها، thresholdها و multiplierهای این فصل در 6 سپتامبر 2026 از صفحه‌های خود providerها خوانده شده‌اند و با همین تاریخ بیان می‌شوند چون تغییر خواهند کرد. روش از اعداد مهم‌تر است: bucketها، rule مربوط به prefix و arithmetic مربوط به tierها دو سال پایدار بوده‌اند، در حالی که هر عدد داخلشان جابه‌جا شده است.

سخنرانی 2 از Stanford CS336، Resource accounting، نزدیک‌ترین treatment آکادمیک این material است و next read درست: همان arithmetic را در سمت training انجام می‌دهد که این فصل در سمت inference انجام می‌دهد. token countهای اینجا با js-tiktoken نسخهٔ 1.0.21 و با encodingهای o200k_base و cl100k_base، روی یک گفت‌وگوی چهل‌نوبتی با 5,090 token تولید شدند؛ per-message template overhead همان تقریب رایج چهار-به‌علاوه-سه است و هرجا شامل شده بیان شده. ارقام cache، tier و truncation حاصل اعمال ruleهای documented pricing روی آن token countهای اندازه‌گیری‌شده‌اند، نه observation از live API responseها — هیچ paid callی برای تولید این فصل انجام نشده، و این همچنین دلیل صادقانهٔ آن است که ادعاهای latency کیفی‌اند و ادعاهای cost نه.

  1. Dao, T., Fu, D. Y., Ermon, S., Rudra, A. and Ré, C. FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. arXiv:2205.14135 (2022). اینکه چرا ceiling بدون تغییر asymptotic cost جابه‌جا شد.

  2. Chen, S., Wong, S., Chen, L. and Tian, Y. Extending Context Window of Large Language Models via Positional Interpolation. arXiv:2306.15595 (2023).

  3. Peng, B., Quesnelle, J., Fan, H. and Shippole, E. YaRN: Efficient Context Window Extension of Large Language Models. arXiv:2309.00071 (2023).

  4. Google، Thinking، ai.google.dev/gemini-api/docs/thinking، و Token counting، ai.google.dev/gemini-api/docs/tokens، هر دو accessed 2026-09-06. «Pricing is based on the full thought tokens the model needs to generate, despite only the summary being output from the API.» usage object این‌ها را گزارش می‌کند: total_input_tokens، total_output_tokens، total_thought_tokens، total_cached_tokens، total_tool_use_tokens و total_tokens — شش bucket، با thoughts و tool use بیرون از output count. نام field قبلی برای همان quantity، که هنوز توسط سطح generateContent برگردانده می‌شود، thoughtsTokenCount است، که در صفحهٔ سومی مستند شده، ai.google.dev/gemini-api/docs/generate-content/thinking.

  5. Anthropic، Prompt caching، docs.anthropic.com/en/docs/build-with-claude/prompt-caching، accessed 2026-09-06. منبع سلسله‌مراتب invalidation با toolssystemmessages و table آن؛ حداقل طول‌های قابل cache شدن برای هر مدل؛ identity total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens؛ و lifetime پیش‌فرض پنج‌دقیقه‌ای که با هر hit بدون charge refresh می‌شود. 2

  6. OpenAI، Prompt caching، platform.openai.com/docs/guides/prompt-caching، accessed 2026-09-06. منبع این موارد: rule مربوط به entire-rendered-prefix؛ حداقل prefix قابل cache شدن (1,024 visible input token در GPT-5.6 و بعد از آن، 2,048 در نسخه‌های قبلی)؛ multiplierهای 1.25× برای write و 0.1× برای read، و نبود هرگونه write charge در GPT-5.5 و قبل از آن؛ lifetime سی‌دقیقه‌ای؛ limitهای چهار write در هر request و پنجاه breakpoint؛ یادداشت machine-affinity و prompt_cache_key؛ مثال‌های محاسبه‌شدهٔ break-even با 1.35×، 2.15× و 10×؛ و statement اینکه summarisation، compaction یا truncation، cache reuse را reset می‌کند. 2

  7. OpenAI، Pricing (platform.openai.com/docs/pricing) و صفحهٔ مدل برای gpt-5.6-terra، هر دو accessed 2026-09-06. gpt-5.6-terra، standard service tier، به‌ازای هر میلیون token: input $2.00، cached input $0.20، cache writes $2.50، output $12.00؛ long context input $4.00، cached $0.40، writes $5.00، output $18.00؛ «promptهایی با >272K input token برای کل request با 2x input و 1.5x output قیمت‌گذاری می‌شوند»؛ context window برابر 1,050,000 token با حداکثر 922,000 input token. همان table، gpt-6-astra را با $10.00/$1.00/$12.50/$50.00 و gpt-5.6-luna را با $0.20/$0.02/$0.25/$1.20 فهرست می‌کند. همهٔ costهای worked در این فصل از نرخ‌های standard short-context برای gpt-5.6-terra استفاده می‌کنند.

  8. Google، Gemini Developer API pricing، ai.google.dev/gemini-api/docs/pricing، accessed 2026-09-06. Gemini 2.5 Pro، به‌ازای هر میلیون token: input $1.25 برای promptهای تا 200K و $2.50 بالاتر از آن؛ output $10.00 و $15.00، که در هر دو مورد با برچسب «including thinking tokens» آمده؛ context caching $0.125 و $0.25، به‌علاوهٔ storage charge برابر $4.50 به‌ازای هر میلیون token در ساعت. Gemini 3.1 Pro Preview از همان threshold 200K با input $2.00/$4.00 و output $12.00/$18.00 استفاده می‌کند.

  9. Anthropic، Pricing، docs.anthropic.com/en/docs/about-claude/pricing، accessed 2026-09-06. به‌ازای هر میلیون token، base input / 5-minute cache write / 1-hour cache write / cache read / output: Claude Sonnet 4.5 $3 / $3.75 / $6 / $0.30 / $15؛ Claude Haiku 4.5 $1 / $1.25 / $2 / $0.10 / $5؛ Claude Opus 5 $5 / $6.25 / $10 / $0.50 / $25. Multiplierها: 1.25× برای write پنج‌دقیقه‌ای، 2× برای write یک‌ساعته، 0.1× برای read. همچنین منبع statement مربوط به long-context («Claude 4.6 و مدل‌های بعدی... کل 1M token context window را با pricing استاندارد شامل می‌شوند»)، token countهای system prompt برای tool-use (496 token روی Claude Sonnet 4.5 با tool_choice از auto یا none، و 588 با any یا یک named tool)، و یادداشت اینکه Claude 4.7 و بعد از آن از tokenizer جدیدتری استفاده می‌کنند که «برای همان متن تقریباً 30٪ token بیشتر» تولید می‌کند. 2 3

  10. Anthropic، Token counting، docs.anthropic.com/en/docs/build-with-claude/token-counting، accessed 2026-09-06. endpoint /v1/messages/count_tokens همان inputهای یک message را می‌گیرد و یک input token count برمی‌گرداند؛ مستندات بیان می‌کند count یک estimate است، ممکن است tokenهایی را شامل شود که Anthropic برای system optimisations اضافه می‌کند، و آن‌ها billed نمی‌شوند.

  11. Liu, N. F., Lin, K., Hewitt, J., Paranjape, A., Bevilacqua, M., Petroni, F. and Liang, P. Lost in the Middle: How Language Models Use Long Contexts. arXiv:2307.03172 (2023). اینجا cite شده، در فصل 24 اندازه‌گیری شده.


تهیه‌شده توسط

David Vicente Campos

بنیان‌گذار NeuraLIA Labs و هم‌بنیان‌گذار MyRealFood

من مهندس کامپیوتر و فارغ‌التحصیل دانشگاه لئون هستم. هم‌بنیان‌گذار MyRealFood بودم، جایی که به‌عنوان مدیر ارشد فناوری اپلیکیشنی را ساختم که میلیون‌ها نفر برای سالم‌تر غذا خوردن از آن استفاده کرده‌اند، و NeuraLIA Labs را بنیان‌گذاری کردم؛ جایی که محصولات هوش مصنوعی می‌سازم. اینجا از چیزهایی می‌نویسم که در طول مسیر باید می‌فهمیدم، همان‌طور که دوست داشتم کسی برایم توضیح می‌داد.

بیشتر درباره نویسنده

منتشرشده توسط NeuraLIA Labs.

پست‌های جدید را در ایمیل خود دریافت کنید

اخبار AI، راهنماها و به‌روزرسانی‌های محصول — هر وقت چیزی ارزشمند منتشر کنیم، یک ایمیل کوتاه می‌فرستیم.

فهرست دوره

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev12 دقیقه مطالعه

مدل هوش مصنوعی Jev برای تصمیم ساخته شده، نه نثر

Jev از TypeSafe AI توجه‌ها را جلب کرده چون هوشمندی نرم‌افزار را مسئله‌ای احتمالاتی می‌بیند: شاخه درست را انتخاب کنید، میزان اطمینان را کنار آن بگذارید، و وقتی کد به یک تصمیم نیاز دارد برای نوشتن متن به یک LLM پول ندهید.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering13 دقیقه مطالعه

مهندسی کانتکست برای عامل‌های AI بلندافق

عامل‌های طولانی‌اجرا فقط به‌خاطر کوچک بودن پنجره شکست نمی‌خورند. وقتی فایل‌ها، خروجی ابزارها و تاریخچهٔ کهنه وظیفه‌ای را که عامل قرار بود تمام کند کنار می‌زنند، شکست رخ می‌دهد.

آماده‌اید انتخاب مدل را به LIA بسپارید؟

با همه مدل‌های هوش مصنوعی در یک جا بسازید — همین امروز رایگان شروع کنید.