1. 推理框架入门:为什么选择Nano-vLLM
当我第一次接触大语言模型推理框架时,面对vLLM这样庞大的代码库(超过10万行代码),简直像面对一座无法攀登的高山。直到发现了Nano-vLLM这个轻量级实现,才真正理解了推理框架的核心原理。这个仅1200行Python代码的框架,完美展现了现代LLM推理引擎的关键技术:PagedAttention、Continuous Batching和Prefix Caching。
对于想要深入理解LLM推理底层机制的同学,我强烈建议从Nano-vLLM入手。它剥离了生产级框架的复杂工程优化,保留了最核心的算法逻辑。就像学习编程先理解算法再学优化一样,掌握这个精简版能帮你建立清晰的认知框架。
提示:本文所有示例基于Qwen3模型和PyTorch框架,配套的Jupyter Notebook可在文末获取。建议边阅读边动手实验,效果最佳。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 请求处理全流程解析
2.1 从文字到Token的转换之旅
当用户输入"你好,人工智能"这样的prompt时,框架首先需要将其转换为模型能理解的数字形式。这个过程就像把一篇文章拆解成一个个乐高积木:
python复制from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3")
tokens = tokenizer.encode("你好,人工智能")
# 输出:[101, 2345, 678, 3456, 7890]
有趣的是,不同语言的分词结果差异很大。英文单词通常对应单个token,而中文可能一个字对应多个token。比如"InfraTech"可能被拆分为3个token。这种特性直接影响后续的显存分配策略。
2.2 KV Cache的显存管理艺术
Attention计算需要保存每个token的Key和Value(KV Cache),这就像给每个单词建立专属档案。但显存资源有限,如何高效管理这些档案成为关键挑战。
Nano-vLLM采用类似操作系统的内存分页机制:
- 将显存划分为多个block(页)
- 每个block包含固定数量的slot(页大小)
- 通过block table管理逻辑block到物理block的映射
假设block_size=4,那么"你好,人工智能"(5个token)需要2个block:
code复制Block 0: [token0, token1, token2, token3]
Block 1: [token4, 空, 空, 空]
这种设计带来三大优势:
- 减少显存碎片(外部碎片)
- 避免频繁申请释放(内部碎片)
- 支持不同请求共享block(Prefix Cache)
2.3 请求处理四部曲
2.3.1 Tokenization阶段
将多个用户请求打包成batch处理,就像餐厅同时接收多个订单。这里需要注意:
- 每个请求的token长度可能不同
- 需要记录positions信息供RoPE使用
- 特殊token(如起始符)需要特殊处理
2.3.2 Prefill阶段
模型首次看到prompt时的全量计算:
python复制# 伪代码示例
def prefill(prompt_tokens):
# 分配初始blocks
blocks = block_manager.allocate(len(prompt_tokens))
# 计算attention
output = model(
