跳至内容
16/30第 16 章,共 30 章

把 context window、token 和账单算清楚

一次 40 轮对话的输入 token 计费是自身长度的 22 倍。缓存可降 68%;时间戳放错位置会多花 20%。

本页内容

这里有一段 40 轮的客服对话,逐轮计费。里面没有任何异常:开发者询问 API,assistant 用一两段话回答。整段对话共有 5,090 个文本 token——约 8 页。

轮次prompt token新文本输出本轮成本累计总额
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 轮时,用户只输入了 17 个 token,却按 4,947 个 token 付费。这个问题并不比第一个更难;它还更短。变化在于,这次请求再次携带了整段对话——第 40 次。

这 40 次调用累计计费的输入 token 总数:112,617。这段对话本身只有 5,090 个 token。你为它付了 22 遍的钱。

本章讲清楚为什么会这样、它在各家 provider 的账单上叫什么,以及 5 类收费项中哪些是你能改变的。

查看详情

本章需要用到第二部分的内容。

  • 第 7 章 构建了 tokenizer。这里的计量单位也是 token——同一个单位,现在有了价格。
  • 第 9 章 推导了 self-attention 及其 O(n2)O(n^2) 成本,在渐近记号框中说明。这个成本就是限制存在的原因,这里只链接,不再重新解释。
  • 第 13 章 测量了 prefill 与 decode,并计算了 KV cache 占用。上表里的输入列和输出列,实际买的就是这两个阶段。

其余都是 TypeScript,因为这里是在给远程调用做账,而不是在做模型数学。

这个行业里最昂贵的误解,是以为模型记得一段对话。

它不记得,而第 13 章的机制准确说明了原因。transformer 在生成期间的状态是 KV cache:为序列中每个 token 计算出的 keys 和 values。这个 cache 只在一次请求的生命周期内存在。请求结束后,持有它的进程可以去服务别人,cache 也就消失了。对面没有按用户保存的存储,也没有 session。

因此下一次请求必须携带模型应当知道的一切,模型在输出第一个新 token 之前,会先对整个 prompt 跑一次 forward pass 来重建这个状态。第 15 章把 prompt 称为“完整状态”。物理原因就在这里:prompt 是完整状态,因为调用结束后没有任何别的东西会留下来。

context window 是这个 prompt 加上回答的最大长度。它限制的是你最多能重建多少状态,而不是一个会在请求之间保存东西的容器。把它叫作“模型的记忆”,把因果方向说反了——你不是在填充记忆,而是在付费重新建立一份记忆。

22 这个数字就是这么来的。第 nn 轮携带前面全部 n1n-1 轮,因此一段 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 轮的历史。把 40 轮中测得的累计输入拟合到 an2+bnan^2 + bn,得到 60.22n2+432.25n60.22\,n^2 + 432.25\,n,它预测第 40 轮为 113,645 个 token,实测为 112,617。二次项占主导,而线性项才是用户实际输入的内容。

本章最该带走的一句话是:你的账单随对话长度的平方增长,而不是随最后一个问题增长。 同样 40 个问题,如果完全不带历史,成本是 $0.066036。保留历史的成本是 $0.274386。历史把账单乘以 4.2,而且它还会继续放大,因为乘数就是对话长度。

window 有限,是因为两个原因朝着同一个方向拉。第一个来自第 9 章:attention 会把每个 token 与每个其他 token 比较,所以这一层的工作量随序列长度平方增长。第二个是内存:KV cache 随序列长度线性增长,第 13 章已经算过——在长序列下,它会比权重还大。

这两个限制都被攻克过,但都没有被消除。FlashAttention1 重新组织计算,让它对高带宽内存的读写少得多,因此长序列变得可行,但没有改变渐近成本。Position Interpolation2 和 YaRN3 通过重新缩放第 9 章中的位置编码,扩展已训练模型的可用 window,而不是重新训练。它们共同解释了为什么 window 在 5 年内从 2K 到了 1M。

但它们没有让长 context 变免费。它们提高了天花板,也让斜率更平缓。斜率仍然存在,而本章后面那些价格 tier 衡量的正是它。

互联网上几乎所有成本计算器,都会把一次 API 调用建模为输入 token 乘以输入价格,再加输出 token 乘以输出价格。2023 年这样做是对的。现在它错了,而且会让账单在两个方向上差出 2 倍甚至更多。

现在有 5 类可计费 token:

含义典型价格,相对于输入
未缓存输入模型必须重新处理的 prompt token
cache read从已存前缀中提供的 prompt token0.1×
cache write本次调用写入 cache 的 prompt token1.25× 到 2×
输出模型生成并发送给你的 token5× 到 6×
reasoning模型生成但没有发送给你的 token输出费率

这 5 类中有 3 类在两年前还不是单独的账单行,而两条 cache 线最容易被误解,因为 cache write 比普通输入更贵,不是更便宜。你为存储某些内容支付溢价,之后才能用折扣价读回;这笔交易是否划算,完全取决于你会读多少次。

reasoning 这个桶来自第 12 章,现在给它标上价格,而且有个细节值得说清楚:Google 文档说,定价“基于模型需要生成的完整 thought tokens,尽管 API 只输出摘要。”4 你会为从未传给你的 token 付费。这是唯一一个你无法计数、检查或验证内容的桶。

现在的问题不再是乘法,而是 normalisation。每个 provider 都用不同名称报告这些桶,而且——陷阱在这里——其中两家用同一个词表示两个不同数量。

取一次调用:从 cache 读取 4,837 个 token,110 个 fresh token,142 个可见输出 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: 4947input_tokens: 110。两个字段都是同一个 prompt 的输入 token 数。OpenAI 的字段包含 cached tokens;Anthropic 的字段不包含——它的文档明确写出了这个恒等式,total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens5 Anthropic 的 input_tokens 表示“你最后一个 cache breakpoint 之后的 token”。

再看输出。OpenAI 和 Anthropic 都报告 442,里面已经包含 300 个 reasoning token。Gemini 报告 142,并把 300 放在单独字段里。第 12 章指出过,这是对同一份工作两种计数方式之间的不兼容;这里则说明它会带来什么成本。

normaliser 只有 30 行,而且不可省略:

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。写这一层的全部意义就在于得到这个一致性。

如果弄错,同一次调用会变成这样:

错误计费误差
cached_tokens 当作 prompt_tokens额外部分$0.0161652.49×——prompt 被收了两遍钱
把 cache reads 当成免费,而不是 0.1×$0.0055240.85×——你吃掉 15 %
读取 candidatesTokenCount 并忽略 thoughtsTokenCount$0.002891这次调用的 55 % 消失了

第三种最危险,因为它会悄悄失败,而且方向看起来像好消息。你的 dashboard 会显示 reasoning model 的成本不到真实成本的一半,同时没有任何地方报错。

bucket normalise 之后,成本函数很短。唯一不太显然的部分是 tier 查找,下一节会解释:

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 价格回退到输入,reasoning 回退到输出——编码了缺失价格表的含义:Gemini 上的 reasoning tokens 按输出费率计费,所以缺失的 reasoning 价格不是零,而是输出价格。并且 contextSize 会把三类输入桶全部相加,而不只是 fresh token,因为 tier 是按 prompt 有多长来选择的,不是按其中多少按全价收费来选择的。

prompt cache 存储的是你的 prompt 某个前缀的模型已计算状态,因此后续有相同前缀的请求可以跳过重复计算。“前缀”这个词带来 4 个性质,而这 4 个都会让人意外。

cache 从渲染后的 prompt 开头向后匹配,并在第一个不同字节处停止。内容如果以不同顺序出现在后面,不会得到部分 credit。OpenAI 说得很直白:“cache 复用要求整个渲染前缀匹配。”6

低于最小长度时,不会缓存,也不会返回错误。OpenAI 上,GPT-5.6 及之后模型的最小长度是 1,024 token,较早模型是 2,048。Anthropic 则根据模型从 512 到 4,096 不等——Claude Sonnet 4.5 是 1,024,Claude Haiku 4.5 是 4,096。如果两个 cache 字段都返回零,通常就是这个原因。

在 OpenAI 和 Anthropic 上,短期 cache 的 cache write 是未缓存输入费率的 1.25×,Anthropic 的一小时 cache 是 2×。读取是 0.1×。Google 不收写入费,但收存储租金:Gemini 2.5 Pro 每百万 token 每小时 $4.50。

它会过期,而且只存在于一台机器上

链接到此部分:它会过期,而且只存在于一台机器上

Anthropic 的默认条目存活 5 分钟,每次命中都会免费刷新。OpenAI 的条目在最近一次写入或复用后至少存活 30 分钟。OpenAI 还指出,cached states 存在于单台机器上,所以只有请求被路由到持有该条目的机器时才会命中——这正是 prompt_cache_key 会影响、但不能保证的事情。

