02 · 读懂整体架构
先把系统分成两半
nano-vLLM 最容易理解的切法不是“按文件夹”,而是:
- CPU 控制面:接收请求、管理状态、决定本轮执行什么、维护 KV block 元数据。
- GPU 数据面:把控制面的决定变成张量,执行模型、缓存写入与采样。
这种分离能让调度算法不直接操作大张量,也让 GPU 计算路径保持紧凑。
核心模块职责
| 模块 | 文件 | 核心问题 |
|---|---|---|
LLMEngine | engine/llm_engine.py | 整个服务循环如何运转? |
Scheduler | engine/scheduler.py | 这一轮选哪些请求和 token? |
BlockManager | engine/block_manager.py | KV Cache block 如何分配与复用? |
Sequence | engine/sequence.py | 一个请求现在处于什么状态? |
ModelRunner | engine/model_runner.py | 如何构造 GPU 输入并运行模型? |
Qwen3ForCausalLM | models/qwen3.py | Transformer 层如何拼起来? |
Attention | layers/attention.py | K/V 写入哪里,如何读取缓存? |
Sampler | layers/sampler.py | logits 如何变成 token? |
初始化顺序
LLMEngine.__init__() 会:
- 从参数构建
Config。 - 根据
tensor_parallel_size启动额外 worker 进程。 - 在 rank 0 创建
ModelRunner。 - 加载 tokenizer,并把 EOS token id 写回配置。
- 创建
Scheduler。
而 ModelRunner.__init__() 会初始化 NCCL 进程组、设置 CUDA device、构建 Qwen3、加载权重、warmup、分配 KV Cache,并在非 Eager 模式捕获 CUDA Graph。
推荐的源码阅读顺序
不要从 qwen3.py 开始。先读控制流,再读计算细节:
text
llm.py
↓
llm_engine.py
↓
sequence.py → scheduler.py → block_manager.py
↓
model_runner.py
↓
attention.py / sampler.py / qwen3.py当你能口头解释一次请求如何从 waiting 进入 running,再进入 finished,模型结构就不再是孤立代码。
HTML INTERACTIVE LAB02 · 读懂整体架构
单独打开 ↗课后习题等待完成
哪个模块最适合回答“本轮应该执行哪些请求”?
动手任务
打开上游仓库的 8 个核心文件,为每个文件写一句“不超过 20 字”的职责说明,再与本章表格对比。
下一节:Sequence 状态机