Graph Runner、Attention Backend 与执行路径选择#

这章解决什么问题#

执行模型讲到这里,读者通常已经理解了 ForwardBatch -> forward -> sample 这条主循环。但真实 runtime 还有一层很容易让人困惑的问题:为什么同一套执行模型在不同环境下会走不同 graph runner、不同 attention backend,甚至表现出完全不同的约束和限制?如果不补这一层,execution model 章节仍然会显得像“抽象闭环图”,而不像一个真的会在不同硬件与配置下变化的系统。

ModelRunner 为什么不只是一种执行路径#

python/sglang/srt/model_executor/model_runner.py 可以看到,ModelRunner 并不是简单地“直接 forward 模型”。它同时持有 CudaGraphRunnerCPUGraphRunnerPiecewiseCudaGraphRunner 等不同 runner 逻辑,也显式管理 ATTENTION_BACKENDS、hybrid attention backend 以及 capture / replay 相关路径。

这意味着 execution model 并不只是一套抽象控制流,它还包含“在当前环境下应该选哪条执行路径”的选择问题。把这一层省略掉,读者很容易误以为 forward 过程总是同样的,只是速度有快慢;但从源码和文档看,差异远不止速度。

attention backend 为什么会改变理解方式#

官方 docs/advanced_features/attention_backend.md 已经强调,不同 attention backend 有不同的 pros and cons,而且 speculative decoding、deterministic inference、quantized KV cache 等能力对 backend 的要求并不相同。这说明 backend 不是“底层实现细节”,而是会反向影响上层行为边界的执行条件。

例如,如果某个 backend 不支持某类 KV cache 或某种 graph capture 语义,那么你在上层看到的就不只是吞吐差异,而可能是功能边界、行为限制甚至调试路径都不一样。也正因为这样,本章要把 backend 视为 execution model 的一部分,而不是附录说明。

graph runner 在执行链里的位置#

cuda_graph_runner.pycpu_graph_runner.pypiecewise_cuda_graph_runner 这一类路径存在,说明 SGLang 不是总以一种“朴素 eager forward”方式工作。相反,它会根据设备、mode 和配置选择不同 graph runner 来驱动执行。

这层的关键价值,不是替读者穷举所有实现细节,而是解释“为什么同一个 ForwardMode,在不同 runner 下会有不同约束”。例如,某些 graph runner 明确不支持 LoRA、PP、speculative inference 或 gathered buffer;这些限制不是偶然,而是 graph execution 语义的直接结果。

一个更贴近真实系统的执行路径图#

flowchart TD
    A["ForwardBatch / ForwardMode"] --> B{"执行路径选择"}
    B --> C["eager forward"]
    B --> D["CudaGraphRunner"]
    B --> E["CPUGraphRunner"]
    B --> F["PiecewiseCudaGraphRunner"]
    C --> G["attention backend"]
    D --> G
    E --> G
    F --> G
    G --> H["logits / sample / next token"]

这张图要解释的不是“内部类名很多”,而是“execution model 其实还有一层路径选择”。也就是说,ForwardBatch 之后并不总是同一条绝对固定的 forward 过程,而是会先经过 graph runner 和 backend 选择。

tradeoff:统一抽象 vs 多条真实路径#

从写作角度看,把所有 runner 和 backend 差异都展开会很容易把一章写成手册;但如果完全不讲,读者又会得到一个过于理想化的执行模型。因此更合理的策略是:保留统一抽象,同时明确告诉读者它在真实系统里会经过哪些路径分化。

这也是为什么本章不是单纯的“性能章”。它真正补的是“抽象统一、实现多态”这层工程现实。

调试时这一层意味着什么#

如果你看到的现象是“相同逻辑在不同设备或配置下行为不同”,优先就应该怀疑 graph runner 和 attention backend 路径,而不是一开始就怀疑上层 request lifecycle。因为这里控制的是“同一批数据最终怎样被执行”,而不是“请求有没有进入系统”。

这类问题最难的地方,恰恰在于它们常常不是业务逻辑 bug,而是执行路径差异。所以本章的调试价值,在于帮读者把这种差异从“神秘性能问题”重新落回具体 runner 和 backend 选择上。

本章对应哪些代码路径#

这一章最重要的锚点包括 python/sglang/srt/model_executor/model_runner.pypython/sglang/srt/model_executor/cuda_graph_runner.pypython/sglang/srt/model_executor/cpu_graph_runner.pydocs/advanced_features/attention_backend.mddocs/advanced_features/speculative_decoding.mddocs/advanced_features/piecewise_cuda_graph.md

小结#

执行模型不是一条单一路径,而是一套统一抽象下的多条真实执行路径。把 graph runner 和 attention backend 放进 execution model 章节之后,读者才能真正理解“同样的逻辑为什么会在不同环境下表现不同”,而不仅仅把差异理解成性能数字。