大模型学习8下-高性能推理引擎vLLM学习笔记

📅 2026/6/28 2:28:36
大模型学习8下-高性能推理引擎vLLM学习笔记
核心概念1.1 背景与问题1.1.1 LLM推理的挑战LLM正加速从云端走向边缘与本地部署背后的驱动力主要来自更低的推理延迟、更强的隐私保护以及更可控的部署成本。与此同时随着模型参数规模和上下文长度不断增长传统推理方案的瓶颈也越来越明显显存利用率低、GPU算力利用率低、并发能力不足并且请求量一旦增加响应延迟就会迅速恶化。这类问题在LLM工程落地中非常常见。模型在单用户或低并发环境下通常表现正常但一旦进入真实生产场景面对十几个甚至几十个并发请求往往就会出现首Token延迟飙升、显存耗尽、吞吐量下降等现象而GPU利用率却始终不高。根本原因在于LLM的自回归生成机制。LLM需要逐Token生成结果并持续维护KVCache来保存历史上下文。KVCache的显存占用会随着上下文长度线性增长而生成长度在推理前又无法准确预知这就使得资源分配高度动态传统优化手段很难奏效。传统推理方案例如直接使用Hugging Face Transformers的model.generate()方法通常采用预先分配策略为每个请求预先分配一整块连续显存空间即便该空间大部分未被使用。这种预留机制造成显存浪费和严重碎片化GPU计算单元频繁等待显存数据访问最终导致吞吐量下降、延迟升高和算力成本上升。vLLM是加州大学伯克利分校团队在2023年开源的高性能推理框架核心目标是提升LLM推理的吞吐量、显存利用率并降低推理延迟。它已经成为Mistral、Qwen、Llama、DeepSeek等主流模型常用的推理后端之一也常被视为面向服务器级GPU的主流LLM推理方案。它的核心性能优势主要来自两项关键技术PagedAttention借鉴操作系统的分页内存管理思想将KVCache切分为固定大小的块统一调度和复用使不同请求能够复用非连续的显存资源从而显著降低碎片率。在实际生产中这种机制通常能减少大量显存浪费。Continuous Batching从调度层面提升GPU利用率。传统推理往往要等一个批次中的所有请求都结束后才能进入下一轮计算而vLLM允许新请求持续加入正在执行的批次各请求独立推进、独立结束不必同步等待。这样一来在相同硬件条件下通常可以带来数倍吞吐提升。除性能优化外vLLM在工程可用性方面也很突出。它原生兼容Hugging Face模型格式并提供OpenAI风格的API接口。开发者只需少量代码或一条vllm serve命令就能快速部署支持流式输出、高并发请求和批处理的推理服务。关于vLLM的定位与适用场景有两点需要明确vLLM是高性能推理引擎不是完整的模型服务平台。监控、日志、自动扩缩容、安全认证、模型版本管理等能力需要由外部系统补齐。vLLM专注于推理优化不涉及模型训练。在轻量级或纯CPU离线推理场景中llama.cpp等方案往往更具性价比。vLLM更适合实时对话系统、多租户模型服务、高并发生成任务以及需要长上下文和流式输出的在线推理服务。在LLM落地实践中模型本身的能力固然重要但承载业务流量的推理系统架构才是LLM工程化落地的核心底座。相关工程问题与解决方案可参考vLLM核心原理与生产实践。1.1.2 KVCache原理与局限原理LLM以自回归方式生成文本也就是逐个Token依次输出。当模型准备生成第N个Token时必须参考此前N-1个Token所包含的全部信息这一能力由注意力机制承担。注意力计算可视为一种查询匹配过程当前待生成的token发出一组Query查询向量意在询问此前内容中哪些部分与当下最相关已存在的每个token均提供一组Key索引标签与Value实际内容。以Query与各个Key的匹配程度作为权重对所有Value进行加权求和所得结果即为当前token应当重点关注的上下文信息。以翻译“The cat sat on the mat”为例。模型已经生成了两个中文词“那只”、“猫”。现在模型要决定第三个中文词是什么。第三个中文词在生成之前先有一个“空位”代表它。这个空位被称为“当前待生成的Token”。模型为这个空位计算出一个Query向量用来询问之前的内容。具体计算这个空位有自己的位置编码和初始向量乘以权重矩阵W_Query得到Query [0.2, 0.8]。这个Query的含义相当于“猫做了什么动作”。每个已存在的英文单词The、cat、sat、on、the、mat都有各自的Key和Value2维向量单词KeyValuecat[0.8, 0.1][0.9, 0.2]sat[0.2, 0.9][0.1, 0.9]其他忽略忽略匹配度计算点积q·k q1×k1 q2×k2Query与cat的Key0.2×0.8 0.8×0.1 0.24Query与sat的Key0.2×0.2 0.8×0.9 0.76加权求和Value × 匹配度再相加cat贡献[0.9×0.24, 0.2×0.24] [0.216, 0.048]sat贡献[0.1×0.76, 0.9×0.76] [0.076, 0.684]结果[0.292, 0.732]这个结果向量被送回空位所在的层。输出层根据这个向量判断概率最高的词是“坐”。于是空位被填充为“坐”。在多层Transformer结构中每一层都会为每个Token分别计算Key和Value。如果每生成一个新Token都重新计算一次全部历史Token的Key和Value计算量会随着序列长度快速膨胀接近平方级增长。为避免这种重复计算vLLM会将每个Token在每一层产生的Key和Value保存下来在后续生成过程中直接复用这些结果。这部分用于存储历史Key和Value的数据结构就是KVCache通常驻留在GPU显存中。生成过程因此可以拆成两个阶段预填充Prefill阶段将整个提示词一次性输入模型并行计算所有Token对应的Key和Value写入KVCache然后生成首个回复Token。解码Decode阶段之后每生成一个新Token只需为新Token计算Query、Key和Value并将新的Key和Value追加到KVCache末尾再基于Query与更新后的缓存计算注意力生成下一个Token。到这里解码阶段的单步计算已经显著降低但新的问题也随之出现。局限随着对话序列长度增长KVCache的显存占用会持续升高。以70B规模模型为例在处理3.2万Token长上下文时单条请求的KVCache可能占用几十GB显存具体数值会受到精度、层数、头数等配置影响。一块NVIDIA H100显卡的总显存约80GB这意味着一条长序列请求几乎可以独占整张卡。传统框架通常为每条请求预先分配一整块连续显存来容纳KVCache这会引发两个明显问题空间浪费与显存溢出并存若按最大长度预分配大部分空间在多数时间内处于空闲状态若按平均长度分配一旦实际输出长度超出预期便会因显存耗尽而触发显存溢出崩溃。显存碎片化每条请求各自占据一块连续显存不同请求的长度和结束时间都不同。当部分请求完成并释放显存后留下的是大小不一、彼此分散的空闲区域。即使剩余显存总量足够新请求也可能因为缺乏足够长度的连续空间而无法启动。这就像一家旅馆按照每位客人可能住的最长天数一次性锁死整层楼的房间。结果大多数客人只住几天大量房间在大部分时间里白白空着偶尔遇到长住客整层楼倒是刚好能被占满。更麻烦的是当一位长住客退房后留下的房间散落在不同楼层彼此不连续。而新来的团队需要的恰恰是一整层连续楼层。于是就会出现一种尴尬的局面总空房间不少但因为不连续怎么也塞不进一个需要整层楼的团队。1.2 vLLM关键技术1.2.1 PagedAttention在LLM中注意力机制需要缓存Key和ValueKVCache显存占用很大。如果直接连续分配容易产生碎片浪费空间并降低性能。vLLM的PagedAttention借鉴了操作系统的虚拟内存与分页机制有效解决了这个问题。操作系统管理内存的基本流程如下可以把操作系统的内存管理想象成书架分块存储内存被切成固定大小的页Page就像书架分成统一格子。按需分配不要求连续程序只分配需要的页这些页在物理内存中可以散落不必连续。映射关系维护系统维护页表记录逻辑页与物理页的对应关系。程序看到的是连续空间但底层可能分散。统一回收消除碎片程序结束后占用的页会被回收放回空闲池。因为分配和回收都是固定大小的页从而避免碎片产生。PagedAttention将这一思想平移到KVCache管理中核心设计包括固定大小的块Block将显存切成大小相同的块每块可存固定数量Token的KV数据。按需分配物理块可分散序列开始时只分配少量块随着Token生成再动态追加。这些块在显存中不必连续。块表Block Table映射每条序列维护一张块表记录逻辑块与物理块的对应关系。注意力计算时通过查表即可找到真实位置。即时回收全局空闲池序列结束或暂停时其占用的块会立即回收并放入全局空闲池供其他请求复用。写时复制Copy-on-Write实现前缀共享多条序列若拥有相同前缀可先共享同一组物理块只有当某条序列需要修改数据时才复制出专属的新块从而避免重复占用显存。凭借这套机制KVCache的显存利用率显著提升分配与回收都变成了轻量级的块操作系统吞吐能力也随之大幅提高。该技术的详细原理与实现可参考Deploy LLMs at Scale with vLLM。1.2.2 Continuous Batching解决显存瓶颈后vLLM进一步把重点放在计算效率上。传统静态批处理通常是先凑齐一批请求统一完成预填充再逐Token生成并且必须等批次内所有请求都结束后才能进入下一轮。这意味着短请求经常要等待长请求GPU也会因为批次内某些序列结束而被动浪费算力。vLLM的连续批处理Continuous Batching更像一个动态拼车系统GPU持续运行一个生成循环每一步只为当前批次中仍然活跃的序列生成一个Token。某条序列完成后立即从批次中移除并归还它占用的KVCache块。同一步调度中系统会从等待队列里拉入新的请求直接插入当前批次。下一步生成会在新旧混合批次上继续执行GPU始终保持较高利用率。在这种情况下短请求不必等待长请求结束完成后也能立刻释放资源。配合PagedAttention灵活的块分配机制新请求可以随时进入执行流程不会因为KVCache无法连续分配而被阻塞。最终vLLM的吞吐量往往能达到传统方法的数倍在线服务成本也会明显下降。高并发调度优化细节可参考vLLM高并发推理优化详解。1.2.3 其他优化措施除了上述两大核心设计vLLM还集成了多项在生产环境中很实用的优化能力自动前缀缓存Prefix Caching自动识别多个请求中的相同前缀例如System Prompt、工具说明或少样本示例并复用对应的KVCache减少重复计算。分块预填充Chunked Prefill将超长提示文本拆成多个小块穿插在解码阶段交替执行避免长输入一次性占满GPU计算资源。FlashAttention-3使用高效注意力内核减少显存读写开销加速Attention计算。PagedAttention专用CUDA内核直接在GPU侧读取块表减少CPU参与调度的开销。多LoRA批量服务在同一批次中并行服务多个不同LoRA适配器的请求适合多任务、多租户场景。投机解码Speculative Decoding先用小模型快速生成候选Token再由大模型验证以提升生成速度。张量并行与流水线并行通过一行参数即可将模型切分到多张GPU上运行便于扩展到多卡甚至多节点环境。智能调度与抢占系统高负载时优先处理短交互式请求并对长序列请求进行适度抢占与恢复以维持整体体验。这些技术协同起来使vLLM不只是一个跑得快的推理工具而是一套更适合生产环境的高效推理引擎。vLLM核心技术与实战落地详解可参考:vLLM Tutorial for Beginners。2 快速上手2.1 安装说明版本兼容vLLM本质上是一个GPU-first推理框架底层高度依赖CUDA Runtime、Triton Kernel、FlashAttention以及PyTorch CUDA等关键组件因此它与NVIDIA GPU生态绑定很深。由于Windows在CUDA工具链、C扩展编译链以及部分底层依赖上的兼容性不如Linux成熟部署时更容易出现依赖缺失、编译失败或运行不稳定等问题。在标准Linux NVIDIA GPU环境下只要完成CUDA和PyTorch等基础依赖安装vLLM通常就能比较顺利地部署。官方一般已经提供集成主要CUDA扩展和推理内核的预编译wheel大多数Linux发行版可以直接通过pip安装无需额外编译。相比之下纯CPU环境难以发挥vLLM的核心优势。PagedAttention主要面向GPU显存带宽和高并发吞吐优化在CPU上很难获得同等级别收益而这一差距在Windows CPU环境中通常会更明显。不过CPU环境仍然可以安装vLLM只是过程更复杂。由于预编译wheel支持有限很多情况下需要从源码编译C和Python扩展模块涉及GCC、CMake、Ninja以及PyTorch等多重依赖约束部分GPU相关算子也会被禁用或降级。在无GPU的CPU推理场景中更适合选择专门面向CPU优化的推理框架例如llama.cpp针对AVX2/AVX512等SIMD指令集优化支持GGUF量化格式在低资源环境下具备更高效率与更低延迟Ollama基于llama.cpp封装提供更友好的模型管理与开箱即用体验Hugging Face Optimum面向Intel生态的系统级CPU推理优化方案可提供更高效的推理加速安装在LinuxCUDA环境下安装vLLM时需要重点关注PyTorch、vLLM与CUDA之间的版本兼容关系。vLLM依赖其支持范围内的PyTorch与CUDA组合运行并基于PyTorch提供GPU计算能力和算子体系进行推理加速。因此一旦PyTorch版本变化底层CUDA相关接口和二进制兼容性也可能变化进而导致vLLM编译失败或运行时无法正常加载。很多表面上的安装问题本质上通常来自PyTorch与CUDA或相关依赖版本不匹配。不同版本的vLLM会限定其支持的PyTorch版本范围而PyTorch本身又与CUDA版本强绑定并进一步影响驱动版本兼容性。在这种链式依赖关系下直接执行pip install vllm该命令会默认安装最新版本的vLLM。如果当前环境中的PyTorch版本不匹配pip在解析依赖时可能会自动调整或升级PyTorch但新版本PyTorch未必与当前CUDA环境完全兼容从而导致运行错误。在安装前应重点核对vLLM与PyTorch的兼容关系可以参考vLLM GitHub Releases来确认具体版本对应关系。如果当前PyTorch版本较低通常需要选择较旧的vLLM版本进行匹配。如果需使用较新的vLLM版本则往往需要同步升级PyTorch与CUDA环境以保证整体兼容。例如PyTorch 2.5.1通常与vLLM 0.7.3版本适配可以这样安装pip install vllm0.7.3对于生产环境更推荐直接使用官方Docker镜像或经过验证的版本组合以降低编译与兼容性风险。如果需要从源码构建vLLM应明确指定release tag并确保当前PyTorch与CUDA组合在官方支持范围内。2.2 模型加载与调用在vLLM中从模型到服务的完整流程通常分为三步模型获取→服务启动→API调用验证。详细内容可参考vLLM快速部署与实战教程。1. 模型获取vLLM支持直接加载Hugging Face或ModelScope上的模型也支持从本地路径加载已经下载好的模型。如果指定在线模型启动服务时会自动下载。生产环境中更推荐提前将模型下载到本地。国内环境常用ModelScope下载示例如下pip install modelscope modelscope download --model Qwen/Qwen3-0.6B --local_dir ./Qwen3-0.6B2. 服务启动无论是本地模型还是在线模型vLLM的启动方式是统一的只需要指定不同的路径。本地模型启动vllm serve ./Qwen3-0.6B --served-model-name Qwen3-0.6B在线模型启动例如直接使用Hugging Face模型时会自动从远程拉取vllm serve Qwen/Qwen3-0.6B --served-model-name Qwen3-0.6B--served-model-name用于指定模型在API中的暴露名称方便后续调用。服务启动后vLLM通常会执行以下操作自动加载tokenizer和模型权重初始化GPU显存分配基于PagedAttention机制启动OpenAI兼容API服务默认端口为8000捕获CUDA Graph形状用虚拟数据预先打包一组GPU操作快照后续直接重放启动后可先查询可用模型列表curl http://localhost:8000/v1/models