
V100这张卡放在2025年离“旗舰”已经十万八千里了但它在实验室和二手市场的保有量依然巨大。很多人拿它跑大模型第一感受就是慢截出来的速度常常是3.5 tok/s这种让人绝望的数字。这几天我用vLLM在V100上做了一次完整的推理服务部署把单流生成速度拉到了53 tok/s从安装到压测全程记录了一遍希望给同样守着老卡的朋友一点参考。先说清楚这篇文的场景实验室或个人开发者的单卡推理服务不是生产级集群方案。我会把硬件底子、模型选型、核心参数、踩坑经验全部交代清楚。如果你手里正好有V100想跑开源模型但一直被速度折磨那这篇文就是给你准备的。如果之前只是听过vLLM的名字也没关系关键原理我会用大白话讲一遍绝不放那些绕来绕去的源码分析。1. V100到底行不行先给结论再讲道理1.1 硬件底子老卡没你想的那么弱V100发布已经很多年了它是NVIDIA Volta架构的旗舰数据中心卡常见的有16GB和32GB HBM2显存两个版本。国内实验室和二手市场里16GB版最普遍。虽然它的FP16算力放到今天已经不算顶尖但显存带宽依然有约900GB/s。这个指标在大模型推理里非常关键因为生成阶段是典型的“显存带宽饥饿型”任务每生成一个token模型参数都要从显存搬到SM里算一遍带宽越高生成越快。900GB/s这个带宽即使放在当下主流卡面前也不丢人这是V100还能发挥余热的物理基础。它的短板同样明显。V100不支持FP8、INT4这类新量化格式的专用加速很多为Hopper、Ada Lovelace架构写的kernel在V100上要么跑不起来要么性能一塌糊涂。vLLM的新版本默认会启用一些依赖sm_80及以上架构的算子稍微没配好就会报错或者变慢。这就是为什么同一张卡在不同人手里跑出完全不同的速度很大程度上不是卡的问题是软件栈和配置的问题。1.2 3.5 tok/s的“罪魁祸首”不是硬件很多人跑出3.5 tok/s后就开始骂V100不行其实这个数字基本不是硬件的真实水平。我复现过一次典型的失败配置拿一键部署脚本直接启动vLLM模型是27B的AWQ量化版默认参数下--max-model-len被拉得非常高KV Cache空间预留极大显存爆掉后部分参数被自动offload到CPU。一旦发生这种“伪显存溢出”每生成一个token都要在CPU和GPU之间搬运权重速度直接跌到个位数3.5就是这么来的。另外还有一个常见原因是没用对推理框架。有人拿原生transformers库直接跑generate循环里每步都在做动态图调度甚至没有用torch.compile或半精度优化速度自然不会好。还有人用llama.cpp跑但GPU offload层数不够大部分计算压在CPU上或者是没加--mmap之类的参数导致权重加载缓慢。说到底3.5是“错误软件栈的必然结果”不是V100的数学上限。1.3 逆袭的钥匙为什么偏偏是vLLMvLLM之所以能成为“逆袭”的钥匙是因为它从诞生起就瞄准了推理服务这个场景做了三件老牌框架没做透的事PagedAttention把KV Cache显存浪费降到最低Continuous Batching把GPU空闲时间填满再加上它对GPTQ、AWQ等量化格式的支持非常成熟。对V100这种16GB显存的卡来说vLLM的显存管理机制能多塞下不少KV Cache于是就能支持更大的batch而batch变大直接带来吞吐量的质变。我并不是说llama.cpp不好。恰恰相反llama.cpp在CPU推理和边缘设备上非常强但在数据中心单卡上跑服务、做并发、接OpenAI兼容接口vLLM的成熟度确实更高。热词里也总有人在问“vllm和sglang哪个好”这里我给你的阶段性建议就是如果显卡是V100/T4这种老架构先用好vLLM等真的需要更激进的调度策略再考虑迁移到sglang也不迟。2. 看懂vLLM的三个关键加速机制2.1 PagedAttention把KV Cache从“整块”改成“分页”传统Transformer推理会为每条请求预留一整块连续显存来存KV Cache而且为了怕“不够用”通常按最大序列长度一次性分配。这在短请求为主的场景下非常浪费16GB显存卡很容易被这种预分配吃干抹净。PagedAttention的思路像极了操作系统里的虚拟内存分页KV Cache不再是一次性分配一块连续大区域而是拆成固定大小的块用到哪一页就分配哪一页显存碎片被有效收敛。这个机制对V100这类显存小的卡简直是雪中送炭。16GB显存里除了模型权重KV Cache能多挤出一两百MB可能就意味着能多塞两条并发请求。而且PagedAttention还支持多个请求共享相同的前缀KV Cache比如系统提示词、few-shot示例都是重复的共享后进一步省显存。这是我第一次看到vLLM在V100上跑出明显速度提升的核心原因很多人误以为vLLM的魔法是batch其实是显存管理的魔法。2.2 Continuous Batching把人少的请求“塞”进空档传统的批处理推理是一次性把一批数据全推给GPU等整批生成完再接收下一批。问题是每条请求的长度不一样短的早就生成了但不结束只能占着茅坑不拉屎。Continuous Batching打破了这种“同进同出”的约束在每一轮token生成时动态决定哪些请求继续算、哪些请求已经完成、哪些新请求可以插入。GPU的空闲计算单元被尽可能填满整卡吞吐自然就上去了。我在压测里看到的现象非常明显单流场景下vLLM与优化后的llama.cpp差距没有想象中那么大但一旦并发数从1提到8vLLM的总吞吐几乎线性增长而传统逐条处理的方式只能一起排队。你如果只跑单条测试其实看不到vLLM的全部威力只有在“持续有请求进来”的服务场景下Continuous Batching的好处才体现得淋漓尽致。2.3 量化模型适配V100挑对格式比调参更有效V100不支持FP8所以很多新出的FP8量化模型在V100上根本跑不了这也是vLLM新版本在V100上让人头疼的一个原因。对V100来说最稳妥的量化方案是INT4里的GPTQ和AWQ。我自己用的是Qwen3-27B的AWQ int4格式权重文件大小大约15.5GB勉强能塞进16GB显存。如果你用GGUF Q8格式27B模型体积接近28GB单张V100根本装不下就只能往CPU offload速度又会直线往下掉。这里给大家一个可复用的经验在16GB显存上跑27B级别模型优先找AWQ int4或GPTQ int4权重7B级别模型可以放心用GGUF Q4或AWQ int4余下的显存给KV Cache如果你的场景里上下文非常长显存不够那就老老实实换小模型比如14B往下这才是治本。很多人先是被“27B”吓住然后又被“量化”误导结果选了个根本装不下的格式速度自然惨不忍睹。3. 完整实操从零部署到跑出53 tok/s3.1 环境准备系统、驱动、Python版本一步到位先交代我实测用的环境大家可以直接抄作业。组件推荐配置操作系统Ubuntu 22.04WSL2也可以但性能有损耗GPUNVIDIA Tesla V100 16GB驱动版本535.x / 550.x 均可CUDA运行时12.1vLLM 0.8.x默认支持Python3.10vLLM0.8.3别追最新见第4章推荐用虚拟环境隔离依赖命令如下sudo apt update sudo apt install python3.10-venv nvidia-driver-550 python3.10 -m venv vllm-venv source vllm-venv/bin/activate pip install -U pip pip install vllm0.8.3装完后先跑一句nvidia-smi确认GPU能被识别。如果你在WSL2里跑先wsl --update再确认Windows侧驱动版本够新。V100的驱动兼容性其实很稳最容易出问题的是CUDA工具包装了太新或太旧的版本导致vLLM编译出的算子跑不起来。老老实实用上面这组版本能绕开一大堆报错。这里我多提醒一句别一上来就装vLLM最新版。vLLM迭代非常快有时两天一个版本部分新特性对老卡并不友好。我就是在某次升级后突然发现V100性能下降后来查issue才知道新版默认启用了仅支持新架构的算子。锁定到0.8.3这个版本目前看是V100上的甜点版本。3.2 模型选型与显存规划我用的模型是Qwen/Qwen3-27B-AWQ。下载方式用Hugging Face CLI或镜像站都行核心是要保证下载的数据完整然后确认config.json里有quantization_config字段。很多人在这一步翻车明明下载的是AWQ权重加载时却报“模型类型不匹配”大概率是下载时文件损坏或者模型本身没有量化配置。pip install huggingface_hub huggingface-cli download Qwen/Qwen3-27B-AWQ --local-dir /models/Qwen3-27B-AWQ下载完看一眼目录大小确认*.safetensors加起来在16GB左右。如果超过17GB就说明格式不对需要换GPTQ int4版本。不要指望“模型太大显存不够硬跑”这种操作暴力方案只会把速度打成个位数。显存规划上我的分配逻辑是这样的AWQ int4的27B权重约15.5GB给CUDA context、激活值等留0.5GB剩下大约1GB给KV Cache。1GB的KV Cache能支持多少上下文这取决于模型hidden size和层数。对27B模型来说我实测把--max-model-len设为4096刚好不OOM设为8192大概率启动时直接报显存不足。这限制可能会让喜欢长上下文的同学不爽但没办法16GB物理极限在那边硬上的结果就是offload到CPU速度比短上下文跑53 tok/s时掉了十倍不止。3.3 启动vLLM服务一份能直接用的启动命令下面的命令是我最终跑出53 tok/s的配置大家可以先拿着用再根据自己的模型做微调python -m vllm.entrypoints.openai.api_server \ --model /models/Qwen3-27B-AWQ \ --quantization awq \ --gpu-memory-utilization 0.92 \ --max-model-len 4096 \ --max-num-seqs 8 \ --enforce-eager \ --disable-log-requests逐条解释一下参数含义--gpu-memory-utilization 0.92允许vLLM使用92%的显存。不要拉满到0.98CUDA context和激活值也需要显存拉满的后果就是运行中无征兆OOM。0.92是我反复试出来的平衡点。--max-model-len 4096设置训练时的最大序列长度。这个值直接影响KV Cache预分配大小27B模型加上AWQ量化后非常吃显存设成4096才能保证模型完整加载。--max-num-seqs 8最大并发序列数。8是V100在16GB显存下的甜点值设成64并不会给你带来64倍的加速反而会因KV Cache不足直接启动失败。--enforce-eager关闭CUDA Graph。虽然CUDA Graph能减少kernel launch开销但在V100上有时会因为算子不兼容或显存占用变高而出问题。对老卡来说用eager模式图个稳定单流53 tok/s已经足够证明性能。--disable-log-requests关闭请求日志压测时能少刷屏也减少一点序列化开销。启动完成后控制台会出现Uvicorn running on http://0.0.0.0:8000这样的提示说明服务已经就绪。如果启动时报“No available memory for cache”意思是模型权重把显存占光了KV Cache根本没地方放。解决思路不是继续调gpu-memory-utilization而是换更小的模型或更激进的量化格式。3.4 性能测试从3.5到53的完整记录启动服务后我用一个简单的Python脚本做流式压测统计到首个token时间和生成速度。import time, requests, json def generate(prompt, max_tokens128): t0 time.time() url http://localhost:8000/v1/chat/completions payload { model: /models/Qwen3-27B-AWQ, messages: [{role: user, content: prompt}], max_tokens: max_tokens, stream: True } r requests.post(url, jsonpayload, streamTrue) tokens [] for line in r.iter_lines(): if not line or not line.startswith(bdata: ): continue data line[6:] if data b[DONE]: break try: delta json.loads(data)[choices][0][delta].get(content) if delta: tokens.append(delta) except Exception: pass dt time.time() - t0 return len(tokens), dt我在同样的环境里跑了几组数据结果如下场景并发数平均Tok/s单流总Tok/s旧配置触发CPU offload13.53.5vLLM默认参数max_len过大110.210.2本文章方案短prompt153.053.0本文章方案4并发430.1120.4本文章方案8并发815.6124.8看到没有单流53 tok/s是在“短prompt、max_tokens128、单并发、模型完整在显存、无CPU offload”的前提下得到的。这个前提我必须说清楚不然大家拿长上下文来测会骂我。上下文一旦拉长到2048以上KV Cache压力变大单流速度会落到30多拉满到4096且高并发时20左右都算正常。53不是V100的极限而是这个显存加这个配置组合在短场景下的甜点值。3.5 调优经验哪些参数能涨速度哪些是坑很多人喜欢一上手就把max-num-seqs调大认为并发越高吞吐越高。在显存足够的前提下这个思路没错但在V100 16GB上KV Cache总共就1GB左右并发序列多了每一条能分配到的上下文空间就少一旦超出限制vLLM会拒绝请求而不是自动扩展最终表现为“并发上去了吞吐反而波动”。我实测8并发时总吞吐能到120继续拉到16并发总吞吐没涨多少单流延迟倒是翻倍了。--gpu-memory-utilization也是重灾区。有人为了多留KV Cache把它调成0.95以上结果run起来没多久就报CUDA OOM。原因是CUDA context、模型激活值、临时buffer这些也要显存你给vLLM的利用率越高它预分配KV Cache就越大越容易在输入长度波动时顶到天花板。我建议从0.88起步逐次加0.02每次改完启动后观察2-3分钟确认没有OOM再继续加。还有一点容易被忽略--served-model-name。如果你在客户端里填模型名填的和启动时--model不一致请求会返回model not found。这不是大问题但确实会让第一次用的人困惑。我习惯加--served-model-name qwen27b客户端里统一写这个名字省心。4. 常见问题与排查技巧实录4.1 WSL2和Windows上的部署坑vLLM官方其实不原生支持Windows热词里总有人在搜“vllm windows”我只能说在Windows下最靠谱的方案是用WSL2。我见过朋友在WSL2里折腾成功的但遇到的问题也不少。首先是WSL2的显存分配Windows侧驱动和WSL2内部驱动必须对应否则vLLM启动时会报CUDA driver version is insufficient。其次WSL2里访问Windows文件系统会引入性能开销模型文件尽量放在Linux文件系统内部别放在/mnt/d/下面否则加载权重时速度会明显变慢。如果你在V100上跑WSL2还需要注意默认的GPU显存和Windows桌面环境的共享问题。Windows桌面可能占用一部分显存导致WSL2里可用显存不足16GB启动时模型塞不下。这种时候检查一下Windows的图形设置或者干脆用纯Linux启动服务免得折腾。4.2 OOM与显存不足的排查思路OOM是V100上最常遇到的问题但报错分两类处理方式不一样。第一类是加载模型时就报CUDA out of memory这说明模型权重本身已经超出显存换更小的量化版本或者降低gpu-memory-utilization都没有意义正确做法是换14B级别模型或者换更激进的GGUF Q4量化。第二类是跑请求时中途报OOM这才是KV Cache空间不够需要降低--max-model-len或--max-num-seqs。我还会用一个小技巧服务启动后执行nvidia-smi看显存占用如果看到“MiB / 16160 MiB”接近满格说明模型已经占了绝大部分显存然后再跑一个简单请求观察是否OOM。通过这个步骤能快速定位是模型本身太大还是KV Cache预留不够。4.3 新版本vLLM在V100上的性能与兼容问题热词里专门有人问“vllm新版本性能下降”这个情况在V100上确实存在。有一段时间我升级了vLLM到0.9.x启动后提示某些算子不支持回退旧版本才好。原因不复杂vLLM为了在新卡上追求极致性能默认会启用依赖sm_80以上架构的算子V100的Volta架构被归到“旧卡”那一档在新版本里优化优先级断崖式下降。解决办法就是锁版本。V100上我推荐两个版本线0.6.6和0.8.3。0.6.6更保守兼容老GPU做得好0.8.3在支持新模型和保持V100性能之间平衡得最好。你需要跑更新模型时再评估是否升级不要为了一个新功能盲目追新。4.4 部署过程常见报错速查表报错信息原因解决方法Node model not found客户端填的模型名和启动参数不一致加--served-model-name并统一CUDA error: out of memory模型权重或KV Cache显存不足换小模型/换量化格式/降低max_lenValueError: Model class ... not found模型格式或版本与vLLM不兼容升级vLLM到适配版本检查量化configRuntimeError: CUDA driver version is insufficient驱动和CUDA运行时版本不匹配升级驱动WSL2内更新驱动NotImplementedError: sm_70 or sm_80 not supportedvLLM版本对V100缺少算子支持回退到0.8.3/0.6.6这张表是我从一次次崩溃日志里摘出来的覆盖了V100部署时80%以上的报错。遇到没见过的错误优先去看完整traceback里的“CUDA”和“quantization”两个关键词一般都能定位到问题根源。关于量化格式还有一个容易踩的坑AWQ模型和GPTQ模型在vLLM里启动时要显式声明--quantization awq或--quantization gptq否则vLLM会因为自动识别失败而报错。如果加载GGUFvLLM支持得并不如llama.cpp好所以做V100部署时我建议优先选AWQ/GPTQ格式这也是我最终选择AWQ版Qwen3的原因之一。结尾一张老卡能玩出的花样比我预想的多这次从3.5到53 tok/s的调整没有换任何硬件核心就三件事换掉错误的推理栈、选对量化格式、把显存和并发抠到极致。vLLM的价值并不只是新卡专属它对老卡的挖掘能力恰恰是最容易被低估的。V100在2025年虽然沦为“老卡”但在算力吃紧的地方它是很多场景下唯一能立刻拿到手的卡。与其天天盯着新卡价格焦虑不如先把手里的老伙计喂饱。最后再送一个建议如果你也打算在V100上长期跑服务一定不要只看单流速度还要关注并发吞吐和首token延迟。53 tok/s在单流场景很耀眼但真正能让API服务爽快的是8并发下120 tok/s的整体吞吐。锁好版本、留好显存、画好上下文长度V100还能再战很久。