<aside>

本文由 AI 主导,人类负责润色

</aside>

<aside> 🧭

**一句话:**DeepInfer 的骨架脱胎于 vLLM,异步调度的思路借鉴自 SGLang,而真正撑起性能的,是 DeepSeek 为 V4.1 专门写的 C++ 调度器、跨 step 修正的元数据,以及模型专用的执行路径。

</aside>

术语表

术语 含义
Sequence 一个请求在引擎中的长期状态:token、采样参数、block table、状态槽、投机解码信息等
SequenceMetadata 本 step 给模型执行侧看的请求视图,记录本轮 seqlen_q、seqlen_k 等
SchedulerOutputs 调度器对执行侧的一轮承诺:跑哪些请求、prefill 还是 decode、哪些请求结束、要做哪些状态或 block 复制
InputMetadata 模型 forward 真正读取的张量包:input ids、position、KV slot、block table、各层专用元数据
ZOS Zero-Overhead Scheduling,DeepInfer 的异步调度:把上一轮 CPU 后处理与当前轮 GPU forward 重叠
MetadataZOS ZOS 下用于修正本轮输入的 GPU 元数据,包括 batch 映射、上一轮采样 token 和接受数量
state cache 每个序列固定大小的状态槽,SWA KV 和部分压缩状态放在这里,与 paged block KV 分开管理

1. 先给出血统:三家各借了什么

来源 可以确认的借鉴 证据强度 DeepInfer 做了什么改变
vLLM LLM → LLMEngine → Worker → ModelRunner 的外层骨架;Sequence、SamplingParams、CacheEngine、Sampler、模型加载与分布式通信等基础模块 强:23 个非 vendor 文件头部写有 Derived from vLLM; modified by DeepSeek. 保留入口与分层,把调度核心、序列状态和元数据准备大量下沉到 C++;模型侧换成 V4.1 专用模块和 DeepSeek kernels
SGLang 异步调度:GPU 执行 forward(N) → sample(N) 时,CPU 同时准备并启动下一轮,再处理上一轮结果 强:官方 Q&A 明确写“参考 SGLang、NanoFlow 的已有实现” 为 DSpark 变长验证增加 GPU 侧长度修正与 batch remap,CPU 只先固定预算
TensorRT-LLM README 只写 additional inspiration 弱:当前代码和 Q&A 没有指出具体模块 只能在理念层面对比,例如 C++ runtime、批调度、CUDA Graph 和通信缓冲,但并不能直接说这些“来自 TRT-LLM”

2. 核心组件:先画出四层边界

整个 DeepInfer 可以按“请求状态 → 调度决策 → 执行准备 → 模型计算”四层来理解:每往下走一层,数据就从上一层的抽象,转换成下一层更方便执行的形态。

flowchart TB
    U["LLM.generate<br>Python 入口"] --> E["LLMEngine<br>请求接入 / step 编排 / 输出处理"]
    E --> S["C++ Scheduler<br>waiting / prompted / running"]
    S --> B["BlockManager + StateManager<br>paged KV + 状态槽"]
    S --> O["SchedulerOutputs + SequenceMetadata"]
    O --> W["Worker<br>forward / post-process / sample 时序"]
    W --> R["ModelRunner<br>InputMetadata / CUDA Graph / Sampler"]
    R --> M["DeepSeekV4 模型<br>Attention / MoE / Engram / YoCo / DSpark"]
    M --> K["DeepSeek kernels<br>FlashMLA / DeepGEMM / DeepEP / TileKernels"]
    W -. "callback" .-> E
组件 主要职责 文件链接
LLM 离线入口:tokenize、为每条 prompt 创建请求、循环调用 LLMEngine.step() 收集输出 llm.py
LLMEngine 校验输入,创建 Sequence,调用调度器,下发 Worker,处理结果和统计;也预留 PD、KV 存储等服务 hook llm_engine.py
C++ Scheduler 维护 waiting、prompted、running;决定 prefill 或 decode;分配 block / state;抢占;处理输出后的状态推进 scheduler.hpp
Worker 组织一步执行:当前轮 forward、上一轮后处理、当前轮采样;ZOS 下把 decode 后处理推迟一轮 worker.py
ModelRunner 把 SequenceMetadata 转成 InputMetadata;选择 eager 或 CUDA Graph;执行模型和 sampler model_runner.py
CacheEngine 分配 GPU paged KV 与 state cache,并向模型暴露逐层缓存接口 cache_engine.py
DeepSeek 模型 逐层执行 V4.1 结构,并在需要时调用 Engram 预取、YoCo 截断、DFlash/DSpark 更新与 sampler deepseek.py

这里有一个和 SGLang 很不一样的地方:**LLMEngine 负责编排,C++ Scheduler 负责决策。**熟悉 SGLang 的话,会很自然地以为 Scheduler 就是主循环,因为 SGLang 的 Scheduler 同时承载了服务事件循环;而在 DeepInfer 里,这部分职责放在了 LLMEngine.step()。

3. 一个请求如何走完一生

下面我们以一个普通的文本请求为例,把主线完整走一遍:输入 prompt,先做 prefill,再进入 decode,直到遇到 EOS 或达到长度上限为止。

sequenceDiagram
    participant User as LLM.generate
    participant Engine as LLMEngine
    participant Sch as C++ Scheduler
    participant Worker as Worker
    participant Runner as ModelRunner
    participant Model as DeepSeek Model
    User->>Engine: add_request(prompt_token_ids)
    Engine->>Sch: add_sequence(Sequence)
    loop 每次 step
        User->>Engine: step()
        Engine->>Sch: schedule()
        Sch-->>Engine: SequenceMetadata + SchedulerOutputs
        Engine->>Worker: execute_model_step()
        Worker->>Runner: execute_main_model()
        Runner->>Model: forward(kv_caches, input_metadata)
        Worker->>Engine: post_process(上一轮)
        Worker->>Runner: execute_sample(当前轮)
        Engine->>Sch: process_outputs()
        Engine-->>User: RequestOutput
    end

3.1 入站:prompt 变成 Sequence

LLM.generate() 会先为每个 prompt 调用 _add_request():如果没有传入 token ids,就先用 tokenizer 编码,再交给 LLMEngine.add_request()。随后 _run_engine() 循环调用 step();等所有请求都结束后,还要再调用一次 flush_inflight_reqs(),把 ZOS 中还没处理的最后一轮输出取回来。

LLMEngine.add_request() 会补齐默认采样参数、写入 EOS、处理多模态 prompt、检查 token 范围,最后创建 Sequence。普通请求直接进入调度器的 waiting 队列;带 structured output 的请求则要先异步构建 matcher,构建完成后才入队。

入口阶段的这些检查,在工程上有两层含义:第一,非法 token 在进入 GPU 之前就被丢弃;第二,Structured Output 的 grammar 编译被移出了主调度路径,不会因为某个复杂 schema 的编译而阻塞整批推理。

先说清楚:SO 异步编译是什么

SO 是 Structured Output(结构化输出)的缩写,指的是要求模型的输出严格符合某种格式,比如一个 JSON schema、一条正则表达式,或者一段 EBNF 语法。实现方式并不复杂:每一步采样之前,根据格式约束算出一张词表掩码(vocab mask),把不合法 token 的 logits 屏蔽掉,模型就只能从合法的 token 里采样。