vLLM 是什么?为什么能让大模型推理性能更好?

21ic电子网 2026-10-29 13:45
vLLM 是什么?为什么能让大模型推理性能更好?

你是一个程序员,想把开源大模型部署起来,对外提供服务。

那很容易想到,可以用 HuggingFace 的 transformers 库把模型加载进来,并对外提供 http 接口,用户在聊天框里发来一个请求,服务就会调一次大模型,然后返回结果。

能跑是能跑。但请求一多,后面的请求就只能排队干等,导致性能很差。那么问题来了,怎样才能在不增加 gpu 的前提下提升模型性能?

没有什么是加一层中间层不能解决的,如果有,那就再加一层。这次我们要加的中间层,就是 vLLM。

你可以将它简单理解为是模型和显卡之间的中间层,通过一系列工程优化让大模型能更好的利用显卡的显存和算力,最终让模型性能翻上几倍。

vLLM 是什么?为什么能让大模型推理性能更好?图1
vLLM 是模型和显卡之间的中间层

它的用法也很简单,执行一行 vllm serve 命令,就能起一个和 OpenAI 接口一样的服务,给启动命令加入不同选项参数,就能得到不同的性能效果。

那么问题又来了,它是怎么做到的?今天我们就假装不了解 VLLM 是什么,将 vLLM 的底层原理和常用参数都讲清楚。

你小子有福了,它是大模型推理性能优化里最经典的一套工程方案,今天一次给你讲透,好好看好好学。

全网资料参差不齐,如有差异,以我为准,所以看之前,你点赞了吗,关注了吗,谢谢!

KV cache 是什么

我们知道,大模型生成文字是一个 token,一个 token 往外蹦的。token 是模型处理文字的最小单位,可能是一个字、一个词,也可能是半个英文单词。模型会给每个 token 算两组数,一组叫 K,一组叫 V。

我们可以把一句话抽象成一个词块数据库。数据库的查询键 key 就是词块本身,简称 K,value 是词块背后的含义,简称 V。

生成的每个新 token,含义都依赖前面整句话说了什么,所以整个生成过程会不断查这个词块数据库里的数据,比如生成第 500 个 token 时,模型要拿着这个新 token,去前面 499 个 token 的 K、V 里查一遍,算出该重点参考谁。而前面那些 token 的 K、V 算一次就定下来了,没必要每生成一个新 token 都重算一遍,存起来直接复用就行,每步只算新 token 自己那一份。

这份按 token 存起来的 K、V 缓存,就是 KV cache。它省下了大量重复计算,但代价是很费显存。以 LLaMA-13B 为例,一个 2048 token 的请求,光 KV cache 就要 1.6 GB,一张 A100 40G 的卡,装完模型权重只剩十几 G,全给 KV cache,也就只够同时处理几个用户请求。

vLLM 是什么?为什么能让大模型推理性能更好?图2
KV cache:旧 token 的 K、V 缓存复用,只算新 token

为什么一个 token 要占这么多显存?LLaMA-13B 每一层要给每个 token 记 4096 个数,K、V 各一份,40 层加起来一个 token 就是 80 万个数,一个数按 2 字节存,一个 token 就是 800 KB。

但模型一次会生成多少 token,事先谁也不知道,所以一些推理框架,比如 Orca,会一次性划一整块能放 2048 个 token 的连续显存给每个请求。

这就带来了新的问题,如果输出的内容写不满,比如只写了 200 个 token,剩下一千八百多个位置就一直空着。

就算空闲显存加起来明明足够下一次请求,但由于找不到一块完整且连续的显存,导致别人也用不了。需要等待请求跑完、显存释放,才能被再次利用起来。

这种空着却用不上的显存,就是常说的内存碎片。导致的结果就是,划出去的显存,其实只有两到四成被真正使用,利用率很低。

vLLM 是什么?为什么能让大模型推理性能更好?图3
内存碎片导致显存利用率只有两到四成

PagedAttention 是什么

那有没有办法把这些碎片利用起来?