break-even 小到可以记在脑子里,而 OpenAI 文档已经帮你做了算术:写入一次前缀并复用一次,成本是普通输入成本的 1.35×,而未缓存处理两次是 2×;10 次请求中,一次写入加 9 次读取是 2.15×,对比未缓存 10×。一次复用就能回本。 Anthropic 的结论也类似:5 分钟 cache 读一次回本,1 小时 cache 读两次回本。

现在再看这段 40 轮对话,开启 caching 且前缀稳定:

未缓存输入cache readscache writes总计
无 cache112,617$0.274386
caching2,887104,7834,947$0.088250

便宜了 68%,而表中有 3 个数字值得注意。

cache 到第 6 轮才开始生效。 prompt 到那时才达到 1,024 token,所以前 5 轮完全按原样计费——而第 6 轮计费还更差,因为它是填充 cache 的那一轮,要付 1.25\u00d7 写入溢价。第一次读取发生在第 7 轮。表中的 2,887 个未缓存 token 就是这笔算术:5 轮的量,不是 6 轮。Caching 是给长 prompt 的折扣,短对话拿不到。

写入溢价是 $0.002474,占 cached bill 的 2.8%。每一轮都写入新的尾部,写了 40 次,而全部写入溢价相对于读取节省的成本只是舍入误差。理解写入收费的精确含义,是为了让你停止为它过度担心。

112,617 个 token 中,只有 2,887 个按完整输入价收费。 这就是正常工作的 cache 形状:几乎一切都是读取。

下面这个失败会真正花钱,而且只是一个一行 bug。

把每次调用都会变化的东西放在 prompt 前面——时间戳、request id、用户姓名、“今天是”这一行、刚检索出来的文档——前缀就会从第一个字节开始不同。没有任何东西匹配。每次调用都是 miss。并且因为每次调用都呈现一个新前缀,每次调用也都会写入

同一段对话,同样 40 轮,启用 caching,但在 system prompt 顶部放一个每次调用不同的时间戳:

总计对比
完全不 caching$0.274386
caching,稳定前缀$0.088250−67.8 %
caching,易变前缀$0.329251+20.0 %

启用 prompt caching 让这段对话比不启用贵了 20%。你对 109,730 个 token 支付了 1.25× 写入溢价,却读回了零。没有错误,没有警告,功能还是开着的。

所以规则——也就是 prompt caching 的一行总结——是:稳定内容放前面,变量内容放后面。 system instructions、tool definitions 和参考材料在前;时间戳、用户身份和当前问题在后。Anthropic 明确给出了层级——cache 遵循 toolssystemmessages,任何层级的变化都会使该层级及其之后的所有内容失效,因此只改一个 tool 描述,也会让整个 cache 失效。5

还有两个后果很容易踩坑。改变哪些 tools 被启用,会改变 tool definitions,所以一个为部分用户添加 tool 的 feature flag 会把 cache 一分为二。并且在 Anthropic 上,切换网页搜索或 citations 会修改 system prompt,这会在你没有改动自己任何文本的情况下,使 system 和 message caches 失效。

面对二次增长账单,最显然的反应是停止发送完整历史:只保留最近十几条消息,把其余丢掉。它确实会降低账单,但通常是错误动作,测量结果说明了原因。

策略总计相对完整历史 + cache
完整历史,无 cache$0.274386+211 %
完整历史,caching$0.088250
最近 12 条消息,无 cache$0.118712+35 %
最近 12 条消息,开启 caching$0.122546+39 %

截断到 12 条消息的 window,比发送全部内容且不缓存便宜 57%——这是人人都会做的比较,也是这个技术流行的原因。但它比发送全部内容且 cache 正常工作贵 39%,而截断同时开启 caching 还会稍微更差,不是更好。

机制还是前缀。滑动 window 每轮都会丢掉最旧消息,所以 prompt 不再从上次开始的地方开始,每一轮都会呈现新前缀。OpenAI 的指导明确说了这一点:“summarisation、compaction 或 context truncation 可能改变前缀并重置 cache 复用。”6 到第 40 轮时,窗口化 prompt 只有 813 token,低于 1,024-token 最小值,因此完全无法缓存。

而钱只是成本中便宜的那一半。你丢掉的,是用户在第 2 轮给出、模型在第 40 轮需要的指令。Truncation 用你看得见的账单换来你看不见的失败;要正确处理它——compaction、保存在 window 外的结构化笔记、按需检索历史——是第 24 章的主题。

