# 01 - 已有引擎结构概览

> **审核日期**: 2026-06-07
> **审核目标**: `multimodal/minivLLM/`（实际引擎目录，不移动、不修改）
> **审核目的**: 建立 Wave 1 基线，记录当前文本引擎的模块拓扑、关键路径、已知缺陷

---

## 1. 引擎的整体设计思路

`minivLLM` 是一个从零构建的轻量级 LLM 推理引擎。它的目标不是替代 vLLM 或 SGLang，而是提供一套可审计、可修改、可学习的文本推理最小实现。引擎选型如下：

- **Python + PyTorch**：面向研究和快速迭代，不追求极致的 CUDA kernel 优化
- **HuggingFace Transformers 兼容**：模型配置和权重加载走标准 HF 路径
- **单 GPU + tp_size=1**：当前完全不做张量并行（代码中硬编码 `assert tp_size == 1`）
- **Qwen3-0.6B 为首选模型**：配置硬编码在 `validate_model.py` 中，权重来自 `model_weights/Qwen3-0.6B/`

引擎的代码量很少，总行数约 500 行 Python，因此可以完整地阅读每一个文件而不遗漏细节。

---

## 2. 模块拓扑：从 config 到 logits

整个引擎的调用链如下（自上而下）：

```
Config 对象（minivllm/config.py）
    ↓
Qwen3(cfg) → Qwen3Model(cfg) → Qwen3DecoderLayer(cfg) × N
    ↓                                   ↓
VocabHead (embedding)              Qwen3Attn + Qwen3FFN
    ↓                                   ↓
LMHead (compute_logits)            Attn + RoPE + RMSNorm + Linear + activation
```

### 2.1 配置层 (`config.py`)

`Config` 是一个 Python dataclass，定义了推理引擎的全局参数。关键字段：

| 字段 | 默认值 | 用途 |
|------|--------|------|
| `model` | (必填) | HF 模型路径 |
| `max_model_len` | 4096 | 最大序列长度 |
| `max_num_seqs` | 256 | 最大并发序列数（计划值，未实现） |
| `max_num_batched_tokens` | 8192 | 最大 batch token 数（计划值） |
| `kvcache_block_size` | 16 | KV cache 块大小（paged attention 预留） |
| `num_kvcache_blocks` | -1 | KV cache 块数（-1 表示自动计算） |
| `gpu_memory_utilization` | 0.9 | GPU 内存利用率 |
| `enforce_eager` | True | 强制 eager 模式（不编译） |
| `tensor_parallel_size` | 1 | 张量并行度 |

`__post_init__` 会调用 `AutoConfig.from_pretrained(model)` 加载 HF 配置，并自动覆盖 `max_model_len` 为两者中较小值。

### 2.2 模型层 (`model/qwen3.py`)

这是引擎的骨架。包含五个类：

1. **`Qwen3Attn`**：单个 attention 层，覆盖 Q/KV 投影、RoPE 注入、softmax attention
2. **`Qwen3FFN`**：前馈网络，实现 SwiGLU（gate_up → act → gate_down）
3. **`Qwen3DecoderLayer`**：一个完整的 decoder layer = attention + MLP + 两个 RMSNorm
4. **`Qwen3Model`**：embed_tokens → N 个 decoder layers → final norm
5. **`Qwen3`**：顶层模型 = Qwen3Model + LMHead

所有 forward 都遵循相同的输入协议：`(input_ids, positions)`。没有 KV cache 参数传递，没有 prefill/decode 模式切换。

**关键观察**：`Qwen3DecoderLayer.forward()` 的 residual 管理是正确的：`input_layernorm` 和 `post_layernorm` 各自负责维护 `residual` 张量的更新。

### 2.3 算子层 (`layers/numpy/`)

这层是"手写 numpy 风格"的算子实现，用最少的 PyTorch 代码表达核心操作：