有,操作系统的内存管理以前也遇到过类似的问题,它的解法是在物理内存之上抽象出一层虚拟内存。程序申请内存时,拿到的是一整块看起来连续的地址,可这些地址背后的数据,实际被切成固定大小的小页,散落在物理内存的各个角落。虚拟地址和物理地址的对应关系,记在一个叫页表的地方。

KV cache 也可以参考这套方案,把显存切成固定大小的显存小块,每块存几个 token 的 K、V,请求写满一块再给下一块,比如每块放 4 个 token,7 个 token 的 prompt 就占两块,第二块空着的一格,留给下一个要生成的 token。将这些分散在显存各处的小块连起来,抽象出一层「看起来连续」的地址。然后将 token 的逻辑位置和显存实际位置的对应关系,记在一个叫块表的地方,这样就能靠它找到散落的块。

vLLM 是什么?为什么能让大模型推理性能更好?图4
块表记录逻辑块到物理显存块的映射

这样模型生成一个新 token,需要使用前面所有 token 的 K、V 进行注意力计算时。就可以通过块表,把需要的块逐个读出来就行,这样效果其实就跟显存连续存放时一样。

但好处是,每个请求最多浪费最后一块没写满的几格,而且由于块大小一致,也就不存在空洞对不上的问题,显存利用率大大提高。

这套把 KV cache 按页分块存放、按块表读取的注意力算法,就是 PagedAttention。

这些散落的块会被统一收集起来管理,形成一个显存池,请求需要显存块的时候就从池子里领取,用完归还。不断复用,省去了反复申请和释放显存的开销。

我们可以在 vLLM 的启动参数里,通过 --gpu-memory-utilization 设置这个实例最多能占这张卡多少显存,默认是 0.92。注意这个额度不是全给显存池的,装模型权重要占一块,计算过程中临时用的显存也要占一块,剩下的才划给显存池。

那么问题就来了,怎么知道自己设的大小合不合理?

很简单,如果设小了,高并发时池子里的显存块会被快速分光,正在生成的请求需要新块时,就只能先踢出一个请求,把它的块腾出来给别人用,这个机制叫抢占。此时日志里会出现类似这样的抢占日志信息。




1
preempted by PreemptionMode.RECOMPUTE

频繁出现这一信息,就说明池子设太小了,调大一点就好。

另外,我们还可以通过 --max-model-len ,设置每次请求的输入输出的最大长度。设成 auto 会自动选一个放得下的值。业务用不到那么长就主动调小,这样能同时装的请求就更多。

前缀缓存是什么

到这里,我们知道显存块是各个请求,自己领自己用的,但多个请求之间很可能会有一些可以复用的内容,比如类似「你是一个专业设计师」这类系统提示词,每个请求的开头都是它。一千个用户来问,这段开头就被算了一千遍、存了一千份。。。

我们可以给每个写满的块,按它前面的全部内容加它自己的 token 算一个指纹,新请求进来先按指纹查,前面有一样的块就直接复用,连计算都省了。

这种让开头相同的请求复用已算好的块的机制,就是前缀缓存。在 vllm 启动参数里加入 --enable-prefix-caching ,就能打开前缀索引。这里画个重点,基于这个原理,我们写提示词时,如果能把固定内容放前面、变化内容放后面,缓存的命中率就能更高,性能也就更好,提升效果很明显。

vLLM 是什么?为什么能让大模型推理性能更好?图5
前缀缓存复用相同开头

连续批处理是什么

有了 PagedAttention 和前缀缓存的加持,单次请求的计算速度是更快了,但请求一多,后面的请求依旧只能排队干等。怎么提升并发度?

我们知道 GPU 天生是并行计算的,里面几千个计算核心,一次算一个请求跟一次算几十个请求,耗时差不多。

请求挨个处理,大部分核心在闲着,GPU 利用率根本打不满。所以多个请求,完全可以直接凑一起算。

最简单的方法是凑够一批一起跑,跑完再换下一批,这叫静态批处理。

可一批里有的请求生成 10 个 token,有的生成 500 个 token,短的跑完了也得占着位置,等长的跑完,新请求需要等整批结束才能被处理,所以就会慢很多。