长 context 更贵,不仅因为它更长。超过某个阈值后,它的单 token价格也更贵,而且这个阈值会追溯应用到整个 prompt。

OpenAI 对 gpt-5.6-terra 的模型页面用一句话说明:“Prompts with >272K input tokens are priced at 2x input and 1.5x output for the full request.”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,55 美分。如果你的服务从大小不可控的检索文档构建 prompt,那么你的成本模型在一个团队没人写下来的边界上有一座悬崖。

Google 的定价也类似,阈值是 200,000 token:Gemini 2.5 Pro 对 200K 以内 prompt 的输入价是每百万 token $1.25,超过后是 $2.50,输出则从 $10.00 变为 $15.00。8 Anthropic 走了相反方向——截至 2026 年 9 月 6 日,其文档说明 Claude 4.6 及之后模型以标准价格包含完整的一百万 token window,因此“900k-token request 和 9k-token request 按相同的每 token 费率计费。”9 更早模型保留了附加费。

所以价格不是一个数字。价格是一个按 prompt 长度索引的 tier 表,这就是成本函数里 Tier[] 的用途,也解释了为什么 computeCost 用整个 prompt 来选择 tier,而不是对每个 bucket 单独选择。

Prefill、decode,以及为什么输出是输入的 6 倍

链接到此部分:Prefill、decode,以及为什么输出是输入的 6 倍

5 个 bucket 映射到第 13 章的两个阶段;一旦看清这种映射,价格比例就不再显得随意。

输入 token 是 prefill。 整个 prompt 一次性通过模型,并行处理——大型矩阵乘法,受计算限制。每 token 成本低,而这个阶段决定 time to first token:4,947-token prompt 在第一个词出现前,要先完成 4,947 个 token 的 prefill。

输出 token 是 decode。 它们逐个生成,每个 token 都是一次完整的 forward pass,会读取整个 KV cache,GPU 大多数时间在等内存而不是计算。这个阶段决定 tokens per second,它无法在单个回答内部并行化,也解释了为什么本文计价模型中输出约为输入的 6 倍:每百万 token $12.00 对比 $2.00。

三个后果直接随之而来。cache read 替代 prefill 工作,所以它同时购买延迟和金钱收益——同一个折扣会表现为更低账单和更短的首 token 等待。Reasoning tokens 是你看不见的 decode,所以 reasoning model 会先几秒钟什么都不流式输出,然后很快回答:第 12 章警告过界面后果,这里是账单后果。并且中止 stream 不会停止生成——第 14 章构建了 cancellation,把价格留到本章,而价格就是完整输出计数,因为 token 已经生成并计费,无论有没有人在听。没人保留的答案也一样:第 40 轮答案重新生成 5 次,为留在屏幕上的那一次花费 $0.057990。

第 7 章的 tokenizer 是 Python 写的,也留在了那里。预算发生在构建请求的服务器里,所以这里必须做,而且准确度只有 3 个层级。

第一层:本地计数。 js-tiktoken 带有与 Python tiktoken 相同的 BPE merge tables,因此对 OpenAI encodings 可得到逐字节一致的计数,而且不需要网络调用:

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);
}

两个常量很重要,本地计数也正是在这里漂移。被 tokenized 的不是你的纯文本——第 11 章的 chat template 会先用 role markers 包裹每条消息,而这些也是你要付费的 token。每条消息 4 个、reply priming 3 个,是 OpenAI chat models 的常规近似;在上面对话的 81 条消息中,它们合计 324 个 token,占长度的 6.4%。这里的计数与第 7 章的 Python tiktoken 对全部 81 个字符串交叉检查,结果一致。

第二层:问 provider。 Anthropic 暴露 /v1/messages/count_tokens,Google 暴露 count_tokens,两者都接受与真实调用相同的请求形状,并免费返回输入 token 数。当你无法本地计数时使用它们——而 Anthropic 就无法本地计数,因为它的 tokenizer 没有公开。Anthropic 文档谨慎说明它给出的是什么:这个计数“是估计值”,并且“可能包含 Anthropic 为 system optimizations 自动添加的 token”,而这些“不会向你收费”。10

第三层:读取响应中的 usage 那是真相,但它在钱花出去之后才到达。这正是前两层存在的原因——用于决定是否发送请求,而不是用于事后计费。

你会付费、但没人展示给你的东西

链接到此部分:你会付费、但没人展示给你的东西

有 4 个不会作为 line item 出现的 line item。