| 文件 | 功能 | 正确性评估 |
|------|------|-----------|
| `attention.py` | MHA + GQA + causal mask | `Attn` 类逻辑正确，但被 `Qwen3Attn` 错误调用 |
| `rope.py` | RoPE 旋转位置编码 | 完全正确，`get_rope()` 带 LRU 缓存减少重复构造 |
| `embedding.py` | Token embedding + LMHead | `Embedding`/`VocabHead` 正确；`LMHead` 含未接线的 prefill 逻辑 |
| `activation.py` | SiLU + Gate 乘法 | `SiluAndMul` 实现正确，但 `Qwen3FFN` 未使用它 |
| `norm.py` | RMSNorm with residual | 正确，支持 fused residual |
| `linear.py` | 简单 Linear 包装 | 正确 |

### 2.4 KV 缓存层 (`core/kv_cache.py`)

`KVCache` 是一个 contiguous buffer，形状为 `(num_layers, max_seq_len, num_kv_heads, head_dim)`。提供 `write()`/`read()`/`reset()` API。

**现状**：完全未被任何模型 forward 引用。整个代码库中没有 `import KVCache` 或 `from ... import KVCache`。

### 2.5 上下文层 (`utils/context.py`)

`Context` dataclass 定义了推理所需的 batch 上下文：

- `is_prefill`：区分 prefill 和 decode 阶段
- `cu_seqlens_q`/`cu_seqlens_k`：变长序列的 cumulative sequence lengths
- `slot_mapping`：token 到 KV cache slot 的映射
- `context_lens`：每个序列的当前长度
- `block_tables`：paged attention 的块表

`set_context()` 函数可设置这些字段，但**从未被调用**。全局 `_CONTEXT` 永远处于默认零值状态。

---

## 3. 模型的 complete forward 路径

以 `validate_model.py` 中的调用为例：

```python
model = Qwen3(cfg).to(device).eval()
input_ids = torch.randint(0, vocab_size, (seq_len,), device=device)
positions = torch.arange(seq_len, device=device)
hidden = model(input_ids, positions)
logits = model.compute_logits(hidden)
```

这条路径不经过 KV cache，不经过 prefill/decode 分叉，不经过 scheduler。是一个纯粹的"单序列、全序列 attention"前向传播。

---

## 4. 引擎当前的能力边界

**能做**：
- 加载 Qwen3-0.6B HF 权重（`validate_model.py` 的权重映射逻辑正确）
- 执行单序列的前向传播（full-sequence attention）
- 与 HF 参考实现比较 hidden states（`cosine_sim > 0.9999`）

**不能做**：
- 增量解码（无 KV cache 接线）
- 批量推理（无 scheduler）
- Paged attention（无 block table 实现）
- 多 GPU 推理（硬编码 tp_size=1）

**有 Bug 需要修复才能运行**：
- `Qwen3Attn.__init__` → `Attn(...)` 参数不匹配（TypeError）
- `Qwen3FFN.act_fn = None` → forward 时 NoneType 调用（TypeError）

---

## 5. 与 vLLM / SGLang 的对比（概要）

| 特性 | vLLM | SGLang | minivLLM (当前) |
|------|------|--------|-----------------|
| Paged Attention | 已实现 | 已实现 | 未实现（仅脚手架） |
| Continuous Batching | 已实现 | 已实现 | 未实现 |
| Prefix Caching | 已实现 | 已实现 | 未实现 |
| CUDA Kernel | 已实现 | 已实现 | 纯 Python（无 Triton/CUDA） |
| 调度器 | 有（preemption, priority） | 有 | 无 |
| 代码量 | 约 100k+ 行 | 约 50k+ 行 | 约 500 行 |

---

## 6. 本节小结

`minivLLM` 是一个结构清晰但功能不完整的文本推理引擎。它的模型拓扑正确，HF 权重映射正确，但有两个构造时 Bug 阻止了实际运行。KV cache 实现存在但未被使用，paged attention 仅有配置/Context 层面的脚手架。这些是后续 Wave 任务需要解决的核心问题。

**下一步学习**：见 `02_attention实现审计.md`（审查 `Attn` 类的具体实现，包括 GQA repeat、causal mask、与 paged attention 的 diff）。