那怎么优化呢?既然模型本来就是一个 token 一个 token 生成的,那就把批的单位从一整轮缩到一个 token。每生成一个 token,跑完的请求马上离场、归还显存块,新请求下一步就补进来。

这种每生成一个 token 就重新排一次队的批处理策略,就是连续批处理,而每一步负责决定谁进谁出的组件,就叫调度器。

vLLM 是什么?为什么能让大模型推理性能更好?图6
静态批处理 vs 连续批处理

但就算有连续批处理做调度,在较高并发场景下,

要是其中一个用户,输入超长 prompt 的请求,那也会长时间占用 GPU,导致其他请求只能干等,效果上就是大量用户看到回答吐到一半,就突然卡住了。

为了提升大部分用户的使用体验,我们可以将长 prompt 拆成多个小段,也就是 chunk,分几轮处理,调度器在中间不断穿插其他请求,这样就不用非得等这个长 prompt 全部读完才轮到别人。这个拆段的开关是 --enable-chunked-prefill,模型支持的话默认就开。

而 vllm 的--max-num-batched-tokens,用来控制 长 prompt 拆段时,每轮最多读多少 token,设小一点输出更流畅,设大一点首字更快、吞吐更高,官方建议追求吞吐时设到 8192 以上。

而--max-num-seqs参数,则可以控制一步最多同时算多少个请求,不设的话 A100、4090 这类卡默认 256,H100、H200 默认 1024。

看到这里还没睡着的,弹幕扣个 1,让我看看还有多少人。

量化是什么

我们知道,大模型本质上是由一大堆数字组成的神经网络,训练完的参数就存在这些数字里,业内管它们叫权重。这堆数字动辄几十 G,前面都默认显卡装得下模型,但其实不是所有显卡都装得下。所以对于显存较小的卡,想跑大模型,最直接的办法是降精度。

所谓降精度,就是让每个数字少占一点空间。

比如权重每个数原本需要 2 字节,也就是 FP16,压到 1 字节,就是 FP8, 显存就减半,而且由于计算位数变少,性能也会更快。代价是损失一些精度,但按经验来说这个精度损失一般影响不大。这种降低权重精度来省显存的技术,就是量化,按我多年调优的经验来看,它是所有优化手段里,提升最明显的方法,没有之一。

vLLM 是什么?为什么能让大模型推理性能更好?图7
量化:FP16 压到 FP8,显存减半

此时画面展示是不是应该用小数点后面几位被简化掉来表示画面

它对应 vllm 里的 --quantization参数,下载的已量化模型一般能自动识别,不用手动传参;如果手头只有原版模型又想压成 FP8,则可以传入 fp8_per_tensor 启动时现场转,可选值还有 awq、gptq 这些。同理 vllm 的--kv-cache-dtype fp8,能把 KV cache 也压成 1 字节,这样显存池子能放的 token 数就能翻倍。

GPU worker 是什么

好啦,到这里,我们已经用 KV cache 和前缀缓存避免了大量重复计算,用 PagedAttention 大大提升显存利用率,让一张卡能同时装下更多请求,通过连续批处理把 GPU 利用率打满,再通过量化让小显存的卡也装得下大模型。

这些能力,可以通过一个进程封装起来,就叫 GPU worker,它主要负责将模型权重加载到 GPU 中,并进行一系列计算操作。我们默认一个 GPU worker 负责一张 GPU 卡。

EngineCore 是什么

但对于一些超大 MOE 模型,比如满血版的 deepseek,单张卡显存就是放不下。要是手头没有多卡,可以先用 --cpu-offload-gb 顶一下,传 20 就是借 20 GB 内存放权重,用到哪块搬哪块,但搬来搬去很慢,自己体验还行,正经对外服务扛不住。所以主流做法还是把模型拆到多张卡上,这里有两种拆法。

一种是把每一层的计算切开,多张卡各算一部分、各存一部分权重,叫张量并行,vllm 里有个参数 --tensor-parallel-size,传 2 就是两张卡一起分摊。代价是每层算完,卡之间都要通信,所以最好有 NVLink 这种高速互联。

