昊梵体育网

DeepSeek 开源推理框架:96% 的输入,都不用重新计算

DeepSeek开源了V4.1Flash背后的推理框架DeepInfer,把一次请求拆成接入、Prefill、Decode三段。顺着技术报告和部署问答看下去,前缀缓存命中率能做到96%,投机解码与异步调度又各自省下一截算力。

刚刚,DeepSeek开源了自家的推理框架DeepInfer,也是当前V4.1Flash所用的那套推理框架;同一时间开源的,还有编解码组件deepseek-recipe

作为背景,这里有一些线上数据:

单个集群每天处理155万亿个token

每次请求平均输入77K个token,其中96%命中缓存,不需要重新计算

平均每张卡每小时的收入是38美元(按谷价计算)

本文则是以原理的角度,结合这份技术报告和仓库里附带的部署问答,给大家讲一下:一个请求发给DeepSeek之后,推理系统是如何一步步把它算完、返回结果的,以及在每一步里,DeepSeek是怎样节省算力的

一次请求,要经过哪些环节

模型处理一次请求,计算分为两个阶段:

Prefill(预填充)模型读取你发来的全部输入,包括系统提示、历史对话、文件和问题。读取的过程中,每个token在模型的每一层都会算出一组中间结果,也就是KVcache

Decode(解码)模型开始生成回答,每次输出一个token。每输出一个token,都要用到前面所有的KVcache

这两个阶段对硬件的要求并不相同。Prefill一次处理几万个token,主要消耗的是计算能力;Decode每次只生成一个token,大部分时间花在从显存中读取参数和缓存上

因此,DeepSeek把两个阶段部署在不同的机器上(这就是常说的PD分离):Prefill使用常见的8卡服务器,Decode使用64到128卡的超节点。如果请求里带有图片,还会先交给单独部署的图像编码服务处理

在实际部署中,两类机器的卡数比例接近1:1。最小可以用一组Prefill加一组Decode运行,但要达到较高的效率,起步规模是64卡Prefill加64卡Decode

请求如何变成token

请求进入系统后,首先由这次一起开源的deepseek-recipe处理

目前主流的API格式有三种:

OpenAI的ChatCompletionsAPI

OpenAI的ResponsesAPI

Anthropic的MessagesAPI

deepseek-recipe会把这三种请求统一转换成同一种对话格式,再按照模型版本拼成prompt、编码成token;模型生成的token,也由它转换回对应的格式,以流式的方式返回

这个过程中,它还处理了两个问题:

防止注入:DeepSeek的模型用一些特殊token标记对话结构,比如用户发言的开始、思考的结束、工具调用的开始。如果用户在输入里手动写了<|User|>这样的字符串,deepseek-recipe会把它当作普通文本编码,模型不会把它识别为结构标记

加快编码:特殊token的位置在拼接prompt时就已经确定,它们之间的几段普通文本可以分别并行编码,从而缩短长上下文请求的分词时间

返回结果时也有类似的处理。比如一个汉字在UTF-8中占3个字节,可能被拆分到相邻的两个token里,deepseek-recipe会先暂存,等字符完整后再输出;工具调用的参数也是边生成边返回,不需要等全部生成完毕

由于deepseek-recipe的处理逻辑与DeepSeek官方API完全对齐,其他人自行部署DeepSeek的模型时,也能获得与官方一致的接口表现

如何做缓存

在Agent场景中,每调用一次工具,客户端都要把完整的历史记录重新发送给模型,包括系统提示、工具说明,以及之前每一轮的回复和工具结果。而其中的大部分内容,在上一轮请求时已经计算过了

DeepSeek的做法是,把计算过的KVcache保存下来,下一轮请求只计算新增的部分

需要注意的是,只有前缀相同(从第一个token开始一致)的内容才能命中缓存,从中间开始的重复内容无法复用

从线上数据看,同一张卡执行Prefill,不计缓存命中时,每秒处理6万个token;计入缓存命中后,每秒处理150万个,相差25倍

这些缓存存放在一个独立的存储集群中,使用的是DeepSeek此前开源的分布式文件系统3FS,容量约100PiB,全部是固态硬盘。KVcache以128个token为一块写入,Agent流量的缓存保留3天,聊天流量保留7天

聊天流量保留得更久,是因为其中有少数缓存会被反复读取很多次,一旦丢失,对整体命中率的影响较大。如果只保留3天,聊天流量的命中率会下降0.5%到1%

之所以使用独立的存储集群,而不是放在计算机器自己的内存里,主要有两方面的考虑:

任何一台Prefill机器都能读取任意一段缓存,分配请求时,不需要把用户固定到上次那台机器上

计算机器的故障率比存储高一个数量级以上。缓存放在存储集群里,即使计算机器出现故障,缓存也不会丢失

