深入 DeepInfer:DeepSeek 的 V4.1-Flash 架构
DeepInfer 是 DeepSeek 面向 V4.1-Flash 的推理架构,其中最有意思的代码并不是某个算子,而是一组调度与内存决策——它们让大规模 GPU 集群不至于把时间耗在互相等待上。下面带你把整套架构走一遍,同时标明生产环境方面的限定。
DeepInfer 是 DeepSeek 为 V4.1-Flash 开源的推理架构。要读懂它,先把三层分开:模型、引擎和服务。模型是 V4.1-Flash,引擎是本页的主题,服务则是 DeepSeek 留在内部的那部分。
推理引擎到底做什么
训练好的模型只是一堆权重。要把它用起来,就得响应请求:读取 prompt、运行模型、生成 token、把结果返回,并且同时服务大量用户,又不浪费昂贵的硬件。
成本主要由两个阶段决定:
- Prefill 读取 prompt 并构建 KV cache。它计算密集,可以并行处理大量 prompt token。
- Decode 一次生成一个 token。每一步都要读取 KV cache 和模型的一部分;它受显存带宽限制,对单步延迟很敏感。
大多数服务优化,要么是让其中一个阶段更便宜,要么是让它与别的工作重叠。DeepInfer 的特性可以清楚地对应到这个划分上。
部署形态:EPD、Wide-EP,以及大量 GPU
DeepSeek 的 Q&A 把生产版 V4.1 系统描述为 Vision-Encoder / Prefill / Decode(E/P/D)部署:
之所以要拆开,是因为 prefill 和 decode 偏好的硬件形态不同。Prefill 受算力限制,decode 受显存带宽限制。把它们放在同一个池里,必然要做折中。拆开之后,每个阶段可以独立扩容——代价是 KV cache 需要在池之间搬运,而且两套不同的负载要分别做均衡。
DeepSeek 的生产数字:
| 阶段 | 并行布局 | 原因 |
|---|---|---|
| Prefill | EP2–8 / DP2–8 | 在能装进 HBM 的前提下用最小的 EP/DP;prefill 是计算密集型。 |
| Decode | EP64–128 / DP64–128(Wide-EP) | 用可用的最大 EP/DP;decode 受显存访问量限制。 |
| 视觉编码器 | 每个实例一块 GPU | 模型很小,别浪费一块快卡。 |
| TP / CP | 生产中不使用 | 开源引擎的示例中仍暴露了 CP;生产描述里不用 TP/CP。 |
DeepSeek 把 64 块 prefill GPU 加 64 块 decode GPU 称为最小的高效单元。1P + 1D 也能部署,但推荐的 decode 布局是 EP64 及以上,因此小集群达不到同样的效率。
专家负载均衡:冗余副本与周期性重排
MoE 路由并不均匀。有些专家很热,有些闲着。静态分配会浪费 GPU。DeepSeek 的 EPLB(专家并行负载均衡)加入冗余专家——热点专家的副本——并根据近期负载周期性地把专家重新分配到 GPU 上。
Q&A 中描述的机制是:
- 每块 GPU 持有自己的常规专家,外加少量冗余专家。
- 系统记录每个专家在最近 N 步内的负载。
- 每 M 步,它重新把专家分配到 GPU,并在 NVLink 域内用对称内存搬运权重。
| 阶段 | 冗余专家 | 统计窗口 | 重分配 | 实测 moe_lb |
|---|---|---|---|---|
| Prefill | 每 GPU 4 个(初始) | 100 步 | 每 1,000 步 | ≈1.03–1.07 |
| Decode | 每 GPU 1 个(初始) | 1,000 步 | 每 10,000 步 | 1.090 |
moe_lb 是最慢 rank 的耗时除以平均值。1.09 意味着最慢的 GPU 比平均多做约 9% 的工作。在 decode 这个规模上,这已经是很紧的数字;但它同样意味着最快的 GPU 仍要在同步屏障处等待。
moe_lb 是 1.074 / 1.045;中文知乎文章给出的是 1.0320 / 1.0618。decode 的数字(1.090)两边一致。我们对 prefill 采用区间,对 decode 采用稳定的那个数字。DSpark:把验证算力花在值得的地方
投机解码用一个 draft 模型先提出若干 token,再用一次前向完成验证。draft 猜对了,就用一次验证的成本换来多个 token;猜错了,就回退。
朴素做法是验证固定数量的 draft。DSpark 的不同之处在于变长验证:置信度头预测每个 draft token 被接受的概率,调度器再选出能让有效吞吐最大的前缀子集。
DeepSeek 还公开了 DeepSpec,一个 MIT 许可的代码库,用于训练和评估投机解码的 draft 模型。它覆盖 DSpark、DFlash 和 Eagle3,与 DeepInfer 引擎相互独立。
DeepSeek 的生产实测:
| 指标 | 固定 5 | 动态长度 |
|---|---|---|
| 每步验证的 draft token 数 | 5.00 | 3.2–4.4 |
| 平均接受长度 | 3.29 | 3.20 |
| 生产工作点吞吐(约 60 seqs/rank) | — | +4–7% |
| 96 seqs/rank 时的吞吐 | — | +11% |
解读很关键:验证工作量下降约 30%,而接受长度几乎不变。高并发下净收益为正。在每 rank 16 个序列时,表中显示的是小幅损失(−1.5%)。这不是免费午餐,而是一个依赖负载的优化。
本次发布中默认的最大 draft 长度为 5。不过,公布的 decode 图使用的是 nextn=3 fixed 和 75% 的单 token 接受率假设——这是一套测量配置,不是默认部署配置。
SWA 有界重放:让一次未命中变便宜,然后干脆不存
滑动窗口注意力(SWA)只把最近的 token 保留在完整注意力中。V4.1 使用 128 token 的窗口。如果 SWA KV cache 缺失,精确恢复的代价很高:每个解码层的窗口都依赖它下面那一层,因此跨 20 个解码层重建状态大约需要 2,560 次 token-layer 重放(20 × 128)。
SWA 有界重放做了一件刻意近似的事:
- 只重放最后 128 个 token。
- 在重放起点截断注意力窗口:位置 i 只注意
[max(s, i−127), i]。 - 接受一个近似的 SWA KV cache,把重算成本压成有界的常数。
发布的默认 V4.1 配置保留 140 token 的后缀(DEEPINFER_YOCO_PREFILL_KEEP_TOKENS=140)。多出来的空间用于覆盖窗口本身以及投机的回退。
这件事的意义不止于省算力:它让不持久化 SWA KV 成为一个理性的选择。因此 V4.1 的持久化 KV cache 只存全局 KV,不存 SWA KV,占用降到 V4 的大约八分之一。全局 KV 本身被压缩到每 token 约 890 字节,约为 V4-Flash 的四分之一。
有界重放并非逐位精确。DeepSeek 称质量损失可以忽略。vLLM 在自己的实现里独立测试过同样的思路,在 GSM8K 和 GPQA 上的差距约在 1.5 个标准误以内——这说明方法本身站得住,但并不构成对 DeepInfer 具体代码的验证。
异步调度:别让 GPU 等 CPU
一个 decode 步是这样的:
schedule(N) → forward(N) → sample(N) → post-process(N)
schedule 和 post-process 是 CPU 上的工作。在执行 post-process(N) 之前,CPU 需要拿到 GPU 上 sample(N) 的结果。这次同步会让 GPU 空转,等 CPU 处理完结果并调度好下一批。
DeepInfer 把两者重叠起来:
GPU: forward(N) → sample(N)
CPU: schedule(N+1) → launch_forward(N+1) → post-process(N−1) → launch_sample(N+1)
这个思路并不新——DeepSeek 引用了 SGLang 和 NanoFlow——但实现包含在本次发布中,并且默认开启。它很好地说明了“基准测试用的算子”与“服务引擎”之间差的是哪类工作。
批次不变推理与确定性采样
动态批处理会改变浮点归约的顺序。同一个 prompt,可能因为恰好和哪些请求分到同一批,而产出略有差异的 logits。对聊天来说,这通常看不出来。对基准测试、审计或复现一次 agent 运行来说,这就是问题。
DeepInfer 提供两级控制:
- 批次不变推理(
DEEPINFER_BATCH_INVARIANT=1):在不同的批次组成下,结果保持一致。 - 确定性采样:相同的输入 token 和采样参数产生完全相同的输出。它要求开启批次不变模式、关闭 MTP 变长解码(
DEEPINFER_ENABLE_MTP_VARLEN=0),并固定seq_seed。
这两项在本次发布中都只支持 NVIDIA。它们不是发布会的卖点,却是严肃评测团队会注意到的能力。
结构化输出:约束文法,而不是约束 prompt
结构化输出把生成约束在 regex、JSON Schema 或 EBNF 文法之内。DeepSeek 的生产设计会在一台独立机器上把约束编译成文法自动机,然后在每个 decode 步施加 token 掩码。编译与推理解耦,因此请求可以在进入引擎之前就取到编译好的文法。
在本次发布中,API 是 SamplingParams(so_args={"schema_type": ..., "schema": ...})。离线示例也可以用 --check_structured_output 跑 regex、JSON 和 EBNF 校验,并验证正常的 EOS 终止。
这并非 DeepInfer 独有——约束解码是众所周知的技术——但把它放进服务引擎内部,对 agent 和抽取类负载来说很方便。
DeepSeek Recipe:“API 兼容”的另一半
推理引擎负责算出 token。而一个 API 服务还必须:
- 接收 Chat Completions、Responses 和 Messages 请求;
- 渲染模型的 prompt 格式,包括思考模式、工具调用和图像;
- 把文本编码成 token ID,同时不让用户文本注入特殊 token;
- 跨 chunk 边界解析流式输出;
- 把推理内容、工具调用和停止序列还原成协议响应。
deepseek-recipe 做的就是这些。它是一个独立的 MIT 许可仓库:Rust 库加 Python 绑定,另附示例服务器。DeepSeek 称其处理逻辑与官方 API 对齐,因此第三方部署可以表现得和官方服务一致。
有两个细节值得称道:
- 特殊 token 注入防御。如果用户输入
<|User|>或<|image|>,Recipe 会把它编码成普通文本,而不是控制 token。模型无法被诱导把用户内容当成角色边界。 - 分段并行分词。构建 prompt 时,特殊 token 及其位置是已知的,因此夹在它们之间的普通文本段可以各自独立编码再拼接。这能降低长上下文的 tokenization 延迟。
如果你在评估 DeepInfer 作为服务栈,Recipe 值得和引擎同等关注。引擎是昂贵的那部分,Recipe 则是让 API “手感对”的那部分。
新想法还是旧想法?
| 概念 | 现状 | DeepSeek 增加了什么 |
|---|---|---|
| 投机解码 | 已有技术 | DSpark 的置信度调度变长验证 |
| 滑动窗口注意力 | 已有技术 | 有界重放 + 不持久化 SWA KV |
| 专家并行 | 已有技术 | 64–128 块 GPU 上的 Wide-EP,加上生产级 EPLB 调参 |
| 连续批处理 / 异步调度 | 已有技术 | 一套完整且默认开启的实现 |
| 结构化输出 | 已有技术 | 集成进引擎,文法编译独立进行 |
| 批次不变 / 确定性推理 | 较少见 | 明确支持,并写明适用条件(仅 NVIDIA) |
| 专用 3FS 集群上的 KV cache | DeepSeek 特有 | 100 PiB、3/7 天 TTL、跨机器 prefix 命中 |
| CED + SWA 重放的协同设计 | DeepSeek 特有 | 模型架构与引擎一起调优 |
老实说:这些原语大多不是 DeepSeek 发明的。它的贡献在于集成——以及愿意把生产环境的调参公开出来。
生产设计 ≠ 开源代码
EPD、EPLB、KV cache 和负载均衡几节描述的都是 DeepSeek 在 Q&A 中记录的生产系统。本次发布不包含 KV cache 系统、VE/Prefill/Decode 分离,也不包含数据并行负载均衡。读生产设计有助于理解这个引擎,但它不是仓库的功能清单。
Q&A 真正给你的,是一张罕见的决策地图:为什么用 Wide-EP、为什么是 64+64、为什么用 3FS、为什么 TTL 是 3/7 天、为什么做有界重放、为什么验证要变长。对另一家实验室的工程师来说,这张地图才是本次发布最有价值的部分——即便代码止步于引擎边界。
下一篇:如何读懂那两张图、缺失部分对部署意味着什么,或者服务框架对比:vLLM、SGLang、TensorRT-LLM。