3759 words
19 minutes
大语言模型的缓存技术

大语言模型的缓存技术#

LLM(大语言模型)推理中的缓存主要解决两个核心问题:成本(token 收费)和延迟(重复计算)。本文按缓存层级、核心概念到主流平台的策略逐层拆解。

LLM 缓存技术原理#

1. KV Cache(KV 缓存)——最核心#

Transformer 自回归生成时,每生成一个 token 都要重新计算之前所有 token 的注意力分数。KV Cache 把已生成 token 的 Key 和 Value 矩阵存下来,下次只需计算新 token 的 Query 与缓存 KV 的注意力,避免重复做前向传播。

  • 显存占用大2 × 层数 × 隐藏维度 × 序列长度 × 精度 × 批次,是长上下文推理的主要瓶颈。
  • 相关优化
    • PagedAttention(vLLM 核心):把 KV 按固定块分页管理,类似操作系统的虚拟内存,减少碎片、提高批处理吞吐。
    • GQA/MQA(分组查询注意):多个 Query 头共享少数 Key/Value 头,大幅压缩 KV 缓存。
    • KV 量化:把缓存的 KV 量化为 INT8/INT4。
    • KV 驱逐/压缩(如 H2O、StreamingLLM):只保留重要 token 的 KV。

2. 前缀缓存 / Prompt Caching(提示词缓存)#

系统提示词、few-shot 示例等前缀固定不变。推理服务把此前缀的 KV Cache 按内容哈希缓存,同一前缀的请求直接复用,跳过重复计算。

  • 语义缓存(如 GPTCache):对查询做语义相似度匹配,完全相同或高度相似的请求直接返回缓存好的完整回答,完全跳过模型推理。
  • OpenAI / Anthropic / Gemini 等 API 都对稳定前缀提供 prompt caching 折扣价(写入按全价、读取打折扣)。

3. 模型结构级缓存#

  • MoE(混合专家):缓存 token 被路由激活的专家路径,减少重复的路由计算。
  • Speculative Decoding(投机解码):与小模型推断候选、大模型验证,其中”验证”部分依赖已缓存信息加速。

4. 硬件 / 系统级缓存#

  • GPU 厂商的 token 缓存KV cache 专用加速(如 NVIDIA、AMD 的 KV 缓存优化,降低显存带宽瓶颈)。
  • 把 KV 缓存放进主机内存 / 远程存储,做跨进程、跨节点共享(如 Mooncake 这类 KVCache 卸载系统)。

5. 缓存一致性 / 失效难点#

  • Prompt 哪怕多一个空格或换行,哈希就变,缓存即失效 → 需要规范化(去除多余空白、排序等)。
  • 服务端按 token 级别(而非字符)计算,长度对齐、是否带 continue 标记都会影响命中率。

一句话总结:LLM 缓存的核心思路是——KV Cache 省掉重复计算(推理层),前缀/语义缓存省掉重复生成(服务层),配合显存管理与量化来对抗缓存的存储开销。

KV Cache 和 Prompt Cache 有本质区别吗?#

Prompt caching 的底层就是 KV cache,但两者严格来说是不同抽象层级的两个概念,差异主要在”是谁在缓存、缓存给谁用、怎么判定命中”。

本质关系#

KV cache: 推理引擎内部的"机制"(单请求内的缓存)
↓ 跨请求持久化 + 前缀对齐
Prompt cache:服务层的"产品特性"(跨请求的缓存)

可以这样类比:KV cache 是内存,prompt cache 是磁盘上的持久化缓存。内存本来就是干这个的,但”持久化 + 按 key 检索 + 淘汰策略”是另一层工程。

关键区别#

维度KV CachePrompt Cache
抽象层级推理引擎内部机制,每个请求必然产生服务层产品特性,需要显式设计才有
生命周期通常随请求结束就释放(除非引擎特意保留)跨请求、跨会话持久,可被多个用户/请求共享
缓存范围整个已生成序列(前缀 + 新生成的部分都缓存)只缓存稳定前缀(系统提示词、few-shot 等),新生成部分不进 prompt cache
命中判定无判定——同一请求内连续计算,天然”命中”需要按 token 级前缀对齐 + 哈希/规范化来判定是否复用
成本形态纯工程成本(显存占用)产品化计费(如 OpenAI 写入全价、读取 4 折)
管理复杂度显存管理(PagedAttention、KV 量化)缓存容量、LRU 淘汰、跨节点一致性、前缀规范化

例证:为什么说 prompt cache “就是” KV cache#

vLLM 的 prefix caching 就是直接把之前请求的 KV cache 块按哈希存下来(block hash 匹配前缀块),下一个请求如果前缀相同,直接从缓存块开始计算,跳过前缀的 prefill。这里 prompt cache 的存储单元就是 KV cache 块,没有第二种缓存介质。

但也有”不是 KV cache”的 prompt 缓存#

  • 语义缓存(GPTCache 等第三方):对问题做 embedding 相似度匹配,命中后直接返回完整回答,连模型都不调用——这本质是”应用层结果缓存”,和 KV cache 无关。
  • 中间状态缓存:有些系统会缓存 prompt 的 prefill 输出(如 embedding、logits 中间态),不限于 KV 对。