system prompt,每次调用都付费。 上面那个加上 template overhead 是 192 token。40 次调用合计 7,680 token——占这段对话总账单的 5.6%,只因为一次写下的 8 行文本。它也是最佳 cache 候选,因为既稳定又在最前面。

Tool definitions。 每个 tool 的名称、描述和 JSON schema 都会随每个请求发送,provider 还会在上面加 scaffolding。Anthropic 公布了数字:只要启用 tools,就会在 Claude Sonnet 4.5 上添加一个隐藏 system prompt,tool_choice 设为 auto 时为 496 token,使用 any 或命名 tool 时为 588 token。9 这还没算你自己的 schemas。第 18 章构建目录;第 24 章会测量它吃掉了多少。

每一次 generation,包括你丢弃的那些。 重新生成 5 次就是 5 倍成本。chat 只显示一个。

你看不到的 thoughts。 计费基于完整 thought tokens,尽管只返回摘要,而你自己的任何账本都无法审计那个数字。

最后用一个警告收尾,因为这是自然会想到的下一步,而答案不是显而易见的那个。

一百万 token window 不代表一百万可用 token。检索准确率会随位置下降:Liu 等人发现,模型在长输入的开头和结尾能可靠定位信息,而在中间位置可靠性低得多。11 更大的 window 买到的是发送更多内容的能力,不是内容一定会被读到的确定性。

这个现象在本课程中测量过一次——同一个 853-token prompt 中 9 个位置的 retrieval rate——它属于第 24 章,因为它会改变 agent 的行为。这里引用它,是因为它会改变你应该购买什么:最便宜的 token,是你没有发送的那个。

你现在可以在发起调用前预测它会花多少钱,在调用后读懂它实际花了多少钱,并区分两者。这覆盖了请求中的一切,除了你还没碰过的部分:旋钮。

第 17 章讲 sampling——temperature、top-p、top-k、penalties,以及你并不拥有的 determinism。它从拆解领域中最普遍的错误开始:以为 temperature 是 creativity 旋钮。它不是:temperature 会在 第 4 章的 softmax 之前除以 logits;提高它不会让模型更有想象力,而是提高模型自己评分更差的 tokens 的概率。接着会讲为什么 greedy decoding 生成的文本可测量地比 sampling 更差,为什么 top-k 和 top-p 会在相反形状的分布上失败,以及本章末尾的实验:temperature 0 下 20 次相同 forward pass,如果模型单独运行,会逐 bit 完全一致;但把同一个 prompt 与别人的请求一起放进 batch,会移动它 97% 的 logits。

它们并不全都匹配。原因要从第 2 章的 floating-point 框开始。


本章所有价格、阈值和倍数都在 2026 年 9 月 6 日 从 provider 自己的页面读取,并注明这个日期,因为它们会改变。方法比数字更重要:bucket、前缀规则和 tier 算术这两年一直稳定,而其中每个具体数字都变过。