另一种是按层切,前一半层放一张卡,后一半放另一张,只在交接时传数据,通信少,但请求要依次走过所有卡,延迟高一些,叫流水线并行,对应参数 --pipeline-parallel-size,传 4 就是模型切成四段,放在四张卡上。

vLLM 是什么?为什么能让大模型推理性能更好?图8
张量并行与流水线并行

那么新的问题就来了,多张卡,意味着有多个 GPU worker,

这时候,我们就需要有个角色,负责分配请求到多个 GPU worker 上,负责协调长 prompt 的分段、显存块的分配和抢占。

于是,我们可以将这些调度和管理的能力从 worker 里抽出来,集中放到一个叫 EngineCore的进程组件里。让它负责调度器和相关的管理功能,多个 GPU worker 由它统一指挥,屏蔽了多卡并行的复杂度。

vLLM 是什么?为什么能让大模型推理性能更好?图9
EngineCore 统一指挥多个 GPU worker

vLLM 是什么

好啦,到这里,有了 EngineCore 和  GPU worker 的加持,不管是单张卡,还是几十张卡的集群,都能轻松把大模型跑起来。

在这个基础上加入 api server,对外暴露跟 OpenAI 一样格式的 HTTP 接口,也就成了我们熟悉的大模型 API。

这些能力共同构成了一个高性能大模型推理服务引擎, vLLM。

vLLM 是什么?为什么能让大模型推理性能更好?图10
vLLM 全貌

一个完整的请求流程

接下来,用一个完整的大模型请求将这些概念串一下。

用户发来一句话,请求会先打进 vllm 的 API server,被切成 token,交给 EngineCore。

EngineCore 里的调度器拿到 token,先查前缀缓存,开头相同的部分直接复用。剩下的 token 按需从显存池里领 KV cache 块。然后调度器用连续批处理,让这个请求跟其他几十个请求挤在同一步里,一起交给 GPU worker 去算。

GPU worker 拿到这一批请求,开始用 PagedAttention 逐步推理,算注意力时按块表把这些块在显存里的散落位置找出来,读出来算。

每生成一个 token,就把它追加到序列末尾,作为下一轮计算的输入。大模型就这样逐 token 往外生成,写满一块就再领一块,直到生成结束,把手上所有的块都还回显存池。

vLLM 是什么?为什么能让大模型推理性能更好?图11
一个完整的请求流程

有了 vllm,调用 api server 提供的 /metrics 接口可以观察到很多内部指标。

通过观察指标和调整参数,可以更方便的实现性能调优,

比如,如果你发现 KV cache 使用率接近 1、排队请求一直不为 0、抢占次数持续上涨,那说明池子不够用了,可以把 --gpu-memory-utilization 调大给池子多分点显存,或者把 --max-model-len 调小,卡住请求长度的上限,超长的请求直接拒掉,同样大的池子就能同时装下更多请求,实在不行就开 --kv-cache-dtype fp8,让每个显存块能存放更多的 token;

如果你发现前缀缓存命中率偏低,那就检查下提示词顺序。

现在大家通了吗?

好啦,如果你觉得这期视频对你有帮助,记得转发给你那不成器的兄弟。

视频里提到的一些参数,我收集成了一张表,附带一些使用经验,都评论区见吧。

最后留个问题,多台机器部署时缓存怎么共享?评论区聊聊。

这里是小白 debug,我们聚焦一切可能影响人类历史进程的技术。

如果你感兴趣,记得关注!我们下期见!

常用参数一览

默认值以 vLLM v0.31.0 为准,版本更新快,用之前以自己版本的 vllm serve --help 为准。

