为什么 DeepSeek 这么便宜¶
约 3053 个字 预计阅读时间 10 分钟
逐层拆解背后的架构创新与工程实现。
一、价格差距有多大¶
1.1 一组价格对比¶
| DeepSeek V4-Flash | OpenAI GPT-4o | |
|---|---|---|
| 输入(缓存命中) | ¥0.02 / MTok | $1.25 / MTok(~¥9) |
| 输入(正常) | ¥1 / MTok | $2.50 / MTok(~¥18) |
| 输出 | ¥2 / MTok | $10 / MTok(~¥72) |
缓存命中价差了 450 倍。即使不算缓存,正常输入价也差了近 20 倍。
而实际使用中,DeepSeek 官方给出的数据是:用户平均超过 50% 的 token 命中缓存,部分场景(长 system prompt、多轮对话、Few-shot)命中率更高。这意味着大部分用户的真实成本远低于标价。
1.2 这引出一个问题¶
同样跑 GPU,同样做推理,DeepSeek 凭什么把价格打到这个程度?答案是三层的连锁反应:
下面逐层拆解。
二、KV Cache 与计算节省¶
2.1 推理的两个阶段¶
Decoder-only 模型(如 GPT、DeepSeek)的每次请求,在服务端都经历两个阶段:
| 阶段 | 行为 | 计算特征 |
|---|---|---|
| Prefill | 并行处理所有输入 token,生成 KV 向量 | compute-bound |
| Decode | 逐 token 自回归生成输出 | memory-bound |
Prefill 阶段需要一次性处理整个 prompt。如果你发了 128K token 的 prompt,这 128K token 的注意力计算必须全部完成,才能开始生成第一个输出 token。
2.2 为什么 Prefill 这么贵¶
Transformer 的核心操作是 self-attention,其计算复杂度与序列长度 N 的关系是:
序列长度翻倍,注意力计算量翻四倍。 这就是为什么长 prompt 的 prefill 既慢又贵——它是 compute-bound 的,GPU 的计算单元火力全开。
DeepSeek 文档中给了一个实际数字:128K token 的首 token 延迟约 13 秒。如果用户反复发送相同或相似的长前缀(system prompt、文档上下文、Few-shot 示例),这些 13 秒就会被反复消耗。
2.3 以存换算¶
核心思路很简单:把 prefill 算出来的 KV 向量存下来,下次直接用。
传统方式:
请求1: [A][B][C] → prefill(算 A、B、C 的 KV)→ decode → 释放 KV
请求2: [A][B][D] → prefill(重新算 A、B 的 KV)→ decode → 释放 KV
↑ 重复计算
磁盘缓存方式:
请求1: [A][B][C] → prefill → decode → KV 写入磁盘(不释放)
请求2: [A][B][D] → 磁盘加载 A、B 的 KV → 只 prefill D → decode
↑ 省掉了 A、B 的计算
代价是:
| 环节 | 耗时 |
|---|---|
| 磁盘加载 KV(几百 MB) | 50~200 ms |
| 被跳过的 prefill 计算(128K prompt) | ~13 s |
用 200ms 的磁盘 IO 换 13s 的 GPU 计算,净赚 12.8 秒。 这就是"以存换算"的本质——磁盘比 GPU 显存便宜两个数量级,但比 GPU 计算快一个数量级。在两者之间做置换,总体效率提升。
三、架构基石:MLA 如何让磁盘缓存成为可能¶
3.1 为什么不能直接把 KV 存磁盘¶
标准 Transformer 使用 MHA(Multi-Head Attention),每层的 KV Cache 体积为:
以一个典型的大模型为例,128K token 的 KV Cache 可以达到 几十甚至上百 GB。这个量级的数据,从磁盘加载的延迟会完全吃掉预计算节省的时间。这也是为什么 OpenAI 等厂商的 Prompt Caching 只把 KV Cache 放在显存中,且 5~10 分钟无活动后自动清除[^1]——体积太大,既存不起磁盘,也舍不得多占显存。
[^1]: OpenAI Platform Docs — Prompt Caching: cached prefixes are automatically evicted after 5–10 minutes of inactivity.
3.2 MLA 的核心思想¶
DeepSeek V2 提出的 MLA(Multi-head Latent Attention) 从根本上解决了这个问题。
MHA 中,每个 head 独立存储 K 和 V:
MLA 引入了一个低秩压缩:
只存低维的 C_KV(Latent),不存展开后的 K 和 V。 压缩比可以做到原来的 几十分之一。
这是整个故事的起点:KV 体积小到可以落盘了,磁盘缓存才从"不划算"变成了"很划算"。
3.3 从 V2 到 V4:能力演进¶
| 时间 | 事件 | 对缓存的影响 |
|---|---|---|
| 2024.05 | DeepSeek V2 | MLA 架构首次落地,KV 体积大幅压缩 |
| 2024.08.02 | 上下文硬盘缓存上线 | 全球首个大规模磁盘 KV Cache 服务 |
| 2024.09 | V2.5 | |
| 2024.12 | V3 | 模型能力跃升,缓存体系继续运行 |
| 2026.04.24 | V4(Flash + Pro) | 缓存命中价降至首发 1/10 |
| 2026.07.24(计划) | deepseek-chat / reasoner 弃用 |
官方计划全面迁移至 V4 系列 |
磁盘缓存不是 V4 的新功能,它在 V2 时代就已经运营超过一年半。 V4 带来的是模型能力提升和更激进的定价,而不是首次引入缓存。
四、Prefix Caching 机制深度剖析¶
4.1 不是单纯的"前缀匹配"¶
传统理解的"前缀缓存"是:新请求的前缀和旧请求的前缀,逐 token 对齐,对齐多少就复用多少。但 DeepSeek 的实现更严格,也更精巧。
缓存的单位是以 64 token 为粒度的缓存前缀单元(cache prefix unit),每个单元在落盘时被赋予固定边界,不可再拆分。匹配时必须完整包含一个或多个单元,从第 0 个 token 开始对齐。
4.2 命中条件的具体案例¶
请求1: prompt = [system_prompt] + [doc_A]
→ 落盘单元: [system_prompt | doc_A](作为一个整体)
请求2: prompt = [system_prompt] + [doc_B]
→ 无法命中 ← 因为 [system_prompt+doc_A] ≠ [system_prompt+doc_B]
→ 但系统检测到 system_prompt 是公共前缀
→ 独立落盘: [system_prompt](成为一个新单元)
请求3: prompt = [system_prompt] + [doc_C]
→ 命中单元 [system_prompt] ← 受益于前两次请求的"探测"
关键洞察:同一前缀需要出现两次,系统才会识别并独立落盘。 这也是为什么 DeepSeek 说"不保证 100% 命中"——缓存的构建是渐进式的。
4.3 三种落盘时机¶
| 时机 | 触发条件 | 目的 |
|---|---|---|
| 请求结束位置 | 每次请求的输入结束点和输出结束点 | 保底覆盖,确保每次请求的完整前缀都能被缓存 |
| 公共前缀检测 | 多次请求出现公共前缀 | 将公共部分提取为独立单元,提高后续命中率 |
| 固定 token 间隔 | 长输入/输出超过阈值 | 避免超长前缀因迟迟不结束而无法被缓存 |
这三种机制配合,既保证了缓存的覆盖范围,又能逐步优化缓存的粒度。
4.4 完整推理链路¶
请求到达 DeepSeek 服务端
│
▼
对前缀按 64-token 边界切分、Hash
│
├─── Hash 命中磁盘索引
│ │
│ ▼
│ 从 NVMe SSD 异步加载 KV 到显存
│ │
│ ▼
│ 跳过该前缀的 prefill 计算
│ │
└─── Hash 未命中
│
▼
正常 prefill(计算 KV)
│
▼
KV 异步写入磁盘
│
┌─────────┴─────────┐
▼ ▼
Decode 逐 token 生成(与无缓存完全一致)
│
▼
返回流式输出给用户
注意:KV 的磁盘加载和写入都是异步的。加载发生在请求排队的间隙,写入发生在请求完成之后,都不阻塞 decode 主线。这就是为什么用户感知不到延迟增加。
到这里可以看出,低价不仅是 MLA 架构的红利——如果缓存 Infra 和开源方案一样停留在显存层面,命中率、缓存时长和跨请求复用都会大打折扣。下面具体对比开源方案,看清 Infra 设计选择带来的差距。
五、行业对比:DeepSeek 比开源方案强在哪¶
5.1 开源社区的主流方案¶
vLLM — Block-level Hash Caching
vLLM 把 KV Cache 按固定大小的 block(通常 16 token)切分,每个 block 基于其 token 序列计算 hash。请求到达时,对前缀的每个 block 计算 hash,去 hash 表中查找是否有已缓存的相同 block。
vLLM 方式:
前缀: [tok0..tok15] [tok16..tok31] [tok32..tok47] ...
↓ hash ↓ hash ↓ hash
查 hash 表 查 hash 表 查 hash 表
- 优点:实现简单,查找 O(1)
- 局限:缓存主要依赖 GPU 显存,容量受限于显存大小(虽支持 CPU swap,但从 CPU 加载的延迟远高于磁盘缓存方案的目标延迟);必须完整匹配 block 边界
SGLang — Radix Tree Caching
SGLang 使用 Radix Tree(基数树) 组织 KV Cache,每个节点对应一段 token 序列,新请求在前缀树上做最长匹配。
- 优点:支持任意长度的最长前缀匹配,比 hash block 更灵活
- 局限:树结构维护成本高,缓存主要依赖 GPU 显存,容量受限于显存大小
5.2 DeepSeek 的差异化¶
| vLLM | SGLang | DeepSeek | |
|---|---|---|---|
| 匹配方式 | Block Hash | Radix Tree | 单元 Hash + 公共前缀检测 |
| 匹配粒度 | 固定 16 token block | 任意长度前缀 | 64 token 单元 |
| 缓存位置 | GPU 显存为主 | GPU 显存为主 | 服务器磁盘 |
| 缓存时长 | 请求级别 | 请求级别 | 几小时到几天 |
| 跨请求复用 | 有限 | 有限 | 大规模 |
| 用户感知 | 需自行部署 | 需自行部署 | 全透明,无需任何配置 |
核心差异在于 存储层级的下沉。vLLM 和 SGLang 的缓存停留在昂贵的 HBM 里,天然受容量约束;DeepSeek 把缓存压到了便宜的磁盘上,存几个小时甚至几天几乎没有成本负担。
5.3 DeepSeek 可能做了哪些额外的深度优化(推测)¶
以下基于工程实践和文档行为的合理推测:
1. 多级冷热分层
热缓存(最近命中过的单元)可能仍然驻留在内存/显存中,冷缓存才落盘。这样高频前缀的访问延迟进一步降低,低频前缀也不占用昂贵资源。
2. 跨节点缓存调度
大规模部署中,同一用户的请求可能被路由到不同节点。DeepSeek 需要一个缓存寻址层来定位某个前缀单元在哪个节点的磁盘上,或者将热点单元复制到多个节点。
3. 异步预加载与流水线
收到请求后立刻(不等排队完成)根据前缀 hash 发起磁盘 IO,让 KV 加载和请求排队 overlap。KV 还在加载时就可以启动部分 prefill,进一步压缩 TTFT。
4. 单元合并与分裂
类似 SGLang 的 Radix Tree 在压缩公共前缀上的思路,DeepSeek 可能也会动态合并高频共现的连续单元(提高命中效率),或分裂低频长单元(释放空间)。
5.4 绕不开的 MoE 红利¶
以上四点属于工程推测,但有一个优势是确定的:DeepSeek-V 系列是 MoE 模型。以 V3 为例,每次前向只激活约 37B 参数(671B 总量)。相比同级别的 Dense 模型,prefill 的计算量本身就小得多。更小的 prefill 计算量 + MLA 压缩后的 KV + 磁盘持久化,三重叠加才造就了现在的性价比。
六、总结:三层驱动的飞轮¶
┌──────────────────────────────┐
│ Layer 1: 架构(MLA + MoE) │
│ 模型效率本身就比同行高 │
│ → 单次推理成本低 │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ Layer 2: Infra(磁盘 KV Cache)│
│ 以存换算,消除重复计算 │
│ → 跨请求复用,成本进一步降低 │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ Layer 3: 定价 │
│ 成本优势转化为价格优势 │
│ → 缓存命中 ¥0.02 / MTok │
└──────────────────────────────┘
便宜不是单一因素造成的。 它是 MLA 压缩 KV、MoE 降低计算量、磁盘缓存消除重复、激进定价让利用户,四件事环环相扣的结果。每少一环,都做不到这个价格。
也正因如此,这套体系难以被竞品简单复制——你可以在 API 层面做缓存,但如果底层没有 MLA 级别的 KV 压缩,磁盘 IO 就是瓶颈;或者你有 MLA,但没有搭好磁盘缓存的 Infra 管线,容量和命中率就是瓶颈。
最终,DeepSeek 的选择是:把复杂性留在 Infra,把红利留给用户。
Last update: April 29, 2026
Discussion