Stanford CS336 第 2 讲 Resource accounting 是最接近本文材料的学术处理,也是合适的下一篇阅读:它在训练侧做了与本章在 inference 侧相同的算术。这里的 token counts 使用 js-tiktoken 1.0.21 生成,采用 o200k_basecl100k_base encodings,基于一段 40 轮、5,090 token 的对话;每条 message 的 template overhead 使用常规的 4 加 3 近似,并在包含时明确说明。cache、tier 和 truncation 数字,是把文档化定价规则应用到这些测得的 token counts 上,而不是实时 API 响应的观测结果——本章没有发起付费调用,这也是真实解释为什么延迟主张是定性的,而成本主张不是。

  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)。解释为什么天花板移动了,但渐近成本没有改变。

  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,Thinkingai.google.dev/gemini-api/docs/thinking,以及 Token countingai.google.dev/gemini-api/docs/tokens,访问日期均为 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_tokenstotal_output_tokenstotal_thought_tokenstotal_cached_tokenstotal_tool_use_tokenstotal_tokens——6 个 bucket,其中 thoughts 和 tool use 位于输出计数之外。同一数量的早期字段名仍由 generateContent surface 返回,即 thoughtsTokenCount,记录在第三个页面 ai.google.dev/gemini-api/docs/generate-content/thinking

  5. Anthropic,Prompt cachingdocs.anthropic.com/en/docs/build-with-claude/prompt-caching,访问日期 2026-09-06。来源包括 toolssystemmessages 的失效层级及其表格;各模型最小可缓存长度;恒等式 total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens;以及默认 5 分钟生命周期、每次命中免费刷新。 2

  6. OpenAI,Prompt cachingplatform.openai.com/docs/guides/prompt-caching,访问日期 2026-09-06。来源包括:完整渲染前缀规则;最小可缓存前缀(GPT-5.6 及之后为 1,024 个可见输入 token,较早为 2,048);1.25× 写入和 0.1× 读取倍数,以及 GPT-5.5 及之前没有任何写入费用;30 分钟生命周期;每请求 4 次写入和 50 个 breakpoint 限制;机器亲和性说明和 prompt_cache_key;1.35×、2.15× 和 10× 的 break-even 示例;以及 summarisation、compaction 或 truncation 会重置 cache 复用的说明。 2

  7. OpenAI,Pricingplatform.openai.com/docs/pricing)以及 gpt-5.6-terra 的模型页面,访问日期均为 2026-09-06。gpt-5.6-terra,standard service tier,每百万 token:输入 $2.00,cached input $0.20,cache writes $2.50,输出 $12.00;long context 输入 $4.00,cached $0.40,writes $5.00,输出 $18.00;“prompts with >272K input tokens are priced at 2x input and 1.5x output for the full request”;context window 1,050,000 token,最大输入 922,000 token。同一表格列出 gpt-6-astra 为 $10.00/$1.00/$12.50/$50.00,gpt-5.6-luna 为 $0.20/$0.02/$0.25/$1.20。本章所有示例成本都使用 gpt-5.6-terra 的 standard short-context rates。

  8. Google,Gemini Developer API pricingai.google.dev/gemini-api/docs/pricing,访问日期 2026-09-06。Gemini 2.5 Pro,每百万 token:200K 以内 prompt 输入 $1.25,超过后 $2.50;输出 $10.00 和 $15.00,两者都标注“including thinking tokens”;context caching $0.125 和 $0.25,另有每百万 token 每小时 $4.50 的存储费用。Gemini 3.1 Pro Preview 使用相同 200K 阈值,输入 $2.00/$4.00,输出 $12.00/$18.00。

  9. Anthropic,Pricingdocs.anthropic.com/en/docs/about-claude/pricing,访问日期 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。倍数:5 分钟写入 1.25×,1 小时写入 2×,读取 0.1×。也是 long-context 说明(“Claude 4.6 and later models... include the full 1M token context window at standard pricing”)、tool-use system prompt token 数(Claude Sonnet 4.5 上,tool_choiceautonone 时为 496 token,使用 any 或命名 tool 时为 588)以及 Claude 4.7 及之后使用新 tokenizer、对同一文本产生“approximately 30 % more tokens”的说明来源。 2 3

  10. Anthropic,Token countingdocs.anthropic.com/en/docs/build-with-claude/token-counting,访问日期 2026-09-06。/v1/messages/count_tokens endpoint 接收与 message 相同的输入并返回输入 token 数;文档说明该计数是估计值,可能包含 Anthropic 为 system optimisations 添加的 token,且这些不会计费。

  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)。在这里引用,在第 24 章测量。


作者

David Vicente Campos

NeuraLIA Labs 创始人、MyRealFood 联合创始人

我是莱昂大学毕业的计算机工程师。我共同创立了 MyRealFood,并在那里作为 CTO 打造了一款数百万人用来吃得更健康的应用;我还创立了 NeuraLIA Labs,在这里我打造 AI 产品。我在本站写下一路走来所必须理解的内容,就像我希望当初有人向我讲解的那样。

了解作者更多信息

由 NeuraLIA Labs 发布。

新文章直达你的收件箱

AI 新闻、指南和产品更新——有值得你花时间阅读的内容时,我们会发一封简短邮件。

更喜欢用消息接收?同样的内容,也在这里:WhatsApp 社群 (在新标签页打开)Telegram 频道 (在新标签页打开)

课程目录

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev10 分钟阅读

Jev AI 模型为决策而生,而非写作

TypeSafe AI 的 Jev 正受到关注,因为它把软件智能视为一个概率问题:选择正确分支,附上置信度,并避免在代码只需要决策时还花钱让 LLM 写文本。

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering12 分钟阅读

Context engineering for long-horizon AI agents

Long-running agents do not fail only because the window is small. They fail when files, tool outputs and stale history crowd out the task the agent was supposed to finish.

准备好让 LIA 替你选模型了吗?

所有 AI 模型都在一处——今天就免费开始。