简介
成本计算器按上下文长度线性定价:输入 token 增加十倍,费用也增加十倍。这就是费率表的构建方式,而市场自身的定价行为承认这并不是长上下文实际服务的成本。在 DigitalOcean 自家目录中,OpenAI 的 GPT-5.5 和 GPT-5.6 系列在 272K token 时调整费率:GPT-5.5 从每 1M 输入/输出 token 的 $5.00/$30.00 提升至 $10.00/$45.00;GPT-5.6 Sol 从 $4.00/$20.00 提升至 $8.00/$30.00;GPT-5.6 Terra 从 $2.00/$12.00 提升至 $4.00/$18.00;GPT-5.6 Luna 从 $0.20/$1.20 提升至 $0.40/$1.80。整个系列的输入步长恰好是 2 倍,输出步长恰好是 1.5 倍(来源:DigitalOcean 推理定价,最后核实于 2026 年 8 月 24 日)。
Google 的 Gemini 2.5 Pro 表现出相同的模式:在 200K token 以下的提示词,每 1M 输入/输出 token 的价格为 $1.25/$10.00;超过 200K 时升至 $2.50/$15.00,输入翻倍,输出提升 1.5 倍,与 OpenAI 的阶梯形状相符(来源:Gemini 开发者 API 定价,标准层,获取于 2026 年 8 月 27 日)。Anthropic 在 DigitalOcean 目录中自相矛盾:Claude Sonnet 4.5 仍保留旧版层级,200K token 以下为 $3.00/$15.00,以上为 $6.00/$22.50;但目录中列出的每个更新的 Anthropic 模型都是固定价格,没有长上下文阶梯:Sonnet 4.6 为 $3.00/$15.00,Sonnet 5 为 $2.00/$10.00,Opus 4.5 至 4.8 以及 Opus 5 均为 $5.00/$25.00,Fable 5 为 $10.00/$50.00。其中多个模型支持最高 1M token 的上下文窗口且无额外费用。OpenAI 和 Google 仍在其当前一代中保留非线性定价。Anthropic 的当前一代已取消该阶梯。这种分歧并非行业共识,因此我们需要通过硬件测量而非仅阅读费率表来解决问题。
本文是《长上下文推理在规模上的隐藏基础设施成本》的测量经济学续篇,该文阐述了此问题的定性形态:KV 缓存增长与固定硬件容量的冲突。本文为单一模型在单张卡上给出了该形态的具体数值。
定价结构上面的结构性后果是大多数关于长上下文定价的讨论止步于此之前的一步。固定的每 token 费率无论请求携带它所消耗的服务容量多少,都对同一个 token 收取相同的费用。如果服务一个 token 的成本确实随上下文长度而变化——这就是本文旨在测量的——那么单一的固定费率本质上无法跟踪这种变化。从结构上看,这意味着请求的形状是相互定价的,而不是根据每个请求实际服务成本来定价:在一个固定费率下,短上下文和长上下文的请求会相互交叉补贴,而它们实际服务成本与所收费用的比率会随着上下文增长而拉大。长上下文溢价层是提供商用来重新引入这种区别的机制,这也是它们存在的原因正是服务成本的证据,而不仅仅是定价偏好。本文不试图说明任何提供商的费率相对于其自身成本的位置,因为这从外部是不可观测的。它测量您可以租用的硬件上的服务成本曲线,并将定价推断留给读者。
本文在单一模型和单一显卡上测量了该结构性主张背后的曲线:Ministral 3 14B Instruct(DigitalOcean 模型 ID mistral-3-14B,Hugging Face 仓库 mistralai/Ministral-3-14B-Instruct-2512),在单个裸露 NVIDIA H200 GPU Droplet(141 GB VRAM)上使用 vLLM v0.27.1 服务,输入上下文范围为 2K、4K、8K、16K、32K、64K、128K 和 256K tokens。它未使用 Dedicated Inference 产品、AMD MI325X 或第二个 GPU,也不声称测得的曲线是适用于所有模型和所有加速器的普遍定律。它认为该曲线对这一特定配置是真实的,并且其背后的机制——固定 KV 缓存池与线性每 token 增长的冲突——即使在具体数字不同时也具备普遍性。
简要概述
- Ministral 3 14B Instruct 的每 token KV 缓存是固定的,来源于模型自身的配置文件:在 BF16 下每 token 为 163,840 字节(160 KiB),在 FP8 下每 token 为 81,920 字节(80 KiB)。这与负载无关,且随上下文长度线性增长,正是成本计算器所假设的。
- 非线性的部分是批处理容量:在固定 KV 缓存池下,单个 H200 上的测量并发请求数从 2K 时的 311 下降到 256K 时的 2。这种双曲线崩溃是导致每 token 的有效成本上升的原因,尽管每 token 的字节数保持不变。
sliding_window: null 在此模型的 config.json 中得到确认,表示所有 40 层均使用全注意力机制,且线性 KV-cache 每 token 的关系在该模型支持的完整 262,144-token 上下文窗口内保持不变,这与较旧的 Ministral-8B-Instruct-2410 中交错的 1:3 滑动窗口设计不同。mistral-3-14B 的无服务器费率为每 1M token 固定且对称的 $0.20,不会随上下文长度变化,而在专用 H200 上服务这些 token 的实际成本会变化。固定费率无法跟踪呈弯曲的成本曲线,而其他模型的长上下文溢价层级正是为了纠正这一点而存在的。19089.8 / 4967.2,而不是两个四舍五入后的美元数值。mistral-3-14B 的 DigitalOcean 无服务器对称费率(每 1M token $0.20)(盈亏平衡利用率 124.99%,高于任何可实现的持续利用率)。
先决条件
要复现本文中的测量结果,您需要:
- 具有 root 访问权限的 DigitalOcean H200 裸 GPU Droplet(141 GB VRAM)。请参阅 如何为 vLLM 推理选择合适的 GPU 了解在预配置 Droplet 之前如何根据模型的内存占用来选择 Droplet 的大小。
- 在 Droplet 上安装 vLLM v0.27.1(
pip install vllm==0.27.1),这是截至 2026 年 8 月 11 日的当前稳定版本(来源:vLLM 发布历史和 docs.vllm.ai)。 - 能够访问 Hugging Face 上的
mistralai/Ministral-3-14B-Instruct-2512代码库,并具备能够运行huggingface-cli或设置HF_TOKEN的 Python 环境。 - 如果您打算运行 FP8 KV 缓存敏感度臂(参见方法论),则需要单独安装 FlashInfer;本文未验证特定的 FlashInfer 版本,请按照 FlashInfer 官方的安装说明进行操作。
- 一种抓取 vLLM 的 Prometheus 指标端点的方法(
curl足矣),并读取其启动日志,因为此方法从日志中读取容量数字,而不是计算得出。
DigitalOcean 将 mistral-3-14B 列为 Serverless 推理的产品,价格为每 1M 输入 token 0.20 美元,每 1M 输出 token 0.20 美元(来源:DigitalOcean 推理定价,最后验证于 2026 年 8 月 24 日)。该页面未说明 mistral-3-14B 是否为专用推理单独列项;给定模型的专用可用性是根据产品的通用模型支持推断得出,而非逐个模型确认,因此本文选择运行自己的 GPU Droplet,而不是假设专用推理得到支持。
为什么 KV 缓存会线性增长而批处理容量不会
模型架构,从配置中读取
相关架构值来自 config.json 中的 mistralai/Ministral-3-14B-Instruct-2512,主分支,提交 1861cbb11d2a33d8107d82941d5662dedc5b04d8,读取于 2026年8月20日。
| 键 | 值 |
|---|---|
num_hidden_layers |
40 |
num_attention_heads |
32 |
num_key_value_heads |
8(分组查询注意力,4:1) |
head_dim |
128 |
hidden_size |
5120 |
max_position_embeddings |
262144 |
sliding_window |
null |
use_cache |
true |
| 架构 | Mistral3ForConditionalGeneration, 文本 model_type: ministral3 |
| 原生数据类型 | bfloat16 (旗舰仓库还提供 FP8 quantization_config,并且存在一个独立的 -BF16 仓库) |
配置未给出总参数数量;“14B” 是模型名称,而不是来自 config.json 的验证数据,并且 DigitalOcean 也没有发布这样的数据。
滑动窗口检查。 sliding_window 在此配置中为 null。这意味着所有 40 层使用完整注意力,而不是窗口变体,这一点很重要,因为滑动窗口注意力会在窗口大小处限制 KV 缓存的增长,这将打破本文整个前提所依赖的过去该窗口之后的每 token 线性增长。较旧的 Ministral-8B-Instruct-2410 以 1:3 的比例交错完整和滑动窗口层;此模型未继承该设计。在确认 sliding_window: null 之后,标准的每 token KV 缓存线性关系在此处使用的完整 256K 扫描范围内成立。
该模型是多模态的:检查点中存在一个 24 层的 Pixtral 视觉塔。仅提供文本服务不会释放该塔的权重占用显存。这会影响剩余用于 KV 缓存池的内存量,这正是本文从 vLLM 启动日志中读取池大小,而不是从假设的权重大小计算的原因(参见方法论)。要更深入地了解 KV 缓存机制如何一般地影响推理成本,请参阅 如何通过 KV 缓存大幅降低 LLM 推理成本。
每个 token 的 KV 缓存:通过推导得出,而非测量
每个 token 的 KV 缓存大小直接由配置决定:2 × layers × kv_heads × head_dim × bytes_per_element。下面的两个数字是通过推导得出的,而非测量所得:它们源自上面已验证配置值的算术运算,而非基准测试;这里将它们作为架构事实给出,而非实验结果。
layers = 40
kv_heads = 8
head_dim = 128
bf16_bytes_per_token = 2 * layers * kv_heads * head_dim * 2
fp8_bytes_per_token = 2 * layers * kv_heads * head_dim * 1
print(f"BF16: {bf16_bytes_per_token:,} bytes/token ({bf16_bytes_per_token / 1024:.0f} KiB/token)")
print(f"FP8: {fp8_bytes_per_token:,} bytes/token ({fp8_bytes_per_token / 1024:.0f} KiB/token)")
OutputBF16: 163,840 bytes/token (160 KiB/token)
FP8: 81,920 bytes/token (80 KiB/token)
本文并未将该推导延伸到特定上下文长度下的总池大小、批处理容量或并发数,也没有将两个上下文长度之间的特定并发比率作为事实或预测给出。这些数字来源于 vLLM 启动日志,按请求给出,而非来自配置的算术运算。下面的推理解释了为什么日志是来源而不是算术。
为什么容量按双曲线而非线性下降
vLLM 保留的 KV 缓存池是固定字节数,记作 POOL_BYTES。每个在上下文长度 L 下的请求会占用该池中的 L × bytes_per_token 字节。能够同时容纳的请求数大约为:
max_concurrent_requests(L) ≈ POOL_BYTES / (L × bytes_per_token)
这是 L 中的一个双曲线,形式为 k / L。随着上下文长度的增长,在较短上下文中能够并发处理的请求数量固定,而在较长上下文中能够并发处理的请求数量按比例减少,在同一固定池中。这是批处理容量的双曲线下降,而不是线性下降,也是本文论点的机制:总吞吐量受限于在 KV 池(而非计算)成为瓶颈时能够并发运行的请求数量,而该上限随着上下文增长呈曲线下降,而不是线性下降。
此公式描述了受内存限制的状态,在此次扫描中,从 2K 到 256K 全程没有任何空闲。在每个点上,包括 2K,测得的峰值并发数恰好匹配 floor 的 boot-log 天花板:在 2K 时为 311,对应报告的 311.02x;随后在更长的点上分别为 155、77、38、19、9、4、2,且没有任何一次试验低于该天花板。在测试范围内的任何地方,计算受限或调度受限的天花板都未将并发数限制在池暗示的数量以下。--max-num-seqs 的上限固定在 512,而 2K 实际达到了 311 个并发请求,因此实际到达该上限的空间从未被接近。这并不排除在 2K 以下存在计算或调度下限的可能性,在那些地方公式会继续预测更高的并发数;而此次扫描的最短点只是未达到该下限。
上述公式同样纯粹作为其自身算术的结果,暗示了在扫描中任意两个上下文长度之间的理论最大并发比率,例如在 2K 和 256K 点之间。该比率是一个 来源于公式本身的构造推导期望,而非测量结果,并且在此处仅此一次地说明,正是出于此原因。此次扫描实际测量的是每点的并发数,这些数值恰好落在每个 boot-log 天花板的整数 floor 上,而不是两点之间的连续比率。不要将理论比率提升为发现:整数取 floor 不会在曲线上保持干净的比率(在 2K 处为 311,在 256K 处为 2,并不是已发表的 155.5x 结果),而 Results 部分报告的是测得的每点数值。该比率在 Key Takeaways 或本文其他任何地方都不会再次出现,也不被视为一个发现。
每个上下文长度的测量持续并发数(实线,log₂ 纵轴),与在取整到整数请求之前的连续 pool ÷ context 比率(虚线)相对比。两个轴均为 log₂,因此斜率为 -1 的直线正是上文推导出的双曲线关系,也是测量点所追踪的。标记的 --max-num-seqs 上限为 512 的钉点位于所有测量点之上,说明在整个过程中批量大小由 KV 池而非调度器决定。在长上下文端,测量点与连续曲线之间的扩大差距正是取整导致的损失:在 256K 时可容纳 2.43 个请求,但实际上只能运行 2 个。
第二个非线性:预填充计算,相较于内存效应
上述双曲线批量容量崩溃是一种内存效应:固定的字节池被分配给上下文随之增长的请求。还有一个独立的开销驱动因素,容易与第一个混淆:预填充阶段的注意力计算随着上下文长度的增长速度快于线性。自注意力在输入的每对 token 之间计算得分,因此单次预填充通道的计算开销随上下文长度的平方增长,即 O(n²) 项,而非线性增长。这是自注意力定义的固有属性,而非测量结果或需要引用的声明;它直接源自该机制本身。
这两个非线性是独立的,本文并未用任何数字(无论是否虚构)来量化第二个非线性。内存效应是本次扫描围绕的核心,基于机制而非断言。预填充计算在每个请求中仅支付一次,随后在该请求产生的每个解码步骤中均摊,因此其对请求总成本的贡献会随着输出长度的增加而降低。它也是分块预填充所要分摊到调度步骤而非一次性阻塞支付的具体开销,而分块预填充在本文使用的引擎版本中默认开启。批量容量上限不具备这些特性:它会在请求的整个生命周期中持续起作用,且没有调度特性能够缓解它,因为它是对字节数的限制而非对时间的限制。这种不对称——一种成本被服务栈均摊并主动缓解,另一种是结构性且持续的——正是内存效应在服务规模下的每 token 成本曲线中显现的原因。这并不意味着计算项在绝对大小上可以忽略不计,本文也没有对其进行测量。请不要将结果章节视为证明预填充计算在任何方向上的依据。
要了解 KV cache 在何时不再是相对于模型权重的四舍五入误差,这是与上面非线性无关的另一个问题,Brenndoerfer 的 KV cache 内存计算(发表于 2026 年 1 月 7 日)给出了一个交叉点:此时 KV cache 大小等于模型权重大小,对应的 token 数为 26,702,在其原文中约四舍五入为 27K。该数字基于 LLaMA 7B、32 层、32 个 KV 头(标准多头注意力,未使用 GQA)、head_dim 128、FP16、批量大小 1,以及大约 13.0 GB 的权重得出,并且不适用于本文所用的模型:Ministral 3 14B 只有 8 个 KV 头(而非 32),层数为 40(而非 32),因此其交叉点需要独立推导,不能直接复用。同一来源还表明了这里需要关注的趋势:LLaMA 2 70B 使用 8 个 KV 头(而非 32),使得该交叉点推后到大约 427,000 tokens。每层 KV 头数越少,KV cache 随着权重增长的速度越慢,这正是本文模型也依赖的 GQA 效果。因此本文不会再次使用该 27K 数字。
方法论:此次扫描是如何测量的
环境免责声明。 本文中所有测量得到的数字均来源于单一配置:Ministral 3 14B Instruct,BF16 权重,运行在单个裸露的 NVIDIA H200 GPU Droplet 上,使用 vLLM v0.27.1 服务。不同的模型、量化方式、GPU 代号或服务栈版本都会得到不同的曲线。请将这里的数字视为此精确配置的可重现参考点,而非关于上下文长度和成本的一般定律。
成本等式
本文在每个上下文长度下应用的公式是:
effective_cpm = (hourly_rate / (total_tps * 3600 * utilization)) * 1,000,000
total_tps is 总计费吞吐量,即每秒输入令牌与输出令牌之和, 而不仅仅是输出吞吐量。这一区别很重要,因为 DigitalOcean 对 mistral-3-14B 的无服务器费用为每 100 万输入令牌 0.20 美元,每 100 万输出令牌也为 0.20 美元,费用对称。由于输入和输出的计费费率相同,总计费令牌是比较的正确基础,无需在两者之间进行加权。这种对称性在此处只需说明一次,随后在每个扫描点使用时无需重新推导。
本文从第一性原理出发自行定义分母,而非沿用本系列其他地方的交叉点数值。本系列的第一篇文章(专用 GPU 上不同流量配置的令牌经济学)对另一种模型采用仅解码吞吐量作为分母,因而得出了不同的交叉点。本文不再引用该交叉点,因为两篇文章在不同模型上使用了不同的分母。如果您需要该早期框架的方法,请直接阅读链接文章,而不要依赖此处引用的百分比。
前缀缓存已禁用:声明的范围限制
vLLM 的 V1 引擎默认启用自动前缀缓存(APC)。vLLM 自己的团队在 V1 发布时就曾说明这一点,理由是即便在 0% 缓存命中率时也几乎没有额外开销,因此应无条件启用(vLLM V1:vLLM 核心架构的重大升级, vLLM 博客,2025 年 1 月 27 日),并且 vLLM 当前的 自动前缀缓存文档 确认该默认设置仍然适用于我们这里使用的 v0.27.x 版本线,而不仅仅是最初引入它的 alpha 版本。自 v0.8.0 起,V1 已成为默认引擎,该版本发布于 2025 年 3 月。如果保持启用,APC 将在本文论点预测会出现崩溃的长上下文点处夸大测得的吞吐量,这会在曲线上最不利的位置植入一个人工制品。因此,本次扫描的主干运行使用 --no-enable-prefix-caching,并结合 vLLM 的 random 数据集生成器进行负载测试,以产生无共享前缀的唯一令牌序列,从而避免前缀重用对结果造成歧义。
这是一个范围边界,而非静默的标志选择:此篇测量的是仅针对上下文长度的无重用下限。缓存对该下限的救援效果在另文《提示缓存成本盈亏平衡伴读》中单独讨论,链接恰好位于范围边界的确切点。
调度器钉点:已根据启动日志验证,而非假设
--max-num-seqs 在每个扫描点均被固定为 512。在编写此方法论时,该钉点是对启动日志并发读数进行验证的预期,而非声称其高于池上限。验证现已完成:在 2K 时,启动日志报告 311.02 倍,测得的峰值并发在三次试验中均为 311,相对钉点 512。该钉点在 2K 或扫描中的任何更长点均未触发绑定。剩余空头为已达到 311 与可用 512 之间的差距,这就是本次扫描观测到的具体余量;它从未被接近。
如果在扫描中的任何上下文长度处 --max-num-seqs 钉点被触发(测得并发达到 512),则该扫描点必须明确报告为调度受限而非内存受限,并在结果部分突出标注,而不应悄然被合并到曲线中。调度受限的短上下文锚点将削弱整个前提——即 KV 池是本次扫描旨在测量的绑定约束。此情形在此未发生。
FP8 臂需要显式确认的后端
FlashAttention-2 作为 vLLM 的默认注意力后端,不支持 FP8 KV 缓存。对于 FP8 敏感度臂,会显式设置 VLLM_ATTENTION_BACKEND=FLASHINFER,并在启动日志中检查以确认 FlashInfer 确实处于活动状态,之后才会信任该运行中的任何 FP8 结果。
如果启动日志未确认 FlashInfer 在给定运行中处于活动状态,则该上下文长度的 FP8 臂无效。其将被报告为未运行,而不会使用可能已静默回退到不受支持配置的后端的数字进行报告。
VLLM_ATTENTION_BACKEND=FLASHINFER vllm serve mistralai/Ministral-3-14B-Instruct-2512 \
--served-model-name mistral-3-14B \
--max-model-len 131072 \
--max-num-seqs 512 \
--no-enable-prefix-caching \
--kv-cache-dtype fp8 \
--gpu-memory-utilization 0.90 \
--port 8000
grep -i "flashinfer" vllm_startup_fp8_131072.log
OutputYes
256K FP8 运行会独立重复相同的检查:Yes。两个上下文会被分别确认,因为在某一上下文长度下能正确加载的后端,并不一定在另一上下文长度下仍然保持活跃。
有关 KV cache 数据类型以外的量化权衡的背景信息,请参阅 如何通过 KV 缓存大幅降低 LLM 推理成本 中的量化章节。
KV 池大小从日志中读取,永不推导
每个上下文级别的预留 KV 缓存池会直接从 vLLM 启动日志中读取,即 GPU KV cache size: N tokens 和 Maximum concurrency for M tokens per request: X.XXx 两行,而不是通过假设的权重大小从 141 GB 中减去得到。导致这种计算不可靠有两点:其一,Pixtral 视觉塔即便在仅处理文本时也会占用 VRAM;其二,--gpu-memory-utilization 参数保留的是总 VRAM 的一个比例而非绝对值,因而可用于 KV 缓存的实际字节数依赖于这些参数,而这些参数本身最好直接从日志中获取,而不是做假设。
CONTEXTS=(2048 4096 8192 16384 32768 65536 131072 262144)
for ctx in "${CONTEXTS[@]}"; do
echo "=== context length: ${ctx} tokens ==="
vllm serve mistralai/Ministral-3-14B-Instruct-2512 \
--served-model-name mistral-3-14B \
--max-model-len "${ctx}" \
--max-num-seqs 512 \
--no-enable-prefix-caching \
--gpu-memory-utilization 0.90 \
--port 8000 > "vllm_startup_${ctx}.log" 2>&1 &
SERVER_PID=$!
sleep 30
grep -E "GPU KV cache size|Maximum concurrency" "vllm_startup_${ctx}.log"
kill "${SERVER_PID}"
wait "${SERVER_PID}" 2>/dev/null
done
OutputGPU KV cache size: 636,976 tokens
Maximum concurrency for {context} tokens per request: 311.02x
该启动读出还替代了大部分手动并发扫描的猜测工作:在每个上下文级别启动服务器,读取并发线,然后在该数值附近进行负载测试以确认,而不是盲目地开始负载测试。
请求形状保持输出长度恒定
输入长度在扫描过程中变化;输出长度在每个点上固定为 256 个令牌。同时变化两者会让输出令牌成本效应(即 输出令牌定价配套文章 的主题)泄漏到本文将其归因于输入上下文长度的曲线中。
预热、试验次数和方差是报告的,而不是假设的
每个扫描点在测量开始前会丢弃一个预热期,并报告方差而非单点估计:
- 预热。 在每个扫描点测量开始前会丢弃
10个请求。这一点很重要,因为在新启动的上下文长度下服务的第一个请求会产生 CUDA 图捕获和内存分配开销,而同一上下文长度下的后续请求不会产生这些开销;如果将它们计入测量窗口,会因与本文论点无关的原因导致吞吐量向下偏差。 - 试验。 每个扫描点运行
3次试验。报告的吞吐量和延迟数值是这三次试验的均值,每个表格的方差列中显示了试验间的标准差。 - 方差。 结果表中的每个吞吐量和延迟数值都会伴随方差度量、标准差或最小/最大范围一起报告,而不仅仅是一个裸�的单一数值。出于此原因,两张结果表都包含一个专门的方差列。
此次运行的 harness 和原始数据
本次 sweep 所使用的服务器启动命令、vllm bench serve 调用、规模规则、预热和试验协议以及指标抓取均在此方法论部分中完整说明。原始的每请求结果文件(--save-detailed JSON,包含 start_times、ttfts 和 itls)在每次被接受的试验中被保留,并用于结果中报告的并发和延迟数字。这些文件以及 sweep 编排代码和 vLLM 启动日志(每个 KV 池大小均从此读取)与本文一起发布在位于 上下文长度推理成本。可以通过上述命令和协议,或者直接使用保留的每请求数据来进行复现。
请求量根据预期持续时间而非固定数量进行缩放
在 256K 上下文中的请求完成所需时间显著长于 2K 上下文中的请求,这是因为 prefill 和 decode 都会随着上下文长度而线性增长。在每个 sweep 点使用相同的 --num-prompts 和 --request-rate 会导致每个点的统计功能极不均衡——在短上下文中采样更有效,在长上下文中采样较少,而这并非有人刻意如此安排。此 sweep 改为以每个 sweep 点的固定最小持续负载墙钟时间为目标,而不是固定请求数量,以使短上下文点(其请求完成速度远快于长上下文点)不会相对于长上下文点(每个请求所需时间显著更长)而被过度采样。--num-prompts 和 --request-rate 会根据上下文长度被选择以满足该持续时间下限,并且在 sweep 全程中不会保持不变。每个点实际使用的数值为:在所有点上 --request-rate inf;--num-prompts 的取值为:2K 2488,4K 1240,8K 616,16K 304,32K 152,64K 72,128K 50,256K 50。
vllm bench serve \
--backend vllm \
--model mistral-3-14B \
--host localhost \
--port 8000 \
--dataset-name random \
--random-input-len "${ctx}" \
--random-output-len 256 \
--num-prompts "${NUM_PROMPTS}" \
--request-rate inf \
--max-concurrency "${MAX_CONCURRENCY}"
NUM_PROMPTS 和 MAX_CONCURRENCY 根据上述调整规则和启动日志上限设置为每个上下文长度的值(例如在 2K 时:2488 条提示,并发数 311)。
捕获的抢占,而非推断
在每个扫描点,从 Prometheus 指标端点抓取 vllm:num_preemptions_total 和 vllm:kv_cache_usage_perc。此版本的指标名称是经过确认而非假设的,因为较旧的 vLLM 版本会发出 vllm:gpu_cache_usage_perc,而不是 V1 名称。
curl -s http://localhost:8000/metrics | grep -E "vllm:num_preemptions_total|vllm:kv_cache_usage_perc|vllm:gpu_cache_usage_perc"
Outputvllm:kv_cache_usage_perc{engine="0",model_name="mistral-3-14B"} 0.0
vllm:num_preemptions_total{engine="0",model_name="mistral-3-14B"} 0.0
model_name="mistral-3-14B" 在该输出中是启动时传入的 --served-model-name 值,而不是运行元数据表下方列出的 Hugging Face 检查点路径(mistralai/Ministral-3-14B-Instruct-2512-BF16);vLLM 使用服务名称来标记其自身的指标,而不是源仓库。
vllm:num_preemptions_total 在每次 sweep 点被抓取,而不是保留为脚注,而且它是一个计数器,因此试验结束时的抓取会捕获试验期间发生的所有抢占。它在整个过程中保持为零(见结果),这是关于此负载模式的真实结果。
vllm:kv_cache_usage_perc 也被一起抓取,但它是一个报告瞬时占用率的仪表盘,这些抓取是在试验结束时进行的,此时服务器已经空闲。因此它到处读取为 0.0,并且不包含关于 sweep 的任何信息。它未被报告为结果。在负载下的池占用率则是在结果部分通过保留的池大小和测得的并发度推导出来的,这是对同一量的更直接测量,且不依赖于抓取时机。任何想要获取该仪表盘本身并重现此 sweep 的人必须在运行期间轮询它,而不是在运行结束后。
作为机制证据的带有飞行中解码的预填充竞争
与前一节讨论的预填充计算非线性无关,长上下文预填充在两者共享一个批次时可能会导致飞行中解码工作停滞。Agrawal 等人,《通过 Sarathi-Serve 控制 LLM 推理中的吞吐量-延迟权衡》,USENIX OSDI 2024 (arXiv:2403.02310),图 9,该研究测量了 naive hybrid batching 相比仅解码批次,令 token 之间的时间增加了高达 28.3 倍,在四张 A100 上运行 LLaMA2-70B,且 token 预算为 512。此结果在此仅被引用为机制证据,以说明在长上下文下,当预填充和解码争夺同一批次时,TTFT 和 token 间延迟可能会急剧下降;这是因为所使用的模型和加速器不同,且该测量无法与本文后文报告的任何 TTFT 数字进行直接比较。
环境和运行元数据
| 字段 | 值 |
|---|---|
| vLLM 版本(主要方案) | 0.27.1 |
| 注意力后端(主要方案) | FLASH_ATTN |
--gpu-memory-utilization |
0.90 |
| BF16 内存占用 | 26.66 GiB (weights + non-torch) |
| 固定输出长度 | 256 |
| 每点的提示数 / 请求速率 | --request-rate inf; --num-prompts: 2K 2488, 4K 1240, 8K 616, 16K 304, 32K 152, 64K 72, 128K 50, 256K 50 |
| 每点丢弃的预热请求数 | 10 |
| 每个扫描点的试验次数 | 3 |
| 驱动 / CUDA 版本 | 580.173.02 / 13.0 |
| 基准测试运行日期 | 2026-08-26 |
结果:跨上下文长度的测量吞吐曲线
下表列出了在 BF16 主要方案的八个扫描点上捕获的所有指标,并采用前一节中描述的完全相同的方法在每个点上进行。每个吞吐量和延迟数值均根据上述预热和试验协议拥有各自的方差列。
容量与抢占
| 上下文 | 预留 KV 池(token 数) | 最大并发(对数) | 持续并发请求数 | 该并发下占用的 token 数 | 池占用率 | 抢占次数 | 波动情况(标准差 / 最小–最大) |
|---|---|---|---|---|---|---|---|
| 2K | 636,976 |
311.02x |
311 |
636,928 |
99.99% |
0 | 0(3 次试验均为 311/311/311,完全一致) |
| 4K | 636,976 |
155.51x |
155 |
634,880 |
99.67% |
0 | 0 (identical 155/155/155 across 3 trials) |
| 8K | 636,976 |
77.76x |
77 |
630,784 |
99.03% |
0 | 0 (identical 77/77/77 across 3 trials) |
| 16K | 636,976 |
38.88x |
38 |
622,592 |
97.74% |
0 | 0 (identical 38/38/38 across 3 trials) |
| 32K | 636,976 |
19.44x |
19 |
622,592 |
97.74% |
0 | 0 (identical 19/19/19 across 3 trials) |
| 64K | 636,976 |
9.72x |
9 |
589,824 |
92.60% |
0 | 0 (identical 9/9/9 across 3 trials) |
| 128K | 636,976 |
4.86x |
4 |
524,288 |
82.31% |
0 | 0 (identical 4/4/4 across 3 trials) |
| 256K | 636,976 |
2.43x |
2 |
524,288 |
82.31% |
0 | 0 (identical 2/2/2 across 3 trials) |
在全部八个主测点(2K 到 256K,每个测点各跑三次)以及两个 FP8 敏感度测点(128K 和 256K)上,试验结束时抓取 vllm:num_preemptions_total,结果每次都返回 0。这个计数器在多次抓取之间不会重置,因此试验结束时读数为零是真实的测量结果:无论在哪条分支、哪种上下文长度下,这种负载模式都从未触发过 vLLM 的抢占路径。
上面的表格中没有给出 kv_cache_usage_perc 仪表盘的数据。它是一个仪表盘,这些抓取是在试验结束时进行的,当时服务器已经空闲,因而每个时间点的读数都是 0.0,无法反映池在负载下的使用情况。方法论部分对此作了完整说明。
池占用率列取代了它,来源于两个已测得的数值:启动日志中的预留池大小,以及通过对每次试验原始每请求时序进行毫秒级精度区间扫 sweep 得到的并发数。在 2K 时,311 个并发请求每个持有 2,048 个 token,占用了 636,928 个可用 token(共 636,976 个),即池的 99.99%。池不仅仅是在短上下文端绑定批次大小,而是几乎被填满,仅剩 48 个 token 未被使用。
随着上下文长度的增加,占用率也会下降,从 2K 时的 99.99% 降至 256K 时的 82.31%,而这一下降正是此次扫 sweep 揭露的第二种机制。并发数是连续池‑上下文比率的 floor(向下取整),因此请求中不匹配的那部分会被搁置:已付费、已预留但不可用。被丢弃的量相当于一次完整请求的缓存,其大小会随上下文长度增长,因而搁置的比例也会随之增加。在 256K 时,有 112,688 个 token 的池处于空闲状态,因为只有 2 个请求能够运行,而理论上可容纳 2.43 个请求。因此,长上下文下的有效容量不如架构部分所描绘的平滑双曲线预测的那样好,额外的损失来源于整数量化而非 KV 增长。
--max-num-seqs 参数在 2K 时未触发上限:测得的峰值并发数为 311,而上限为 512,扫 sweep 中未曾达到 512。没有任何行被标记为受调度器限制。
吞吐量与延迟
| 上下文 | 总吞吐量(tok/s,输入+输出) | 仅输出吞吐量(tok/s) | TTFT p50 | TTFT p99 | 波动幅度(标准差 / 最小值–最大值) |
|---|---|---|---|---|---|
| 2K | 19089.8 |
2395.58 |
1093.1 |
22196.2 |
19089.8 ± 16.5; p50 ± 0.8; p99 ± 45.3 |
| 4K | 18812.3 |
1178.07 |
1112.3 |
24170.0 |
18812.3 ± 5.4; p50 ± 0.3; p99 ± 27.9 |
| 8K | 17933.2 |
560.96 |
1135.3 |
26074.7 |
17933.2 ± 6.5; p50 ± 0.0; p99 ± 14.0 |
| 16K | 16214.8 |
253.48 |
1685.6 |
28627.8 |
16214.8 ± 6.7; p50 ± 0.5; p99 ± 13.1 |
| 32K | 13929.6 |
108.85 |
3092.1 |
33751.9 |
13929.6 ± 12.9; p50 ± 2.1; p99 ± 62.0 |
| 64K | 11048.2 |
43.16 |
8205.3 |
41640.2 |
11048.2 ± 19.5; p50 ± 20.3; p99 ± 30.6 |
| 128K | 7988.2 |
15.6 |
22721.4 |
51946.5 |
7988.2 ± 2.8; p50 ± 5.1; p99 ± 56.7 |
| 256K | 4967.2 |
4.85 |
63648.1 |
92645.2 |
4967.2 ± 1.5; p50 ± 51.4; p99 ± 668.1 |
关于延迟的测量方法,以及如何分别解读 p50 和 p99,而不是把它们压缩成一个数字,请参阅为什么你的 vLLM p99 延迟在生产环境会爆表,以及分块预填充和调度如何解决和LLM 推理中的 P50 与 P99 延迟对比。在较长的上下文下,实测 TTFT p99 相对 p50 会有所上升,这与“方法论”一节所引用的预填充-解码争用机制相吻合。不过,这里真正有参考价值的是本文自己测得的 TTFT 数据,而不是 Sarathi-Serve 的数字——后者使用的毕竟是另一套模型和加速器。
主要图表
在 100% 利用率下测得的每 1M 总 token 的有效成本(实线),保持在 2K 时的数值($0.0650/1M)作为线性定价的参考(虚线),并标出 $0.20/1M 的无服务器费率以作比较。X 轴为 context length,采用 log₂ 刻度,范围从 2K 到 256K。测量曲线与该平直线之间的差距正是本文想要论证的地方:两条线分岐的点就是线性假设不再符合硬件实际行为的地方。
读取延迟与成本曲线
在两侧的每个点上,抢占计数始终保持为 0;由于该指标是计数器而非仪表,这个零是真实结果,而不是读取时的产物。因此,无法从容量表读取出驱逐 cliff:在 2K 时池填充至 99.99%,在 256K 时填充至 82.31%,且 vLLM 永不会抢占请求。由于方法论部分所述原因,kv_cache_usage_perc 仪表在此被排除,因此它不会以任何方式产生影响。本节想要进行的比较因此是在 TTFT p99 与每 token 的有效成本之间,二者均来源于本文中的填充表格。
将“急剧上升”定义为每个序列中连续步骤的最大百分比跳变。根据此定义,两个信号在同一过渡点达到峰值:
| 步骤 | TTFT p99 跳变 | 每 1M 有效成本跳变(@100% 利用率) |
|---|---|---|
| 2K→4K | 8.9% | 1.5% |
| 4K→8K | 7.9% | 4.9% |
| 8K→16K | 9.8% | 10.6% |
| 16K→32K | 17.9% | 16.4% |
| 32K→64K | 23.4% | 26.1% |
| 64K→128K | 24.8% | 38.3% |
| 128K→256K | 78.3% | 60.8% |
两条曲线在中段逐步上升,然后在 128K 到 256K 之间跨出它们各自的最大单步。在 64K 处,p99 已实现其从 2K 到 256K 总体上升的 27.6%,而成本实现了 25.6%;到 128K 时,这两个比例分别为 42.2% 和 48.9%。根据此定义,任一方信号并未明显领先另一方。即便在同一点将 p99 与 p50 进行对照,也无法挽救领先/滞后的叙事:p99/p50 比率从约 20×(在 2K)下降至 1.5×(在 256K),这是因为在长上下文末尾,p50 的上升速度实际上快于 p99。
此扫描所示的是同步变化,而非在成本转折之前出现的早期延迟警告。仅关注成本仪表盘的操作员在此数据集中不会错过另一个更早的悬崖,因为最剧烈的延迟变化和最剧烈的成本变化发生在同一步骤。有价值的操作读取范围更窄:在 TTFT 和成本共同上升期间,抢占始终保持沉默,且池子在整个过程中始终保持在 82% 到 100% 的满载状态之间,因此零抢占计数并不能说明长上下文负载便宜、延迟稳定或具备缓存余量。
256K点
256K 仍然是上述连续曲线的一部分。它之所以留在该曲线上,是因为在此点测得的并发度仍然描述了与扫描其余部分相同的批处理容量机制。
在 BF16 头条臂上,256K 的日志验证并发度为 2,三次试验完全一致,直接从 vLLM 启动日志的并发行读取,并通过对每次试验原始每请求时序数据进行毫秒级精度扫描独立验证,而非取自 vLLM 自身的聚合并发字段。并发度为 2 已经很低,以至于值得质疑这是否仍在测量批处理容量。答案是:仍然是在测量批处理容量。如果只能容纳单个请求(并发度为 1),那就属于另一种情况:此时没有可测量的批次,也没有并发流之间的抢占,也没有调度竞争,因而此扫描所描述的批处理容量机制就不再适用。两个并发请求仍然会争夺同一固定的 KV 池,并且仍然表现出本次扫描旨在刻画的批处理容量行为,这一点正好对应于架构章节推导出的双曲线崩溃已经发展到最远的点。该测量本身也很稳定:在此点上每次试验完成 50 个请求,零失败请求,且三次试验都得到完全相同的并发值,这与扫描其他七个点表现出的稳定性一致。如果把 256K 拎出来单独成节,就会移除使曲线论证成立的端点。文章所测量的机制是并发度从 2K 时的 311 下降到 256K 时的 2,这一趋势在曲线最远端可见。FP8 KV 敏感度臂自身的 256K 并发数更高,将在下文独立章节中报告,且不会改变此结论——因为该臂从未属于本节所讨论的“连续曲线”。
FP8 KV 缓存敏感度臂
FP8 臂仅在 128K 和 256K 两种上下文长度时报告,这是因为在这两种长度下,FP8 每个 token 的占用空间减半(80 KiB 对比 160 KiB)最有可能显著改变并发上限。每种上下文长度都拥有自己独立的槽位集合。
| 上下文长度 | FlashInfer 已确认激活 | 保留的 KV 池及最大并发度 | 总吞吐量 (tok/s) |
|---|---|---|---|
| 128K | Yes |
1,273,968 tokens / 9.72x boot; true concurrency 9 |
9436.6 |
| 256K | Yes |
1,273,968 tokens / 4.86x boot; true concurrency 4 |
6064.7 |
如果启动日志未确认在给定上下文长度下 FlashInfer 处于活动状态,则根据上述方法论规则,该行将被报告为未运行,而不是填入数字。
上下文长度对每令牌有效成本的影响
应用方法论部分的成本身份,effective_cpm = (hourly_rate / (total_tps * 3600 * utilization)) * 1,000,000,在 DigitalOcean H200 GPU Droplet 按需费率为每小时 4.47 美元(来源:GPU Droplet 定价,最后验证于 2026 年 8 月 25 日),可得到每种上下文长度下的每百万总令牌有效成本。将该数字与每种上下文长度下的每 1M 对称无服务器费率 0.20 美元进行比较,即可得到专用 GPU 必须维持的利用率以实现盈亏平衡。
在 $4.47/hr、utilization = 1.0(100%)的情况下,使用结果表中的已填总吞吐量均值得出:
- 2K:
(4.47 / (19089.8 × 3600 × 1.0)) × 1,000,000 = 0.0650434613→ $0.0650/1M; 盈亏平衡利用率 =0.0650434613 / 0.20 = 0.325217(32.52%) - 4K:
(4.47 / (18812.3 × 3600 × 1.0)) × 1,000,000 = 0.0660029165→ $0.0660/1M; 盈亏平衡利用率 =0.0660029165 / 0.20 = 0.330015(33.00%) - 8K:
(4.47 / (17933.2 × 3600 × 1.0)) × 1,000,000 = 0.0692384330→ $0.0692/1M; 盈亏平衡利用率 =0.0692384330 / 0.20 = 0.346192(34.62%) - 16K:
(4.47 / (16214.8 × 3600 × 1.0)) × 1,000,000 = 0.0765761321→ $0.0766/1M; 盈亏平衡利用率 =0.0765761321 / 0.20 = 0.382881(38.29%) - 32K:
(4.47 / (13929.6 × 3600 × 1.0)) × 1,000,000 = 0.0891387166→ $0.0891/1M; 盈亏平衡利用率 =0.0891387166 / 0.20 = 0.445694(44.57%) - 64K:
(4.- 128K:
(4.47 / (7988.2 × 3600 × 1.0)) × 1,000,000 = 0.1554376038→ $0.1554/1M; 盈亏平衡利用率 =0.1554376038 / 0.20 = 0.777188(77.72%)- 256K:
(4.47 / (4967.2 × 3600 × 1.0)) × 1,000,000 = 0.2499731572→ $0.2500/1M; 盈亏平衡利用率 =0.2499731572 / 0.20 = 1.249866(124.99%) - 128K:
盈亏平衡利用率是 effective_cpm(100%) / 0.20。在 100% 利用率时,有效成本首次超过 $0.20/1M 出现在 256K($0.2500 > $0.20);这也是唯一一个盈亏平衡利用率超过 100% 的点(124.99%)。测得的 256K/2K 成本比为 3.84x,以 2K 为基准,以匹配上图中的平坦参考线。它是根据上面推导列表中的未四舍五入数字计算得出的,0.2499731572 / 0.0650434613 = 3.8432,这与总吞吐量比率 19089.8 / 4967.2 = 3.8432 完全相同。将四舍五入后的显示数字相除($0.2500 / $0.0650)得到 3.85,因此该数字来源于未四舍五入的数值。
| 上下文 | 每 1M 总 token 的有效成本(100% 利用率) | 与 $0.20/1M 无服务器的盈亏平衡利用率 |
|---|---|---|
| 2K | $0.0650 |
32.52% |
| 4K | $0.0660 |
33.00% |
| 8K | $0.0692 |
34.62% |
| 16K | $0.0766 |
38.29% |
| 32K | $0.0891 |
44.57% |
| 64K | $0.1124 |
56.19% |
| 128K | $0.1554 |
77.72% |
| 256K | $0.2500 |
124.99% |
以下两个数字来源于对上述已填充行应用相同的公式:
- 256K: 有效成本在 100% 利用率时首次超过 $0.20/1M 的最小上下文长度($0.2500 > $0.20;盈亏平衡利用率 124.99% > 100%)
- 3.84x: 在 256K 与 2K 的有效每 token 成本的测量比率,来源于未四舍五入的数字(
0.2499731572 / 0.0650434613),等于总吞吐量比率19089.8 / 4967.2;这不是架构章节中公式推导得到的构造。
经济因素何时会改变您的架构决策
本文要解答的运营商问题是:在什么具体的上下文长度下,专用的 H200 不再是服务 Ministral 3 14B 流量的更经济方式,以及一旦超过该阈值应如何应对。答案是 256K,直接取自上一节的盈亏平衡列,而不仅仅是根据曲线形状估算的。以下四点按运营商应实际采用的顺序给出。
1. 首先始终压缩上下文
在进行路由决策或硬件变更之前,第一个杠杆是减少请求实际需要的上下文量。与其把整个文档塞进提示词中进行上下文填充,不如先尝试压缩和检索,因为每减少一个请求上下文的 token 都能直接恢复批处理槽位:架构部分中的双曲关系意味着较短的上下文在预填充时每个 token 的成本更低,并且在同一固定 KV 池中能够容纳更多的请求,这正是本文 Results 部分测量曲线实际获得其形状的地方。检索增强生成(RAG)——仅检索请求所需的段落,而不是将整个源文档塞进上下文——是这一纪律在实践中的正确示例。本文并未为该恢复附加一个具体的“每节省 N 千个 token”数值,因为从未验证过这样的数值;机制本身是主张,而测量曲线则让您能够在自己的运营点上精确评估给定上下文减少量的价值。
2. 按上下文长度路由,而不仅仅按流量量
如果有相当比例的流量经常超过上述的盈亏平衡上下文长度,则应将该流量路由到无服务器而非专用硬件。原因是引言中提到的结构性观点应用于两个已公布的数字。DigitalOcean 在 Serverless Inference 上对 mistral-3-14B 按固定价格收取每 100 万 token 0.20 美元,费用不随上下文长度变化;而本文测得的曲线表明,在专用 H200 上你的每 token 有效成本会随上下文长度上升。这两个事实不相交:一种工具随上下文长度保持平坦,另一种则不然。超过盈亏平衡点后,平坦的工具 simplesmente 就是对你计费更便宜的选择,这一点无论服务提供商实际的服务成本如何都保持不变。做出此决定不需要了解提供商的经济情况,只需知道你面对的是哪两种费率中的哪一种。
3. 重新检查 FP8 KV 缓存臂,在假设专用方案在长上下文中失效之前
结果部分中 FP8 在 128K 和 256K 下的敏感性结果要么将盈亏平衡点向外移动,要么不会。这是本文自身扫描所设计给出的经验答案,而不是一种普遍主张,即量化 KV 缓存总能在每种模型和加速器上救回长上下文的经济性。
4. 将前缀和提示缓存视为独立的杠杆,而非此测量的替代方案
本文的头条数字刻意测量了无复用基线。如果生产流量具有高前缀复用,则 提示缓存配套文章 将单独说明该复用可以将本文的盈亏平衡线移动多少以及移动的幅度。
此测量量化的两个回调
混合专家推理成本文章 警告说,硬件预算应围绕缓存项以及模型权重进行。本文自身测得的数字正是对单个稠密模型的该尺寸规则的量化:决定批处理容量如何随上下文长度崩溃的是 KV 缓存池,而不是权重占用,这就是为什么本文从启动日志中读取池大小,而不是仅凭权重来推断。
DigitalOcean 自己的 推理引擎更新说明 记录了长上下文高效的模型架构、压缩注意力变体以及减小的 KV 足迹,作为正在进行的开发。这些正是对本文在服务端测量的经济学的模型端响应:如果未来架构以 FP8 KV 缓存在此所做的方式缩减每 token 的字节数,则相同的双曲线容量机制仍然适用,只是 POOL_BYTES-to-footprint 比率更大,盈亏平衡的上下文长度相应地向外移动。
这并不意味着所有模型在所有加速器上的盈亏平衡点都会与 H200 上的 Ministral 3 14B 在相同的上下文长度出现。该机制——固定 KV 池和每 token 的线性成本——是架构层面的且具有普遍性;而 256K 中的具体数字则不具备这种普遍性,只有在方法论部分重新针对自己的模型和卡运行扫 sweep,才能得到自己的数字。
关于此主题的常见问题?
上下文长度会线性影响推理成本吗?
在专用硬件上不是这样。无服务器的每 token 费率通常是固定或阶梯式的,看起来是线性或分段线性的,但按小时计费的专用 GPU 上,每 token 的 KV 缓存成本是线性的,而能够放入固定 KV 缓存池的批处理容量在上下文增长时会呈双曲线下降。这意味着即使底层每 token 的缓存成本不变,有效的每 token 成本也会随上下文长度上升,因为在更长的上下文下,同一 GPU‑小时内能容纳的请求变少了。
如果每个 token 的 KV 缓存是常量,为什么批处理容量会随着上下文长度增长而下降?
因为 KV 缓存池本身是 GPU 上固定字节数,而不是随着需求增长而增长的东西。每个请求的 KV 足迹是 context_length × bytes_per_token,因此在上下文更长时,每个请求占据该固定池的更大份额,因而能够并发处理的请求数量减少。上下文长度与能够并发处理的请求数量之间的关系是双曲线,而不是直线,即使该公式内的每 token 成本本身是线性的。
如果无服务器定价是固定的,那是不是意味着长上下文的定价是公平的?
这并不是说价格会跟踪成本。固定的每 token 费率对 2K 上下文请求中的一个 token 和 256K 上下文请求中的一个 token 收取相同的费用,而本文的测量表明,在这两个 token 背后的服务成本在专用硬件上并不相同。单一的固定费率无法表达这种差异,因此它实际上是根据请求的形状相互定价。长上下文的高级别套餐是供应商重新引入这种区别的方式,而一些供应商收取费用而另一些则不收取费用正是本文引言中所讨论的分歧的起点。就您自身的决策而言,有用的后果更为明确,且无需猜测任何人的成本:如果您按与上下文长度无关的固定费率计费,您的账单不会像专用 GPU 的每 token 有效成本那样随上下文增长而上升。
Ministral 3 14B 使用滑动窗口注意力吗?
不。sliding_window 是 null 在模型的 config.json 中,并且所有 40 层均使用全注意力。这与较旧的 Ministral-8B-Instruct-2410 有显著区别,后者以 1:3 的比例交错全注意力层和滑动窗口层。滑动窗口注意力会将 KV 缓存的增长限制在窗口大小;由于此模型未使用它,KV 缓存会在其完整的 262,144-token 支持窗口内随上下文线性增长。
Ministral 3 14B 每个 token 需要多少 KV 缓存内存?
在 BF16 下每个 token 为 163,840 字节(160 KiB),在 FP8 下每个 token 为 81,920 字节(80 KiB),源自 2 × 40 layers × 8 KV heads × 128 head_dim × bytes_per_element。这些是从模型自身配置文件得出的架构事实,而非来自基准测试。它们是模型的固定属性,不依赖于服务硬件,尽管实际上能够容纳的 token 数量的缓存会受到特定 GPU 的限制。
KV 缓存内存效应是导致长上下文服务成本增加的唯一原因吗?
不是。存在第二个独立的成本驱动因素:在 prefill 阶段的注意力计算随上下文长度的平方增长,而非线性增长,这是因为自注意力会对输入中的每一对 token 进行评分。本文未用实际测量数据量化该效应。在操作层面,本文的分析围绕内存效应而非计算效应展开,这是因为两者之间存在不对称:prefill 计算会在请求的 decode 步骤中均摊,而 chunked prefill(在此使用的引擎中默认开启)正是为了将其分散到调度步骤中;而批量容量上限则会在请求的整个生命周期中持续起作用,且没有等价的缓解手段。这并不是说计算项可以忽略不计;本文也没有以任何方式测量它。
如果长上下文成本过高,我应该首先做什么?
在调整硬件或路由之前,先降低上下文长度。通过检索和压缩——只取请求所需的片段,而不把整个文档塞进提示词——可以直接恢复批处理容量,因为较短的上下文占用的固定 KV 缓存池比例更小,从而能够让更多请求并发运行。按上下文长度进行路由以及重新检查量化的 KV 缓存,是接下来的两个杠杆,按此顺序在“经济因素如何决定架构决策”一节中有所介绍。
本文的测量适用于哪些硬件和模型?
单个裸露的 NVIDIA H200 GPU Droplet(141 GB 显存),运行 BF16 精度下的 Ministral 3 14B Instruct,使用 vLLM v0.27.1。测得的曲线不会直接迁移到其他模型、其他 GPU 代际或多 GPU 设置;虽然固定 KV 池与每 token 线性增长的冲突这一架构机制具有普适性,但具体的吞吐量和成本数字则不具备这种迁移性。
自动前缀缓存会改变此结果吗?
本文的核心测量故意禁用自动前缀缓存(--no-enable-prefix-caching),并使用唯一且不重复的提示词,以确保缓存带来的吞吐量提升不会掩盖本文所隔离的上下文长度效应。在实际生产流量中,若出现重复的前缀,则在长上下文情况下所看到的实际惩罚会小于本文无重复基准所展示的水平。这种救援效应及其大小,在提示词缓存盈亏平衡伴读文章中有所阐述。
DigitalOcean 是否公布了此模型的最大输出 token 限制?
不。DigitalOcean 在其定价页面上未公布 mistral-3-14B 的最大输出 token 数值,本文也没有对此进行估计。
结论
成本计算器将上下文长度视为直线来定价,这是因为费率表的写法就是这样:输入 token 乘以费率,输出 token 乘以费率,而 token 数量的十倍看起来就像成本的十倍。本文在一块专用 GPU 上测量了该费率表下实际发生的情况:Ministral 3 14B Instruct 每个 token 的 KV 缓存确实是线性的,BF16 下为 160 KiB,FP8 下为 80 KiB,这一数据直接来源于模型自身的 config.json。非线性的部分在于这些按 token 分配的量实际上能放进 GPU 固定 KV 缓存池中的数量,而该容量会随着上下文增长呈双曲线下降,这就是为什么在专用硬件上,即使每个 token 的缓存计算未变,有效的每 token 成本仍会随上下文长度上升。其次,还存在一个与内存效应独立的二次非线性——预填充计算的平方增长。本文的测量聚焦在内存效应上,正是因为它在请求的整个生命周期内持续绑定,且没有调度器可以缓解;而预填充计算则会在解码步骤中均摊,正是分块预填充所要分散的对象。这种不对称性,而非认为计算可以忽略不计,正是本文所测得曲线为内存效应曲线的原因。
相同的机制解释了为什么固定的每 token 费率和测量得到的服务成本曲线不可能同时正确地描述长上下文的成本。一个不随上下文长度变化的费率无法跟踪确实随长度变化的成本,于是它只能把不同请求的形状相互比较定价,而长上下文的溢价层级正是供应商重新引入这种差异的方式。文中给出的盈亏平衡上下文长度——在这一点,专用的 H200 不再是服务 Ministral 3 14B 流量的更便宜方式——仅适用于在整个扫描范围内保持固定费率的计费情形。如果 DigitalOcean 对此模型的无服务器费率像 OpenAI 在同一目录页上对 GPT‑5.x 系列所做的那样,在某个上下文阈值处出现阶梯式调整,那么这个盈亏平衡点就必须按照阶梯费率重新计算,而不是原来的固定费率。
结果部分所示的测量曲线及其所暗示的盈亏平衡上下文长度,仅适用于在单张 H200 上运行 vLLM v0.27.1、且有意关闭前缀缓存的 Ministral 3 14B Instruct 模型。这并不意味着所有模型在所有加速器上都会在同一点交叉;市场本身的分歧——OpenAI 和 Google 仍在为长上下文设置阶梯费用,而 Anthropic 的当前模型则取消了这种阶梯——表明没有一个放之四海而皆准的答案。真正具有普遍性的是该机制,而理解这一机制的最佳方式是把它看作关于密度而非数量的陈述:在费率表中,上下文长度被当作数量来定价(token 数乘以费率),但在硬件上它表现为密度,决定了在同一时刻有多少请求共享固定的 GPU 内存池,正是这种密度,而不是费率表,才真正决定了长上下文的成本。
本文是推理经济学系列文章的第五篇,包含以下文章:大规模长上下文推理:隐藏的基础设施成本(这是直接的前置文章,在引言部分上面有链接),专用 GPU 上不同流量配置的 Token 经济学,为什么突发的推理流量会打破专用 GPU 的计算模型,和输出 Token 定价的隐藏成本。相关阅读:KV 缓存如何大幅降低大规模 LLM 推理成本,混合专家推理成本,LLM 推理优化,如何为 vLLM 推理选择合适的 GPU,以及 DigitalOcean 自己的推理引擎更新说明和LLM 推理基准测试博客。
参考文献
- DigitalOcean, 推理定价, 最后验证于 2026年8月24日
- DigitalOcean, Droplet 定价, 最后验证于 2026年8月25日
- Google, Gemini 开发者 API 定价, 标准层级, 2026年8月27日获取
- Hugging Face,
mistralai/Ministral-3-14B-Instruct-2512config.json, 主分支, 提交1861cbb11d2a33d8107d82941d5662dedc5b04d8, 阅读于 2026年8月20日 - vLLM, 文档主页
- vLLM, 发行说明 (v0.27.1, 截至 2026年8月11日的当前稳定版)
- vLLM 博客, vLLM V1:vLLM 核心架构的重大升级, 2025年1月27日
- vLLM, 自动前缀缓存 (v0.27.x 系列默认启用行为)
- vLLM, v0.8.0 发行说明 (V1 引擎于 2025 年 3 月成为默认)
- Agrawal et al., “使用 Sarathi-Serve 调节 LLM 推理中的吞吐量-延迟权衡,” USENIX OSDI 2024 (arXiv:2403.02310)
- Brenndoerfer, LLM 推理的 KV 缓存内存计算, 2026 年 1 月 7 日发布
- DigitalOcean Community, 大规模长上下文推理:隐藏的基础设施成本
- DigitalOcean Community, 专用 GPU 上不同流量配置的 Token 经济学
- DigitalOcean Community, 为什么突发推理流量会打破专用 GPU 的计算
- DigitalOcean Community, 输出 Token 定价的隐藏成本
- DigitalOcean Community, KV 缓存如何在大规模场景下大幅降低 LLM 推理成本
- DigitalOcean Community, 混合专家推理成本
- DigitalOcean Community, LLM 推理优化
- DigitalOcean Community, 如何为 vLLM 推理选择合适的 GPU
- DigitalOcean Community, 为什么您的 vLLM p99 延迟在生产环境中会激增,以及分块预填充和调度如何修复
- DigitalOcean Community, LLM 推理中的 P50 与 P99 延迟对比
- DigitalOcean Community, 提示缓存成本盈亏平衡点
- DigitalOcean Blog, 推理引擎的最新动态
- DigitalOcean Blog, LLM 推理基准测试
- 基准测试工具和原始参数扫描数据, 上下文长度推理成本参数扫描