KV cache 与 prompt cache 有什么区别?
KV cache 是每个请求都要占用的 RAM 或 VRAM,可能导致模型加载失败;prompt cache 只影响延迟和费用,未命中时按全价计费。
KV cache 与 prompt cache:简短结论
KV cache 和服务提供商的 prompt cache 只共享一个词,几乎没有其他共同点。KV cache 是每个请求的工作内存。在单个请求的整个生命周期内,它都驻留在服务器的 RAM 或 VRAM 中,并且会随上下文长度和并发请求数增加而增长。服务提供商的 prompt cache 是一种计费和延迟优化功能。系统会将提示词中稳定不变的前缀存储在服务提供商的服务器上;再次发送该前缀时,可按折扣价格计费。
前者是您通过硬件购买的内存。后者是由其他方持有、并向您收取使用费用的内存。
实际差异比定义更重要。KV cache 可能耗尽;耗尽后,模型无法加载,或者请求会被拒绝。prompt cache 不会耗尽。您只能无法命中缓存,此时系统会静默地按全价计费。
KV cache 保存什么,以及它存在的原因
生成第 500 个 token 的 transformer 必须关注前面的 499 个 token。对于这些 token 中的每一个,每一层都需要一个 key 向量和一个 value 向量。如果每生成一个新 token 都重新计算全部向量,生成开销会随序列长度的平方增长,因此运行时会将它们保留下来。这个存储区就是 KV cache(key/value cache)。
它是每个请求独有的状态,因为它基于该请求的确切 token 序列构建。发送不同提示词的两个用户不能共享此缓存,除非运行时启用了 prefix caching;这是后文介绍的另一项功能。
服务过程分为两个阶段。Prefill 读取完整提示词并填充缓存,受计算能力限制。Decode 一次生成一个 token,并将其追加到缓存,受内存带宽限制。因此,当您在自己的设备上测量每秒生成的 token 数时,提示词处理和 token 生成会报告不同的速度。
KV 缓存占用多少内存?
不要去查厂商表格。对于任何模型,都可以通过以下算式重新计算缓存大小:
bytes per token = 2 * layers * kv_heads * head_dim * bytes per element其中的 2 代表 key 和 value。其他数字都来自模型的 config.json,可在模型的 Hugging Face 页面上查看。
以 Llama 3.1 8B 为例。其配置列出 num_hidden_layers 为 32,num_key_value_heads 为 8。hidden_size 为 4096,分布到 32 个注意力头后,每个注意力头的维度为 128。在 f16 中,每个元素占用 2 字节:
2 * 32 * 8 * 128 * 2 = 131072 bytes = 128 KiB per token将结果乘以请求使用的上下文长度,再乘以同时运行的请求数。
此图表背后的数据
[
{
"label": "2k context",
"one_request_gib": 0.25,
"four_requests_gib": 1
},
{
"label": "8k context",
"one_request_gib": 1,
"four_requests_gib": 4
},
{
"label": "32k context",
"one_request_gib": 4,
"four_requests_gib": 16
},
{
"label": "128k context",
"one_request_gib": 16,
"four_requests_gib": 64
}
]上下文长度为 8k 时,缓存占用 1 GiB。上下文长度为 32k 时,缓存占用 4 GiB,与 4-bit 权重本身处于同一数量级。使用模型完整的 128k 上下文时,单个请求占用 16 GiB;如果 4 个请求都填满上下文,则占用 64 GiB。权重没有变化,变化的只有缓存。
分组查询注意力(GQA)显著降低了这个数值。Llama 3.1 8B 有 8 个 key/value 头为 32 个 query 头提供服务,因此每 4 个 query 头共享一组已存储的 key/value。对于 num_key_value_heads 等于 num_attention_heads 的模型,在参数量相同的情况下,缓存占用量会达到 4 倍。在假设两个 8B 模型的服务成本相同之前,先检查这个字段。
为什么在 2k 下运行正常的模型拒绝在 32k 下加载
因为运行时会在模型加载时预留 KV 缓存。缓存大小取决于您配置的上下文长度,而不是实际发送的提示词长度。Ollama 的默认值已不再是单一数值。截至 2026 年 10 月,其上下文长度文档按 VRAM 设置默认值:显存小于 24 GiB 的机器为 4k,24 至 48 GiB 为 32k,48 GiB 或更高为 256k;云端模型则默认使用其最大值。仅使用 CPU 的 VPS 或小型 GPU 默认从 4k 开始。将其提高到 32k 后,在收到第一个 token 之前,您就要求额外分配 4 GiB。对于 24 GiB 显卡,32k 已经是默认值,因此无论您是否主动配置,运行时都会进行这项预留。
OLLAMA_CONTEXT_LENGTH=32768 ollama serve在交互式提示符中为每个会话设置相同的值:
ollama run llama3.1:8b
/set parameter num_ctx 32768不同软件栈中的失败表现不同。vLLM 会在启动时检查内存计算结果,并拒绝运行:
ValueError: To serve at least one request with the model's max seq len (131072), (16.0 GiB KV cache is needed, which is larger than the available KV cache memory (9.56 GiB). Based on the available memory, the estimated maximum model length is 78336. Try increasing `gpu_memory_utilization` (which also controls CPU memory on the CPU backend) or decreasing `max_model_len` when initializing the engine. See https://docs.vllm.ai/en/latest/configuration/conserving_memory/ for more details.在运行 Ollama 或 llama.cpp 的仅 CPU VPS 上,这项分配使用普通系统内存,内存不足可能不会在启动时被发现。此时内核的内存不足终止程序会终止该进程,并将证据写入内核环形缓冲区:
dmesg -T | grep -i "killed process"如果某一行列出了您的推理服务进程,说明该主机承诺提供的内存超过了实际可用内存。解决方法是减小上下文长度,而不是增大交换文件:分页到磁盘的 KV 缓存会在每个生成的 token 时读取,因此生成速度会降到无法实际使用的程度。如何选择合理的数值,请参阅我们的 Ollama num_ctx 和上下文长度指南。
并发如何影响数字
每个正在处理的请求都需要自己的 KV 缓存。这是许多容量规划遗漏的关键点。4 个用户各自持有 32k 上下文时,彼此合计需要 16 GiB,此外还要为模型权重预留内存。
不同运行时对此的处理方式并不相同。Ollama 和 llama.cpp 在加载模型时会预留您指定的上下文容量,因此无论是否实际使用,这部分内存都会被提交。vLLM 会将内存池拆分为固定大小的块,并随着请求增长逐块分配,因此一个 500-token 的请求只会占用相当于 500 个 token 的空间。无论采用哪种方式,内存池的容量都是有限的。内存池满后,新请求会排队,而不是立即执行。排队对响应时间的影响见自托管 LLM 可服务多少个并发用户。
缩小 KV 缓存的 4 种方法
- 降低上下文长度。这是影响最大、通常成本最低的调整项。大多数聊天工作负载都不会接近 32k。
- 对缓存本身进行量化。Ollama 的
OLLAMA_KV_CACHE_TYPE默认为f16,也接受q8_0(占用的内存约为一半)和q4_0(占用的内存约为四分之一)。llama.cpp 对应的选项是-ctk q8_0和-ctv q8_0。 - 选择键/值头数量更少或层数更少的模型。下载 40 GB 的权重前,先阅读
config.json。 - 同时处理更少的请求,将其余请求排队。
在 q4_0 下,Llama 3.1 8B 每个 token 的占用量会从 128 KiB 降至约 32 KiB,因此 32k 上下文的成本约为 1 GiB,而不是 4 GiB。这种节省并非没有代价。键和值会以更低的精度存储,因此在保留该设置前,请使用您自己的提示词比较输出结果。
Provider 提示词缓存实际带来的收益
Provider 提示词缓存是另一种产品,其计费单位也不同。您需要标记一个稳定的前缀,由 Provider 保存该前缀。之后,只要请求重复使用完全相同的前缀,就会按折扣价格计费,而不是按完整输入价格计费。
截至 2026 年 10 月,Anthropic 发布的倍率如下:5-minute 缓存写入费用是基础输入 token 价格的 1.25 倍。1-hour 写入费用是 2 倍,缓存读取费用在大多数模型上是 0.1 倍。最新模型的读取价格更低:Claude Opus 5.5 和 Sonnet 5.5 为 0.05 倍,Claude Fable 5.1 和 Mythos 5.1 为 0.025 倍。以 20,000-token 的系统提示词代入标准倍率后,收益差异就很明显。
此图表背后的数据
[
{
"label": "No caching, every call",
"billed_token_equivalents": "20,000"
},
{
"label": "First call, 5 minute cache write",
"billed_token_equivalents": "25,000"
},
{
"label": "First call, 1 hour cache write",
"billed_token_equivalents": "40,000"
},
{
"label": "Every later call, cache hit",
"billed_token_equivalents": "2,000"
}
]按算术计算即可。5-minute 写入溢价相当于首次调用额外支付 5,000 个 token:25,000,而未使用缓存直接发送该提示词需要支付 20,000。在缓存窗口内的后续调用只计费 2,000,而不是 20,000,每次可节省 18,000 个 token。因此,从第二次调用开始,5-minute 缓存就已经节省成本。
1-hour 缓存的收益条件不同。写入时计费 40,000,相当于额外支付 20,000 个 token,因此在 1-hour 内需要命中两次后才开始节省成本。这取决于您的流量模式,而不是模型本身。完整计算方式以及如何选择缓存窗口,请参阅 Claude 提示词缓存的盈亏平衡计算。
两个细节决定请求是否能命中缓存。第一,低于模型最小长度的前缀不会被缓存,而且不会返回错误:截至 2026 年 10 月,文档规定 Claude Opus 5、Opus 5.5 和 Sonnet 5.5 的最小长度为 512 tokens,Claude Sonnet 5 的最小长度为 1,024 tokens。更短的请求会按正常方式处理。第二,缓存生命周期从写入或读取该条目的请求开始时计算,每次读取都会在不增加费用的情况下刷新生命周期。因此,高流量 endpoint 可以让 5-minute 缓存无限期保持有效。每 10 分钟调用一次的 endpoint 则每次都支付写入溢价,始终无法获得缓存读取收益。
请检查响应,不要凭推测判断。usage 对象会报告 cache_creation_input_tokens 和 cache_read_input_tokens。如果每次调用的读取计数都是 0,说明您一直在支付写入费用,却没有获得任何缓存读取收益。
两种缓存的交汇点
长系统提示词是两种缓存的交汇点,而且会同时从两侧产生开销。
在本地,20,000-token 的系统提示词在采用 f16 的 Llama 3.1 8B 服务器上约占用 2.4 GiB 的 KV 缓存;每个包含该提示词的并发请求都会单独占用这些缓存。在远程端,相同前缀只需写入缓存一次,之后每次调用的输入成本为 0.1 倍;在最新模型上可能更低。本地开销随用户数增长。远程开销随流量增长,并会在空闲期间重置。
本地有一项功能看起来像提供商的提示词缓存,因此经常与后者混淆:前缀缓存。vLLM 文档将自动前缀缓存描述为缓存“现有请求的 KV 缓存,使新请求在与某个现有请求共享相同前缀时可以直接复用该 KV 缓存”。当前版本的 vLLM 默认启用此功能。llama.cpp 服务器默认会为每个 slot 保留提示词缓存,而 --cache-reuse N 设置了它尝试复用的最小块大小。
前缀缓存节省的是 prefill 计算。20,000-token 的系统提示词只需处理一次,而不是每次请求都重新处理,因此可显著缩短首 token 延迟。在 vLLM 中,共享块会被复用,而不是重复存储,因此内存占用也会改善。但它不会减少当前仍处于活动状态的 token 所需保留的缓存。让权重在请求之间常驻内存是相关但独立的优化手段,详见让 Ollama 模型在请求之间保持加载状态。
在自己的服务器上测量什么
以目标上下文长度加载模型,然后读取实际数值,不要只相信估算结果。
ollama ps
nvidia-smi --query-gpu=memory.used,memory.total --format=csv
free -gollama ps会列出已加载的模型、模型大小、加载时使用的上下文长度,以及模型运行在 GPU 还是 CPU 上。先检查上下文列,因为默认值现在取决于 VRAM。 如果你预期模型完全运行在 GPU 上,但输出显示存在 CPU 分配,说明 KV cache 将模型的一部分推到了 CPU,生成速度也会相应下降。nvidia-smi会给出实际的 VRAM 数值,free -g在仅使用 CPU 的 VPS 上提供相同的信息。逐步提高上下文长度,重新加载模型,并观察数值变化。你的计算结果和输出数值应该接近。如果两者不一致,差值通常来自运行时自身的计算缓冲区,而不是公式错误。
如果这些数值让你倾向于选择不太想租用的硬件,可以在GPU VPS 与 API token 的对比中查看按 token 付费的成本比较。
FAQ
KV 缓存和提示缓存是同一回事吗?
不是。KV 缓存是服务进程内按请求分配的内存,用于保存当前上下文中每个 token 的 key 和 value 向量。它位于 RAM 或 VRAM 中,请求结束后释放。提供商的提示缓存是一项计费功能,会在提供商的基础设施上存储稳定的提示前缀;再次发送该前缀时,按较低费率计费。KV 缓存耗尽会导致模型无法加载。没有命中提示缓存只会增加账单和首 token 时间。
为什么我的模型在 2k 上下文下可以加载,但在 32k 下失败?
因为运行时会在加载时分配完整的 KV 缓存,其大小取决于配置的上下文长度,而不是你发送的提示长度。对于 f16 格式的 Llama 3.1 8B,缓存大小为每个 token 128 KiB,因此 2k 上下文需要 0.25 GiB,32k 需要 4 GiB。两种情况下权重都能装入内存。失败的是内存预留。vLLM 会通过 ValueError 报告此问题,说明所需的 KV 缓存内存和可用内存,并给出估算的最大模型长度,同时建议增大 gpu_memory_utilization 或减小 max_model_len。在运行 Ollama 或 llama.cpp 的纯 CPU 服务器上,内核的内存不足终止程序机制可能会直接终止该进程;可通过 dmesg -T | grep -i "killed process" 确认。
如何计算模型的 KV 缓存大小?
将 2、层数、key/value 头数、头维度和每个元素的字节数相乘,得到每个 token 所需的字节数。然后再乘以上下文长度和并发请求数。从模型的 config.json 中读取层数和头数。f16 或 bf16 每个元素使用 2 字节。q8_0 缓存的大小约为其一半,q4_0 约为其四分之一。
提示缓存会减少我的服务器所需的内存吗?
提供商的提示缓存不会影响你的硬件,因为缓存存储在提供商一侧。本地对应方案是前缀缓存,vLLM 和 llama.cpp server 都支持该功能。它会复用共享前缀已经计算出的 key 和 value 向量,从而减少 prefill 计算并缩短首 token 时间。在 vLLM 中,共享块会被复用,而不是重复创建,因此也能减少内存占用。但这两种功能都不会减少当前正在处理的 token 所需的缓存大小,因此上下文长度和并发数的计算仍决定内存下限。
只发送一次的提示,值得缓存吗?
不值得。写入缓存的费用高于普通输入;截至 2026 年 10 月,5 分钟选项的费用是基础费率的 1.25 倍。因此,如果前缀在缓存窗口内不会再次发送,缓存只会造成损失。相同前缀会重复使用时,缓存才有价值,例如较长的系统提示,或需要针对同一文档提出多个问题的场景。检查 API 响应中的 cache_read_input_tokens,确认请求命中了缓存,而不是为写入操作付费。