AI

深入理解大模型训练推理过程(2):一个LLM请求的基本处理过程

2026年8月29日 阅读(5)

1.请求通用处理过程

用户 HTTP 请求
    │
    ▼
┌─────────────────────────────────────────────────────────┐
│ ① 接入层:鉴权 → 限流 → 参数解析 → Tokenize            │
└────────────────────────┬────────────────────────────────┘
                         ▼
┌─────────────────────────────────────────────────────────┐
│ ② 调度器:入队 → 资源预估 → 组 Batch → 分配 KV Cache    │
└────────────────────────┬────────────────────────────────┘
                         ▼
┌─────────────────────────────────────────────────────────┐
│ ③ Prefill:整段 prompt 一次性前向 → 生成第 1 个 token    │
│    (算力密集,决定首字延迟 TTFT)                        │
└────────────────────────┬────────────────────────────────┘
                         ▼
┌─────────────────────────────────────────────────────────┐
│ ④ Decode 循环:每步 1 token → 前向 → 采样 → 追加 KV     │
│    (带宽密集,决定生成速度 TPS)                         │
│    ┌──→ 前向计算 ──→ 采样 ──→ 停止判断 ──┐              │
│    └──────────────────────────────────────┘              │
└────────────────────────┬────────────────────────────────┘
                         ▼
┌─────────────────────────────────────────────────────────┐
│ ⑤ 后处理:Detokenize → 敏感词过滤 → 格式化              │
└────────────────────────┬────────────────────────────────┘
                         ▼
┌─────────────────────────────────────────────────────────┐
│ ⑥ 返回:流式 SSE / 一次性 JSON                          │
└────────────────────────┬────────────────────────────────┘
                         ▼
┌─────────────────────────────────────────────────────────┐
│ ⑦ 资源回收:释放 KV Cache Block → 调度器补入新请求       │
└─────────────────────────────────────────────────────────┘

2.基于Hugging Face transformers库的简单代码实现

这段代码虽然只有十几行,但它完整串联了 Hugging Face transformers 库从模板渲染、Tokenization、模型加载、自回归生成到解码的全链路。后续文章我们将以transformers为例,详细解析前述4个阶段的详细代码实现。

from transformers import AutoTokenizer, AutoModelForCausalLM  

path = "./models/Qwen2.5-0.5B-Instruct"

tokenizer = AutoTokenizer.from_pretrained(path)
model = AutoModelForCausalLM.from_pretrained(path)            

messages = [{"role": "user", "content": "你好,介绍一下你自己"}]
text = tokenizer.apply_chat_template(
    messages, tokenize=False, add_generation_prompt=True
)
inputs = tokenizer(text, return_tensors="pt")

outputs = model.generate(**inputs, max_new_tokens=128)

# 只解码新生成的部分
reply = tokenizer.decode(
    outputs[0][inputs["input_ids"].shape[1]:],
    skip_special_tokens=True
)
print(reply)

分析对象版本: transformers 5.15.1(V5 架构,统一使用快速 tokenizer)

3.常见推理引擎介绍及对比

3.1 推理引擎介绍

目前业界主流的推理引擎可以分为三大阵营

1. 纯 GPU 集群高并发引擎(生产服务端)

  • vLLM:目前工业界最主流的开源引擎。核心创新是 PagedAttention(借鉴操作系统虚拟内存分页管理 KV Cache),解决了显存碎片问题,将并发吞吐量提升了 2-4 倍。支持 Continuous Batching。
  • SGLang:后起之秀,UC Berkeley 团队出品。通过 RadixAttention(基数树前缀缓存)在多轮对话、多分支推理(如 Tree-of-Thought)场景下,复用公共前缀的 KV Cache,吞吐量在某些场景下超越 vLLM。
  • TensorRT-LLM (NVIDIA):NVIDIA 官方出品。本质是一个编译器,将模型编译成极度优化的 TensorRT 图。支持算子融合(Fused Kernels)、FP8/INT4 量化、In-Flight Batching。性能天花板最高,但学习曲线极陡,调试黑盒。
  • DeepSpeed-FastGen:微软出品,结合了 DeepSpeed 的 ZeRO 能力与动态 Splitwise 调度(Prefill 和 Decode 分离到不同 GPU),适合超大规模参数模型的推理。

