📦 GitHub: https://github.com/geekchow/deepseek-v41-flash-inference-guide
你在哪里 :已知问题与定义,现在一次性铺开整片领域。
读完本文你将知道:8 个核心概念(按依赖顺序)、7 个关键组件各自"负责什么 / 知道什么 / 刻意不做什么",以及它们如何协同把一个请求变成一个回答。此处不讲内部实现。
3.1 领域映射:从问题到概念
| # | 现实问题 | 系统概念 | 一句话定义 | 为什么是这个抽象 |
|---|---|---|---|---|
| C1 | prefill 和 decode 脾气相反 | EPD 分离 | 视觉编码(VE,Vision Encoder)、预填充(P)、解码(D)部署在不同机器池,各自扩缩容 | TTFT 与 TBT 可以分别优化;各阶段选各自最优并行度和硬件 |
| C2 | MoE 权重太大、decode 访存瓶颈 | Attention DP + MoE EP(Wide-EP) | 注意力按数据并行(#DP = #EP),专家按专家并行切到多卡;decode 用 EP64--128 | EP 越宽,每卡要读的专家权重越少,批越大,矩阵乘效率越高 |
| C3 | 缓存要省、要大、要可靠 | 分层 KV 缓存 | 三类:在途 KV(显存)、SWA KV (本机内存,单副本)、Block KV(3FS 集群,分页) | 不同 KV 体积与复用价值差异巨大,分层存放成本最低 |
| C4 | 多轮请求大量重复前缀 | 前缀命中与命中策略 | 用哈希链对前缀做元数据匹配;命中长度由 Block KV 决定,最后一块是否重算由 SWA KV 决定 | 任意 prefill 机器可命中任意前缀,路由不必考虑亲和 |
| C5 | SWA 缓存缺失时重算代价随层数和长度增长 | SWA Bounded Replay | 只重放最近 128 个 token、并把注意力窗口截断在重放段内,得到近似 SWA KV | 重算代价变为常数;持久化 KV 降到 V4-Flash 的约 1/8 |
| C6 | 请求长短悬殊,按"请求数"均衡不准 | 计算配额(compute quota) | 用拟合的二次代价模型 cost(q, c) 把请求换算成纳秒级时间预算,按预算调度和均衡 |
均衡的是"算力时间",而不是"请求个数" |
| C7 | 固定长度投机解码浪费验证算力 | DSpark 变长验证 | 草稿模型一次出 5 个 token,置信度头(Confidence Head)预测每个的接受率,只验证边际收益最高的前缀 | 验证 token 数减少约 30%,接受长度几乎不变 |
| C8 | 三种 API 协议、控制 token 注入风险 | 统一 Conversation + 特殊 token 区间 | 所有协议先转成同一个 Conversation,再渲染出 prompt 和"哪些字节是真正的特殊 token" | 一套模板服务三种协议;用户文本中的同名字符串只能是普通文本 |
依赖关系:C1 → C2(分离后才能各选并行度)→ C3/C4(有了分离和多副本,缓存必须共享)→ C5(共享缓存只存 Block KV,SWA 缺失时怎么办)→ C6(请求换算成算力才能均衡)→ C7(decode 侧再提速);C8 横跨入口和出口。
3.2 关键组件:从概念到组件
下图回答:系统的物理分层长什么样(官方架构图)。

黑色箭头为请求流,蓝色粗箭头为 KV 缓存流。
| # | 组件 | 负责(Owns) | 知道(Knows) | 刻意不做(Does not do) |
|---|---|---|---|---|
| K1 | deepseek-recipe | 协议 JSON ↔ token 序列 + 采样参数;输出 token 流 ↔ 协议流式事件 | 各协议字段语义、V4/V4.1 模板、特殊 token 表、tokenizer | 不推理、不发 HTTP、不执行工具、不算 logprobs |
| K2 | Entrypoint | 请求入口;前缀命中长度计算;选择 prefill 路由;回收 decode 结果 | 本地 kvcache-store(CHECK 角色)的哈希链元数据;SWA KV 位置目录(按 key 分片) | 不搬运 KV 数据本身(只看元数据) |
| K3 | KVCache Storage(kvcache-store + 3FS) | 持久化 Block KV;按 LRU 回收过期缓存 | ~100 PiB SSD 上每个块的位置;10+2 纠删码分组 | 应用层不做副本、不做 TTL 判断(全交给 3FS GC) |
| K4 | 负载均衡器族(Prefill LB / Decode LB / VE LB / EPLB) | 把请求分配到 DP 副本;把专家分配到 GPU | 各引擎剩余计算配额、并发数、KV 总长度、专家近期负载 | 不考虑前缀亲和(缓存是全局共享的) |
| K5 | Vision Encoder Service | 把图片编码成 embedding 交给 prefill | 每卡正在处理的 patch 数 | 不参与文本 prefill;单卡即可,用便宜卡 |
| K6 | Prefill Service(DeepInfer 实例,EP2--8) | 计算未命中后缀的 KV;执行 SWA Bounded Replay;把 KV 写入 3FS 并传给 decode | 本批请求的命中长度、换入的 KV 块、时间预算 | 不做长时间生成;不用 TP(Tensor Parallelism,张量并行)/ CP(Context Parallelism,上下文并行) |
| K7 | Decode Service(DeepInfer 实例,Wide-EP 64--128) | 逐步生成 token;DSpark 投机解码;结构化输出掩码;把 decode 产生的 KV 也落盘 | 在途 KV、每请求每草稿 token 的接受率、语法自动机状态 | 不做 KV offload(decode 不受缓存容量约束) |
这 7 个组件就是第 5 章深潜的目录(K5--K7 同属 DeepInfer,合并为一个子文件夹)。
3.3 协同一览:快乐路径
下图回答:一个请求从 JSON 进来到 JSON 出去,依次经过谁、带着什么数据。
Decode(DeepInfer) Decode LB 3FS KV Store Prefill(DeepInfer) Prefill LB Entrypoint Recipe Client Decode(DeepInfer) Decode LB 3FS KV Store Prefill(DeepInfer) Prefill LB Entrypoint Recipe Client #mermaid-svg-sB95pQU8D7VQvVuu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sB95pQU8D7VQvVuu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sB95pQU8D7VQvVuu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sB95pQU8D7VQvVuu .error-icon{fill:#552222;}#mermaid-svg-sB95pQU8D7VQvVuu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sB95pQU8D7VQvVuu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sB95pQU8D7VQvVuu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sB95pQU8D7VQvVuu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sB95pQU8D7VQvVuu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sB95pQU8D7VQvVuu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sB95pQU8D7VQvVuu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sB95pQU8D7VQvVuu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sB95pQU8D7VQvVuu .marker.cross{stroke:#333333;}#mermaid-svg-sB95pQU8D7VQvVuu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sB95pQU8D7VQvVuu p{margin:0;}#mermaid-svg-sB95pQU8D7VQvVuu .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sB95pQU8D7VQvVuu text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-sB95pQU8D7VQvVuu .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-sB95pQU8D7VQvVuu .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-sB95pQU8D7VQvVuu .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-sB95pQU8D7VQvVuu .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-sB95pQU8D7VQvVuu #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-sB95pQU8D7VQvVuu .sequenceNumber{fill:white;}#mermaid-svg-sB95pQU8D7VQvVuu #sequencenumber{fill:#333;}#mermaid-svg-sB95pQU8D7VQvVuu #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-sB95pQU8D7VQvVuu .messageText{fill:#333;stroke:none;}#mermaid-svg-sB95pQU8D7VQvVuu .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sB95pQU8D7VQvVuu .labelText,#mermaid-svg-sB95pQU8D7VQvVuu .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-sB95pQU8D7VQvVuu .loopText,#mermaid-svg-sB95pQU8D7VQvVuu .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-sB95pQU8D7VQvVuu .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-sB95pQU8D7VQvVuu .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-sB95pQU8D7VQvVuu .noteText,#mermaid-svg-sB95pQU8D7VQvVuu .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-sB95pQU8D7VQvVuu .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sB95pQU8D7VQvVuu .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sB95pQU8D7VQvVuu .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sB95pQU8D7VQvVuu .actorPopupMenu{position:absolute;}#mermaid-svg-sB95pQU8D7VQvVuu .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-sB95pQU8D7VQvVuu .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sB95pQU8D7VQvVuu .actor-man circle,#mermaid-svg-sB95pQU8D7VQvVuu line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-sB95pQU8D7VQvVuu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} loop 每一步 API JSON 请求 1 token 列表 + 采样参数 2 哈希链前缀匹配 算出命中长度 3 请求 + 命中长度 4 按计算配额分配 5 异步取回命中的 KV 块 6 算未命中后缀 + SWA 有界重放 7 新 KV 块落盘 8 交给 decode 9 按并发与 KV 长度均衡 10 KV 传输(P→D) 11 DSpark 草稿 + 验证 12 新 token 13 token 列表 14 流式协议事件 15 decode 产生的 KV 落盘 16
两条最重要的非快乐路径(机制留到深潜):
- SWA KV 缺失 :Block KV 命中了,但 SWA KV 所在机器不可达 → 命中长度回退一个块(128 token)并重放 → 见 05.2 Entrypoint 与 KV 存储。
- Decode 实例下线 / GPU 故障 :1 分钟宽限期后把未完成请求连同 KV 一次性转给其他实例;EP 规模按健康 GPU 数重新确定 → 见 05.5 弹性与容错。
3.4 质量检验
现在你应该能在白板上画出:入口(recipe + Entrypoint)→ 三类均衡器 → 三类服务池 → 共享存储,并说出每个组件为什么必须存在------即使还不知道任何一个组件的内部细节。
下一篇:04-running-example.md --- 贯穿示例 | 返回:00 总览
📚 返回专栏目录