一句话总结:Prompt cache ≈ KV cache 的跨请求持久化 + 前缀复用特化。它没有发明新的缓存数据,而是在 KV cache 之上加了生命周期管理、命中判定、计费策略这三层东西。KV cache 是”机制”,prompt cache 是”建立在机制之上的产品策略”。

交替前缀(A, B, A, B)会命中 Prompt Cache 吗?#

如果多次请求的 prompt 前缀是间隔相同的——第一和第三次前缀相同(A),第二和第四次前缀相同(B)——会命中缓存吗?结论:会命中,但”间隔相同”本身不是决定因素。

决定命中与否的是两个东西保留时长(TTL)缓存容量(淘汰策略),而不是请求的交替模式。只要这两个条件满足,第 1、3 次用前缀 A,第 2、4 次用前缀 B,都能各自命中

为什么”交替模式”不影响命中#

你担心的场景是:请求 3(前缀 A)进来时,缓存里可能还留着请求 2(前缀 B)的东西,A 会不会被挤掉?这取决于:

1. 保留时长 / TTL(Anthropic 这类 API)#

Anthropic 的 prompt cache 有 5 分钟默认 TTL(可配置到最多 1 小时)。只要第 3 次请求离第 1 次请求在 TTL 窗口内,前缀 A 的缓存就还”活着”,直接命中,跟中间隔了几个请求无关。TTL 是”从缓存被写入/读到的那一刻起倒计时”,不是”按请求次数”。

2. 容量 / 淘汰策略(vLLM 这类自托管)#

vLLM 的 prefix caching 用 LRU(最近最少使用)淘汰,缓存块按 block hash 管理。关键问题:前缀 A 的块会不会在前缀 B 被加载时被踢出

  • 如果缓存容量足够大:A 和 B 的块都能并存,请求 3 命中 A,请求 4 命中 B,互不干扰。
  • 如果容量吃紧:LRU 会优先淘汰最久没用的块。请求 2 用了 B,A 就成了”较久没用”的,可能被淘汰 → 请求 3 就 miss,需要重新 prefill A。

真正的判定条件#

举个具体例子——假设缓存容量能同时装下 A 和 B:

请求前缀命中?原因
1Amiss首次,还没缓存
2Bmiss首次
3AhitA 未被淘汰,且在 TTL 内
4BhitB 未被淘汰,且在 TTL 内

而如果容量只够装一个前缀,LRU 会让 A、B 互相驱逐,结果变成全部 miss(每次都重新 prefill),因为每次换前缀都会把上一个踢掉。

一句话总结:交替请求(A, B, A, B)能命中,前提是:① 时间上落在 TTL 窗口内;② 缓存容量足够容纳多个前缀,不会被 LRU 互相挤掉。真正决定命中率的是 TTL 和容量/淘汰策略,不是请求的先后交替模式。

百炼 / Kimi / 智谱 / DeepSeek 的 Prompt Cache 策略对比#

以下策略信息来自各平台官方文档的一手核对。

1. 百炼(通义千问 / DashScope)—— 显式 + 隐式双模式#

百炼是这四家里**唯一支持显式缓存(用户手动控制)**的平台,也提供自动隐式缓存。

维度显式缓存隐式缓存
开启方式需在 content 里加 cache_control:{"type":"ephemeral"}全自动,无法关闭
命中规则确定性命中(服务端从标记位置向前回溯)自动识别公共前缀,命中率不确定
最少缓存 Token1024256
有效期5 分钟(命中后重置)不确定,系统定期清理
创建缓存的 Token 计费标准输入价 125%标准输入价 100%
命中缓存的 Token 计费标准输入价 10%标准输入价 20%

关键细节:

  • 单次请求最多 4 个缓存标记,回溯最近 20 个 content 块
  • 工具定义(function calling)会作为系统消息参与缓存计算,要求每次完全一致(顺序、字段都一致)否则失效。
  • 支持模型:qwen3.8-max/plus/flash、glm-5.1、kimi-k2.6/k2.7-code、deepseek-v3.2 等。

2. Kimi(Moonshot)—— 全自动,无需配置#

  • 对所有模型自动启用,无需手动创建、无需缓存 ID、无需管理 TTL。
  • 命中条件:前一个请求的 prompt tokens > 256 才缓存(小于 256 的请求会被丢弃)。
  • 建议把固定大段上下文(system prompt、知识文档)放在 messages 数组最前面以提高命中率。
  • 定价(K3 为例):
价格(/1M tokens)
输入(缓存命中)¥2.00
输入(缓存未命中)¥20.00
输出¥100.00

即命中价 = 未命中价的 10%