2. 端侧 / CPU / Apple Silicon 引擎(本地设备)

  • llama.cpp:C++ 纯手写实现,无任何第三方依赖。核心是 GGUF 量化格式和针对 x86 CPU (AVX2/AVX-512) 及 Apple Metal 的极致汇编级优化。是 Mac 本地跑 LLM 的绝对标准。
  • MLX / MLX-LM (Apple):Apple 专为自家芯片(M1/M2/M3/M4)设计的 NumPy/PyTorch 替代框架。利用统一内存架构(CPU/GPU 共享内存),无需显式数据拷贝。
  • Ollama:底层是对 llama.cpp 的封装,加上一层极简的 Model Management 和 API Server。让小白也能一行命令跑模型。

3. HuggingFace 官方轻量引擎

  • Text Generation Inference (TGI):HuggingFace 官方的生产级推理服务器。底层用 Rust 写了 Continuous Batching 和 Token 流推送,中间调用定制化的 Flash Attention 算子。深度绑定 HF 生态。

3.2 对比分析

引擎

核心优势

适用场景

部署难度

量化支持

vLLM

PagedAttention,吞吐极高

大并发 API 服务,GPU 集群

GPTQ/AWQ/FP8

SGLang

RadixAttention 前缀复用

复杂 Agent 多轮/多分支推理

GPTQ/AWQ/FP8

TensorRT-LLM

极致单卡/多卡性能,算子融合

追求极限 QPS 的云厂商

极高

FP8/INT4/INT8

llama.cpp

纯 CPU/Metal 优化,零依赖

消费级 PC/Mac 本地运行

GGUF (Q2-Q8)

MLX-LM

统一内存,Apple 原生体验

Mac 开发者本地调试

MLX 格式 (4bit)

TGI

HF 原生兼容,Rust 后端

使用 HF 生态的商业化部署

GPTQ/AWQ/Bitsnbytes

4.推理引擎与 Hugging Face Transformers 库的关系

一句话总结:transformers 提供了“模型骨骼的描述规范”,而推理引擎是“替换了心脏和肌肉的超级赛亚人”。

4.1 关系演变史

  1. 远古时代(2023 前):推理直接用 model = AutoModel.from_pretrained(); model.generate()。此时推理引擎 == transformers + PyTorch。
  2. 瓶颈显现:随着模型变大,transformers 原生的静态 Batch 和朴素的 Attention 算子导致 GPU 利用率不到 10%。KV Cache 显存疯狂 OOM。
  3. 彻底解耦(现在):vLLM/TensorRT 等引擎完全重写了 Forward 过程,只把 transformers 当作“模型结构的初始化配置器”。

4.2 现代推理引擎的“两条路线”

路线 A:绕过 PyTorch,只借用配置(以 vLLM/SGLang 为代表)

  • 不使用 transformers model.forward() 逻辑。
  • 使用 transformers Config 类来初始化网络维度。
  • 底层算子(Attention、RMSNorm、SwiGLU)全部用 C++/CUDA 手写或调用 FlashAttention / vLLM Kernel

路线 B:作为编译器前端(以 TensorRT-LLM 为代表)

  • transformers 定义的模型结构,翻译成 TensorRT 的计算图(IR)。
  • 编译期完成算子融合、精度校准。
  • 运行时完全脱离 PyTorch,执行编译后的二进制引擎。

4.3 推理引擎底层依赖了 Transformers 的哪些模块?

尽管推理引擎重写了计算逻辑,但在模型加载和初始化阶段,它们依然离不开 transformers。具体依赖以下四大模块:

1. Configuration 模块(最核心依赖)

推理引擎必须知道模型长什么样才能分配 GPU 内存和构建计算图。

# vLLM 底层伪代码
from transformers import AutoConfig

# 1. 读取 config.json 获取模型维度
config = AutoConfig.from_pretrained("Qwen/Qwen2.5-7B-Instruct")

