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 关系演变史
- 远古时代(2023 前):推理直接用
model = AutoModel.from_pretrained(); model.generate()。此时推理引擎 == transformers + PyTorch。 - 瓶颈显现:随着模型变大,
transformers原生的静态 Batch 和朴素的 Attention 算子导致 GPU 利用率不到 10%。KV Cache 显存疯狂 OOM。 - 彻底解耦(现在):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 的引擎。
- 格式隔离:它不读
safetensors或pytorch_model.bin,而是用专门的脚本(convert-hf-to-gguf.py)将 HF 模型转换为 GGUF 格式。 - 结构硬编码:它没有读
config.json的动态路由机制。Llama、Qwen、Mistral 的架构差异,全是 C++ 代码里用if-else和switch-case硬编码写死的。 - 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 定义的这座地基之上。