3. 智谱(GLM)—— 隐式自动 + 内容相似度#

  • 自动缓存:基于内容相似度识别重复上下文(系统提示词、历史对话),无需任何配置。
  • 命中情况通过 usage.prompt_tokens_details.cached_tokens 透明返回。
  • 计费:缓存命中的 Token 按优惠价(文档示例为标准价的 50%),新内容按标准价,输出按标准价。
  • 支持所有主流模型(GLM-5.2 / 5.1 / 5 系列等)。
  • 注意:轻微格式差异可能影响命中;缓存有”合理时效”,过期会重算。

4. DeepSeek —— 硬盘缓存,折扣最狠#

  • 采用上下文硬盘缓存(存分布式硬盘阵列),全自动,无需改代码换接口。
  • 命中规则最严格:要求从第 0 个 token 开始前缀完全相同,中间开始的重复不能命中。
  • 64 tokens 为存储单元(不足 64 的不缓存);“尽力而为”,不保证 100% 命中。
  • 长期不用的缓存自动清空(几小时到几天)。
  • 命中统计:prompt_cache_hit_tokens / prompt_cache_miss_tokens
  • 定价(V4 为例):
模型缓存命中输入缓存未命中输入输出
deepseek-v4-flash0.02元/1M1元/1M2元/1M
deepseek-v4-pro0.025元/1M3元/1M6元/1M

命中价 ≈ 未命中价的 2%,折扣是四家里最大的。得益于 MLA 结构把 KV Cache 压缩到可落硬盘。

交替前缀(A,B,A,B)在各平台的表现#

结合各平台策略,结论依然是 “能命中,取决于 TTL 和容量”,但各平台权重不同:

  • 百炼显式:TTL 明确 5 分钟,只要 A、B 各在 5 分钟内被再次使用就能各自命中(命中会重置 TTL)。容量/淘汰由服务端管,通常两种前缀可并存。
  • Kimi / 智谱:TTL 由系统自动管理、不透明,命中率不做保证,交替大概率能命中但不保证
  • DeepSeek:TTL 是”几小时到几天”的清空机制,A、B 交替基本都能命中;但记住必须从第 0 token 前缀完全一致,只要 A、B 各自的 system prompt 保持稳定即可。

一个共同陷阱:所有平台都是前缀匹配。交替请求时,[A, B, A, B] 中第 3 次请求(前缀 A)能命中,前提是 A 的稳定前缀部分(如系统提示词)在两次请求间完全一致——如果 A 前缀里混入了上轮对话历史等动态内容,命中率会大幅下降。

什么是前缀匹配(Prefix Matching)#

在 prompt cache 语境里,“前缀”指的是 token 序列从最开头(第 0 个 token)开始的一整段连续内容。“前缀匹配”就是:新请求的前面这一段内容和缓存里存过的内容完全对齐,我们就认为它可以复用这段时间的缓存结果。

它只认”从头部开始、连续、完全一致”#

缓存里存过的前缀: [系统提示词] [few-shot示例] [用户问题1]
新请求的完整内容: [系统提示词] [few-shot示例] [用户问题1] [用户问题2]
└────── 这部分和缓存一致 ──────┘
↑ 命中点

判定规则两条:

  1. 必须从第 0 个 token 开始——不能从中间某处开始匹配。
  2. 必须连续且完全一致(token 级,一个多余的空白/换行/顺序变化都会让后续全部失效)。

满足这两条,新请求就能跳过前缀这段的 prefill 计算,直接从命中点之后开始算。

为什么”前缀”而不是”任意位置”#

因为 Transformer 的注意力是因果的(causal):每个位置的输出只依赖它之前的所有 token。所以一段内容只要在开头、且和之前完全一样,它的 KV cache 就完全可复用——前面没变,后面算出来必然一样。

反过来,如果重复内容出现在中间后面,它前面的 token 变了(比如混入了上一轮对话历史),那它的 KV 就算重算也不对,所以中间/后段的重复无法命中

具体例子#

请求1:你是助手。 用户说:天气如何? → 首次,miss
请求2:你是助手。 用户说:天气如何? → 前缀命中!(你是助手。)
请求3:你好。 用户说:天气如何? → miss,因为开头变成了"你好。"
请求4:你是助手。 用户说:股票如何? → 仍命中!(你是助手。 部分复用)

注意请求 4:虽然用户问题变了,但开头”你是助手。“没变,所以这部分照样命中,只重算后半段。

各平台对”前缀”要求的严格度不同#

平台前缀规则
DeepSeek最严格:必须第 0 个 token 开始完全一致,中间开始的重复一律不命中
百炼显式缓存cache_control 标记位置向前回溯固定数量内容块,要求这些块完全一致(偏前缀性质)
Kimi / 智谱自动识别公共前缀,命中率不保证,格式差异可能失效

一个常见误区#

“前缀”不是指用户最近说的话,而是指一整个消息序列最开头的那部分——通常是系统提示词、固定知识库、或历史对话的早期部分。所以实践中把固定的大段内容放在 messages 最前面,才能最大化命中率。

大语言模型的缓存技术
https://sgjki547.top/posts/2026-08-05-大语言模型的缓存技术/
Author
SGJki
Published at
2026-08-05
License
CC BY-NC-SA 4.0