档
参数
管的是什么
默认值
必知
--model
跑哪个模型
无,必填
必知
--max-model-len
上下文长度,prompt 加输出的上限
模型自身最大长度
必知
--gpu-memory-utilization
给这个实例多少显存
0.92
必知
--tensor-parallel-size
几张卡一起分摊每一层
1
必知
--max-num-seqs
一步最多同时算几个请求
按显卡 256 或 1024
必知
--max-num-batched-tokens
一步最多处理多少 token
按显卡和用法自动定
常用
--quantization
权重用什么方式量化
读模型配置
常用
--kv-cache-dtype
KV cache 用什么精度存
跟模型一致
常用
--dtype
权重和计算用什么精度
auto
常用
--enable-prefix-caching
开不开前缀缓存
模型支持就开
常用
--enable-chunked-prefill
长 prompt 切不切段
模型支持就开
常用
--block-size
一个显存块放几个 token
按显卡和模型自动选
场景
--pipeline-parallel-size
按层切到几张卡
1
场景
--data-parallel-size
起几份完整模型分摊请求
1
场景
--cpu-offload-gb
借多少 CPU 内存放权重
0
场景
--kv-cache-memory-bytes
直接指定 KV cache 用多少显存
不设
场景
--enforce-eager
不录计算图,省一点显存
关
场景
--trust-remote-code
允许执行模型仓库里的代码
关
服务
--served-model-name
接口里对外显示的模型名
同 --model
服务
--host
 / --port
监听地址和端口
所有网卡 / 8000
服务
--api-key
访问密钥
无
服务
--enable-auto-tool-choice
 + --tool-call-parser
让模型能调用工具
关
服务
--reasoning-parser
把思考模型的思考过程单独拆出来
不设
已删除
--swap-space
以前管换出到 CPU 的内存
新版本已删,照抄会报错

表里有几个视频没细讲的,这里补几句。

--model 指定模型,--served-model-name 是接口里对外显示的模型名,客户端调用时要对上。--host 默认监听所有网卡,服务要对外开放,记得加上 --api-key,不然谁都能调。

模型一张卡放得下、只是请求太多,用 --data-parallel-size 起几份完整模型分摊请求。

显存不够时的报错以 To serve at least one request with the model's max seq len 开头,末尾 the estimated maximum model length is 后面就是能放下的长度。

/metrics 里对应的指标分别是 vllm:kv_cache_usage_perc、vllm:num_requests_waiting、vllm:num_preemptions,命中率用 vllm:prefix_cache_hits 除以 vllm:prefix_cache_queries 算。

--enforce-eager,vLLM 默认会把计算过程提前录成固定的图来提速,这些图要额外占一点显存,开了它就不录,显存紧张时能挤出一点,代价是变慢。

--dtype 默认 auto,跟随模型,V100、T4 这类老卡不支持 bfloat16,会自动退回 float16,一般不用管。

END


vLLM 是什么?为什么能让大模型推理性能更好?图12



最后提一句,21ic论坛(bbs.21ic.com)正在招募原创作者,单篇文章奖励最高500元,欢迎广大网友踊跃投稿!vLLM 是什么?为什么能让大模型推理性能更好?图13 

往期精选:




您的👍对我们很重要
可以点击最下面的💗给小编加鸡腿

关于科技区角:国内科技展会垂直内容策划服务商,提供从论坛内容全案策划、会展市场化IP打造到精准专业观众一站式邀约服务,以产业内容吸引高质量B端人群,打通展会从议题设计、演讲嘉宾邀约、宣传预热、精准邀观到供需对接全链路。
声明:内容取材于网络,仅代表作者观点,如有内容违规问题,请联系处理。
大模型
more
DeepSeek与MiniMax完成合规登记,国产AI大模型出海路径更清晰
融资数亿元,前上海AI Lab大模型负责人创业,打造能自进化的研究基础模型|智能涌现首发
行业首发!算能CV84X6芯片释放大模型推理新势能
数种声源混叠也能精准解析!科大讯飞亮出语音基座大模型SparkAudio 1.0
1058万元,智谱拿下大模型大单
神木交警再回应问界碰撞起火事故;武汉通回应苹果免费开卡安卓端收费15元;大模型MiniMax港股跌破发行价;微软Win11给8GB内存电脑减负...
大模型商业化迎来TaaS时刻!科大讯飞让Token交付结果
谷歌重夺大模型第一,华尔街却不买账
Mistral发布“万亿参数”开源大模型ML4,剑指网络安全主权
AI大模型化身“急救顾问”:山东聊城小伙凭豆包提示抢回父亲生命
Copyright © 2025-成都区角科技有限公司
蜀ICP备2025143415号-1
  
川公网安备51015602001305号