# 2. 根据维度分配 KV Cache 显存
num_layers = config.num_hidden_layers       # 依赖此值决定 PagedAttention 的层数
num_kv_heads = config.num_key_value_heads   # 依赖此值决定 K/V Cache 的大小
head_dim = config.hidden_size // config.num_attention_heads
kv_cache_bytes = num_layers * num_kv_heads * head_dim * dtype_size

如果 config.json 缺失或 model_type 未注册,所有推理引擎都会在启动瞬间崩溃。

2. Tokenizer 模块(文本进出的大门)

推理引擎不懂文本,只懂 Token IDs。Tokenize 和 Detokenize 必须与训练时严格一致。

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B-Instruct")

# Prefill 阶段:文本转 ID
input_ids = tokenizer.encode("你好", return_tensors="pt")

# Decode 阶段:ID 转文本(流式输出)
for token_id in generated_ids:
    text = tokenizer.decode(token_id, skip_special_tokens=True)

3. Model Architecture Definition 模块(骨架搭建)

在构建 CUDA Kernel 之前,引擎需要知道权重的名称和形状。

# vLLM 加载权重时的映射逻辑
from transformers import Qwen2ForCausalLM

# 1. 拿到 transformers 定义的模型结构
hf_model = Qwen2ForCausalLM(config)

# 2. 获取所有参数的名称和形状
hf_state_dict = hf_model.state_dict()
# 例如: {"model.layers.0.self_attn.q_proj.weight": [5120, 5120]}

# 3. 引擎根据这个 map,从 safetensors 文件中读取对应的权重
# 然后可能进行切分(Tensor Parallel)或重排,喂入自己的 CUDA Kernel

vLLM 内部维护了一个巨大的 hf_weight_loader 映射表,把 HuggingFace 命名规范的权重(如 q_proj),搬运到自己定义的张量结构(如 q_proj_0, q_proj_1... 用于 TP)中。

4. Chat Template 模块(对话格式渲染)

为了让 API 接收 JSON 格式的对话,引擎必须把对话渲染成模型期望的特殊 token 格式。

# vLLM 内部处理对话请求
messages = [{"role": "user", "content": "hello"}]

# 借用 tokenizer 的 chat_template
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
# 结果: "<|im_start|>user\nhello<|im_end|>\n<|im_start|>assistant\n"

# 然后再送入 tokenizer 进行 encode

4.4 一个极端反例:llama.cpp 完全脱离 Transformers

llama.cpp 是唯一一个几乎不依赖 transformers 的引擎。

  1. 格式隔离:它不读 safetensors pytorch_model.bin,而是用专门的脚本(convert-hf-to-gguf.py)将 HF 模型转换为 GGUF 格式
  2. 结构硬编码:它没有读 config.json 的动态路由机制。Llama、Qwen、Mistral 的架构差异,全是 C++ 代码里用 if-else switch-case 硬编码写死的。
  3. Tokenizer 独立:GGUF 文件内部自带了 SentencePiece 或 BPE 的词表二进制数据,llama.cpp 用纯 C++ 实现了分词,完全抛弃了 transformers 的 Tokenizer。

为什么? 因为 llama.cpp 的目标是:在任何没有 Python、没有 PyTorch、甚至没有操作系统的嵌入式设备上运行。

4.5 Hugging Face Transformers 库在现代推理栈中的定位

模块

在训练/微调中的定位

在现代推理引擎中的定位

AutoConfig

定义超参数

核心依赖:决定显存分配和并行策略

AutoTokenizer

文本处理

核心依赖:保证输入输出的编解码一致性

Modeling_*.py

定义前向传播逻辑

仅作参考:引擎只借用以获取权重形状和命名映射,前向计算全部重写

model.safetensors

保存权重

数据源:引擎从此读取权重,但加载后通常会重新排列以适配自定义 Kernel

结论:transformers 库已经从早期的“全栈推理框架”,演变成了如今 LLM 生态的“元数据注册中心与接口协议制定者”。各大推理引擎在底层算子和调度上已经与它分道扬镳,但在模型权重的序列化规范和配置协议上,依然建立在 HuggingFace 定义的这座地基之上。

You Might Also Like