读取缓存的过程,同样不能拖慢首字延迟。入口服务只查询元数据,确认能命中多长的前缀;把数据从硬盘读到内存、再传到显存,都在后台完成,并且与计算同时进行。目前线上平均每次输入77K个token,首字延迟平均为400毫秒

如何处理缓存未命中

V4.1Flash的模型中,有一部分层使用了滑动窗口注意力(SWA),每个token只关注距离自己最近的128个token。这部分的KVcache是单独保存的:不写入硬盘,而是保留在计算它的那台机器的内存中,大约3分钟后就会被清除,命中率在98%以上

如果没有命中,V4的做法是精确重算,也就是逐层恢复窗口状态,需要重新计算“层数×窗口长度”个token。为了减少这种情况,V4把这部分缓存也写入了硬盘,结果占用了硬盘缓存近一半的容量

但这部分缓存,只在对话进行中的几分钟内有用,用保存数天的硬盘来存放并不划算

V4.1改用了SWABoundedReplay:只重新计算最后128个token,并且计算时注意力只在这128个token之内进行,得到一份近似的窗口缓存。这样一来,重算的成本是固定的,与上下文长度和模型层数都无关

同样的方法,也用在了模型的另外20层上。这20层的窗口缓存,每次Prefill都需要重新计算,原本要处理最后2560个token,现在只需要处理最后128个,Prefill的总计算量因此减少了近一半

如何加快生成速度

进入Decode阶段后,模型每计算一步,只能生成一个token

投机解码的思路是:先由一个轻量的草稿模块连续猜测5个token,再由大模型一次性验证这5个。猜对的部分直接采用,在第一个猜错的位置,由大模型给出正确的结果。这样,一步计算就能得到不止一个token

DeepSeek自研的投机解码方法叫DSpark,在此基础上又增加了一步:先估计每个猜测被接受的可能性,可能性低的就不再验证,把验证的算力留给其他请求。与固定验证5个相比,线上吞吐提升了6%

此外,在每两步计算之间,CPU需要安排下一步的请求、处理上一步的结果,这段时间里GPU原本处于等待状态。DeepInfer让两者重叠进行:GPU计算第N步时,CPU已经在安排第N+1步

目前线上Decode阶段,每张卡每秒生成14K个token,单个用户的生成速度为每秒230个token,代码场景下为300个

如何做负载均衡

V4.1Flash是MoE模型,模型中有多组“专家”参数,每个token只会用到其中几组。其中,路由专家共有384个

在Decode阶段,DeepSeek把这些专家分布到64张卡上,每张卡存放6个,再额外放1个热门专家的副本,一共7个。每张卡上的专家越少,每一步需要从显存读取的参数就越少,同样数量的卡就能服务更多请求

官方离线测试:64卡一组(蓝)与8卡一组(橙)

热门专家的副本也会动态调整:每1000步统计一次各个专家的负载,每10000步重新分配一次。线上实测,负载最高的卡只比平均水平高9%

请求同样需要均匀分配:

Prefill按输入长度分为4档(16K以下、16K到64K、64K到256K、256K以上),每一档分配多少台机器,根据上一轮的需求动态调整

Decode同时考虑两个因素:每张卡上的请求数量,以及这些请求的缓存总长度。短请求分给请求少、缓存较长的卡,长请求分给缓存较短的卡

通过这些调度,系统整体能达到离线测试中完全均衡状态的80%左右

机器数量也会随流量自动增减:Prefill根据未命中缓存的token数量判断,Decode根据正在处理的请求数量判断。如果一个Decode实例中有一张卡出现故障,整个实例需要重启,重启后用剩余正常的卡重新组成实例

至于能不能跨机房部署,DeepSeek的回答是技术上可行,每8张卡需要配备约400Gbps的互联带宽,但“可能会损失可靠性,跨机房的光纤容易被挖断”

DeepSeek自己的推理节点,部署在不同但相邻的机房里

最后

以上这些,便是DeepSeek推理系统处理一次请求的过程:

把API请求转换成token

Prefill读取输入,能复用的缓存直接从存储中读取

Decode逐个生成token,用投机解码和异步调度加速

把专家和请求均匀地分到每张卡上

这次开源的有两个项目:DeepInfer(Apache2.0协议)和deepseek-recipe(MIT协议)。DeepInfer目前支持DeepSeek-V4.1-Flash,可以运行在英伟达SM100GPU和华为昇腾950上,开源版本提供的是离线推理

上文提到的缓存存储系统、Prefill与Decode的分离部署,以及多副本之间的负载均衡,由于与内部基础设施耦合较深,暂时没有开源。如果要搭建完整的线上服务,这几部分需要自行实现

DeepInfer最初主要基于vLLM构建,也参考了SGLang和TensorRT-LLM。之后DeepSeek新模型的推理代码,也会在这个仓库中持续更新