Ubuntu上部署vLLM与Qwen3:从环境配置到推理优化全指南

发布时间:2026/9/20 12:32:43
Ubuntu上部署vLLM与Qwen3:从环境配置到推理优化全指南 简介面向在Ubuntu系统上部署vLLM推理引擎与Qwen3 32B大语言模型的开发者这套可运行源码覆盖从环境准备到模型加载的完整参考实现。压缩包共2个文件含HTML说明文档与inscode源码文件整体约5KB轻量易用。已有1014人学习下载。资源重点展示CUDA/PyTorch环境配置、tensor-parallel分片、显存利用率控制等关键参数并提供curl请求示例用于验证推理输出同时整理部署中的常见问题排查思路便于熟悉Linux与深度学习的用户在GPU资源受限条件下快速完成大模型推理部署实验。1. 部署前的思路梳理与环境准备先说结论在Ubuntu上把vLLM和Qwen3跑起来难度并没有想象中那么高真正折磨人的通常不是模型本身而是环境匹配问题。我第一次部署的时候光是在CUDA版本和vLLM版本之间来回折腾就花了大半天后来把思路理顺了半小时就能从零到能跑通推理。这篇文章我会把整个部署过程拆开揉碎从环境准备、源码编写到问题排查给出一套可以直接复现的方案。在动手之前先明确你需要准备什么。硬件方面显卡是刚需。Qwen3系列有多个尺寸的模型从0.6B到235B不等如果你只有一张消费级显卡比如RTX 3090、4090建议选择Qwen3-4B或Qwen3-8B这类中小尺寸模型配合4-bit或8-bit量化显存占用能控制在10GB以内。如果是A100、H100这类大显存卡直接上Qwen3-14B甚至更大都没有压力。至少要保证显卡驱动正确安装nvidia-smi能正常输出这是后续所有步骤的地基。操作系统方面我使用的是Ubuntu 22.04 LTS这也是当前生产环境中用得最多的版本。你要是用20.04或者更新一点的24.04问题也不大但要额外注意系统自带的Python版本20.04默认是3.822.04是3.1024.04是3.12。vLLM目前对Python 3.10和3.11支持最好22.04的3.10就是最优解。24.04自带Python 3.12虽然在最新版本的vLLM上也能用但一些依赖包还没完全跟上容易碰见奇怪的编译报错对新手不太友好。我这里整个方案也默认以Python 3.10为例。注意如果只是为了学习和验证不要用Windows或者WSL去折腾。虽然vLLM官方现在有Windows的预览支持但在Ubuntu原生环境下的稳定性、兼容性和参考资料的数量都是最好的。用虚拟机或者双系统都行生产用途直接裸机装Ubuntu最省心。2. 安装vLLM与CUDA环境配置2.1 用conda管理Python环境避免把系统环境搞乱我强烈建议你用Miniconda来创建独立的虚拟环境。这不是矫情而是vLLM的依赖项非常多包括torch、transformers、flash-attention等一堆包它们之间版本耦合严重。直接在系统Python里装大概率会在某一天因为升级某个包导致vLLM彻底起不来。用conda隔离之后出问题了直接把整个环境删掉重建一样的时间成本完全不影响系统其他Python项目。# 下载并安装Miniconda wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh # 初始化conda然后重开终端 conda init source ~/.bashrc # 创建Python 3.10环境 conda create -n vllm python3.10 -y conda activate vllm这里有个细节要注意conda activate vllm之后先确认一下python --version确实是3.10再继续。有的人系统里可能有多个PythonPATH混乱的情况下conda环境可能没生效后面所有步骤都会跟着出问题。2.2 安装vLLM版本匹配是成功的一半vLLM的安装实际上有两种主要途径pip直装和源码编译。如果你想快速跑通pip直装是首选。pip install vllm但这里就是一个容易踩坑的地方。pip默认会安装当前最新版本的vLLM而最新版本对CUDA版本和PyTorch版本有明确要求。vLLM 0.5.x以上基本都要求CUDA 12.1以上。你可以通过nvidia-smi查看驱动支持的最高CUDA版本但真正决定vLLM能不能跑的是你在conda环境里安装的PyTorch所依赖的CUDA runtime。我个人的做法是先装一个指定CUDA版本的PyTorch再装vLLM这样两者之间不会打架。# 安装PyTorch 2.5.1对应CUDA 12.1 pip install torch2.5.1 torchvision0.20.1 --index-url https://download.pytorch.org/whl/cu121 # 再安装vLLM pip install vllm这样装完之后建议跑一个最小验证脚本确认GPU能被正确识别import vllm print(vLLM version:, vllm.__version__)如果这一步没报错说明vLLM的核心依赖都已经就位了。如果报了类似CUDA error: no kernel image is available的错误说明CUDA版本和PyTorch不匹配这时候不要硬着头皮继续直接删除环境重建换一个CUDA版本的PyTorch再试。2.3 源码编译方式什么时候需要自己编译有些特殊场景下pip直装解决不了问题。比如你的显卡架构比较老比如Tesla P40、GTX 1080这种Pascal架构最新版vLLM官方wheel已经不包含对应的CUDA kernel了这时候就得走源码编译路线。还有如果官方wheel里没有你对应的CUDA版本也需要自己从头编译。源码编译vLLM并不算复杂但耗时比较长我个人的经验是在8核CPU的机器上编译一次大约需要20到40分钟。步骤如下# 拉取源码 git clone https://github.com/vllm-project/vllm.git cd vllm # 切换到你想要的分支比如v0.6.3.post1 git checkout v0.6.3.post1 # 编译安装 pip install -e .在编译之前确保系统有完整的编译工具链和CUDA toolkitsudo apt update sudo apt install -y build-essential cmake sudo apt install -y nvidia-cuda-toolkit提示编译时间和内存高度相关。建议至少给编译过程预留16GB内存否则容易在链接阶段因为内存不足进程被OOM杀掉。我之前就吃过这个亏加了一个swap分区之后才顺利编过。3. 获取Qwen3模型选择合适的下载方式3.1 ModelScope还是Hugging FaceQwen3模型官方同时发布了在Hugging Face和ModelScope上的权重。国内读者建议直接用ModelScope下载速度快且稳定不用额外配置网络代理。如果你是海外服务器用Hugging Face也没问题。如果你是国内服务器需要先安装ModelScope的Python包pip install modelscope然后直接用命令下载模型权重。以Qwen3-8B为例modelscope download --model Qwen/Qwen3-8B --local_dir ./models/Qwen3-8B如果你想在Python脚本中下载也可以用API方式from modelscope import snapshot_download model_dir snapshot_download(Qwen/Qwen3-8B, local_dir./models/Qwen3-8B) print(f模型已下载到: {model_dir})下载耗时取决于网络带宽8B模型大概有16GB权重文件在百兆带宽下大约需要半小时到一小时。3.2 确认模型目录完整下载完成后检查模型目录下有safetensors文件、config.json、tokenizer.json等关键文件。models/Qwen3-8B/ ├── config.json ├── generation_config.json ├── model.safetensors.index.json ├── model-00001-of-00004.safetensors ├── ... ├── tokenizer.json └── tokenizer_config.json如果缺少任何文件vLLM在加载的时候会直接报错这类问题是最容易排查的重新用snapshot_download补下即可。4. 编写可运行的vLLM部署源码4.1 基础版单卡部署Qwen3现在进入最核心的部分写一个真正能跑起来的部署脚本。这个脚本有两种角色一是模型服务端对外提供OpenAI兼容的API二是一个客户端请求脚本调用服务并拿到结果。先从服务端开始。创建一个deploy_qwen3.py脚本from vllm import LLM, SamplingParams from transformers import AutoTokenizer # 指定模型路径这里是上一步下载的本地路径 model_path ./models/Qwen3-8B # 初始化LLM llm LLM( modelmodel_path, dtypebfloat16, tensor_parallel_size1, max_model_len32768, gpu_memory_utilization0.9, trust_remote_codeTrue, ) # 加载对应的tokenizer tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) # 定义采样参数 sampling_params SamplingParams( temperature0.7, top_p0.8, max_tokens2048, repetition_penalty1.05, ) # 准备prompt messages [ {role: system, content: 你是一个乐于助人的AI助手。}, {role: user, content: 请用通俗的语言解释一下什么是大语言模型。} ] # 使用tokenizer应用chat template text tokenizer.apply_chat_template( messages, tokenizeFalse, add_generation_promptTrue ) # 模型推理 outputs llm.generate([text], sampling_params) # 打印结果 for output in outputs: prompt output.prompt generated_text output.outputs[0].text print(f生成的回答{generated_text})这个脚本可以先用小尺寸模型验证流程比如把模型路径换成./models/Qwen3-4B确认输出正常之后再切换到实际部署的大模型避免在调试阶段因为显存不足等各种问题干扰判断。几个关键参数的说明dtypebfloat16现代显卡基本都支持bf16而且比fp16在数值稳定性上更好。如果显卡较老不支持bf16改成dtypefloat16。gpu_memory_utilization0.9表示最多用90%的显存作为KV cache。这个值不要设成1.0留一点余量给模型权重和临时计算图否则容易出现OOM。max_model_len32768Qwen3支持最高128K上下文但上下文越长KV cache占用越大。对于8B模型如果你只有24GB显存建议从32768起步实际用起来再把长度调低或者用量化方案。tensor_parallel_size1表示用一张卡。多卡场景实际就是改这个参数。4.2 服务化部署用OpenAI API格式对外提供服务上面的脚本只是验证模型能跑通。在实际项目中我们通常需要把模型包装成一个HTTP服务让业务代码通过API调用。vLLM自带了一个功能强大的API服务模块一条命令就能启动。python -m vllm.entrypoints.openai.api_server \ --model ./models/Qwen3-8B \ --served-model-name qwen3-8b \ --tensor-parallel-size 1 \ --max-model-len 32768 \ --gpu-memory-utilization 0.9 \ --trust-remote-code \ --host 0.0.0.0 \ --port 8000启动之后可以用curl测试一下curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen3-8b, messages: [ {role: user, content: 你好请介绍一下自己} ], max_tokens: 512 }如果一切正常你会收到一个OpenAI格式的JSON响应里面包含了模型的回复内容。这样你就有了一个标准的大模型推理服务任何编程语言都能通过HTTP请求对接。4.3 源码包结构参考为了让整个项目更规范我建议的目录结构如下qwen3-deploy/ ├── deploy_qwen3.py # 推理验证脚本 ├── start_api.sh # API服务启动脚本 ├── client_test.py # 客户端调用示例 ├── models/ │ └── Qwen3-8B/ # 模型权重目录 └── requirements.txt # 依赖清单其中requirements.txt内容如下vllm0.6.3.post1 transformers4.46.1 modelscope1.20.0版本锁定是个好习惯防止以后升级某个包导致依赖冲突。5. 多卡并行部署与量化实践5.1 双显卡tensor parallel的配置和注意事项如果你的机器有两张或更多显卡通过tensor parallel张量并行方式加载大模型是最常见的方法。Qwen3系列较早的版本比如Qwen3-14B单卡很难跑满精度多卡并行几乎是必须的。在vLLM里开启多卡极其简单把启动参数配置一下就行python -m vllm.entrypoints.openai.api_server \ --model ./models/Qwen3-14B \ --tensor-parallel-size 2 \ --max-model-len 32768 \ --gpu-memory-utilization 0.92 \ --trust-remote-code这里有一个容易踩的坑--tensor-parallel-size 2要求两张显卡型号完全相同、显存大小一致。如果不同型号混插例如一张A100-40G和一张A100-80GvLLM初始化时可能会报错或者在推理过程中因为并行张量切分不均导致CUDA OOM。在双卡部署前先用nvidia-smi检查两张卡是否都是同样的型号和显存。另外双卡部署时gpu_memory_utilization可以稍微调高一点比如0.92到0.95因为两张卡的总显存更大了但每张卡仍要留一部分给通信缓冲和激活值。注意tensor parallel在推理过程中GPU间通信非常频繁需要通过NVLink连接。如果是PCIe连接的卡通信延迟会明显拖慢推理速度尤其当batch size较大时性能甚至可能不如单卡。5.2 用AWQ/GPTQ量化降低显存门槛如果你手头的显卡显存不够大又想跑更大参数的模型量化是绕不开的话题。vLLM原生支持AWQ和GPTQ两种量化格式加载时不需要额外设置量化算法只要模型权重本身就是量化过的vLLM会自动识别。以AWQ量化一个Qwen3-8B模型为例。你需要先下载原始模型然后用AutoAWQ做离线量化pip install autoawq然后写一个量化脚本from awq import AutoAWQForCausalLM from transformers import AutoTokenizer model_path ./models/Qwen3-8B quant_path ./models/Qwen3-8B-AWQ quant_config { zero_point: True, q_group_size: 128, w_bit: 4, version: GEMM } model AutoAWQForCausalLM.from_pretrained(model_path) tokenizer AutoTokenizer.from_pretrained(model_path) model.quantize(tokenizer, quant_configquant_config) model.save_quantized(quant_path) tokenizer.save_pretrained(quant_path) print(f量化模型已保存到: {quant_path})量化完成后把模型路径指向量化后的目录即可。4-bit量化后的Qwen3-8B大约只需要5GB多显存消费级显卡轻松运行。我实测下来AWQ 4-bit在推理速度上几乎没有明显损失内存带宽瓶颈下反而可能因为KV cache占用更小让吞吐量更高。提示量化对推理结果的精度会有轻微影响在代码生成、数学推理等任务上尤其明显。如果模型输出的核心用途是代码生成或数学题解建议优先用8-bit量化或者干脆不量化用更大的显存来换取精度。6. 常见问题与排查技巧实录6.1 CUDA error: out of memoryOOM是整个部署过程中最常出现的错误。遇到这个问题先不要急着加显存按以下顺序排查查看当前进程占用nvidia-smi确认是否有其他进程占用了显存。我见过有人启动了两次API服务两个进程把显存瓜分完毕。gpu_memory_utilization是不是设太高了。如果设为0.95以上加载模型时可能因为临时变量占用直接把显存打爆。建议从0.85开始逐步调高。max_model_len是否过大。上下文长度翻倍KV cache占用也近似翻倍。8B模型在24GB显存下max_model_len131072几乎不可能跑通老老实实降到32768。6.2 模型输出全是乱码或重复词这个问题通常是因为tokenizer没有正确应用chat template。Qwen3系列的模型在预训练时使用了特定的对话格式你必须用apply_chat_template来构造输入把message列表转成模型认识的prompt。如果直接拿纯文本丢进去模型可能会生成大量重复或无意义的token。再一个常见原因是repetition_penalty设置不合理。如果这个值设成1.0也就是不惩罚重复模型在中长文本生成时容易陷入重复循环特别是采样温度偏低的时候。我一般设置1.05到1.1之间。6.3 vLLM的chunked prefill与缓存命中率优化vLLM在较新版本中默认启用了chunked prefill分块预填充目的是把超长的prompt切分成多个chunk与decode阶段的请求交错执行减少GPU空闲。但在某些版本里chunk_size设置不合理会导致GPU利用率波动较大。这个问题在vLLM 0.23.0版本中比较明显。如果你用的是这个版本可以把--chunked-prefill-size参数调大一些比如默认的1024改为2048或4096实测对吞吐量有正向影响。vLLM还有一个prefix caching前缀缓存机制如果你在API调用中多次请求相同的系统提示词前缀vLLM能复用KV cache这个对推理速度的提升非常显著。启动API服务时增加--enable-prefix-caching即可。python -m vllm.entrypoints.openai.api_server \ --model ./models/Qwen3-8B \ --enable-prefix-caching \ --port 80006.4 版本升级带来的行为变化vLLM迭代速度非常快经常一个minor版本升级默认参数行为就变了。比如--gpu-memory-utilization在旧版本中默认是0.9新版本中可能还是0.9但KV cache的计算策略变了。升级前一定仔细阅读release note。如果新版有问题回退到以前的稳定版也是一种完全可行的策略。生产环境不建议追新版本。7. 客户端调用与性能测试7.1 用Python客户端调用API服务跑起来之后业务代码通过HTTP请求即可完成推理。下面是一个Python客户端示例import requests import json url http://localhost:8000/v1/chat/completions headers {Content-Type: application/json} payload { model: qwen3-8b, messages: [ {role: system, content: 你是一个专业的技术文档助手。}, {role: user, content: 用三段话总结vLLM的优点} ], max_tokens: 1024, temperature: 0.6 } response requests.post(url, headersheaders, datajson.dumps(payload)) result response.json() print(result[choices][0][message][content])在实际项目里max_tokens要根据业务需求合理设置。设得太大响应时间会显著变长设得太小长文本生成会被截断。我一般会先测几个典型场景统计平均生成token数再设置一个合适的余量。7.2 用简单的脚本来测吞吐量和延迟部署完成之后用并发工具压一下看看模型服务能不能承受业务流量。对于不熟悉ab工具的人可以直接用Python写一个简单的并发测试import time import requests import json from concurrent.futures import ThreadPoolExecutor url http://localhost:8000/v1/chat/completions headers {Content-Type: application/json} def call_once(i): payload { model: qwen3-8b, messages: [{role: user, content: f请生成一段关于数字{i}的简短介绍}], max_tokens: 256 } start time.time() r requests.post(url, headersheaders, datajson.dumps(payload), timeout120) latency time.time() - start return r.status_code, latency with ThreadPoolExecutor(max_workers8) as executor: results list(executor.map(call_once, range(100))) success [r for r in results if r[0] 200] latencies [r[1] for r in results if r[0] 200] print(f请求数: {len(results)}, 成功数: {len(success)}) print(f平均延迟: {sum(latencies)/len(latencies):.2f}s) print(f吞吐量: {len(success)/sum(latencies):.2f} req/s)吞吐量的数值和显卡性能、max_tokens设置、并发数强相关。我实际测得Qwen3-8B在单张A100-80G上max_tokens256并发8时大概能做到每秒5到8个请求。如果吞吐量远低于预期优先检查显卡utilization是不是打满了用nvidia-smi dmon看实时利用率。8. 最后再分享几个实际部署时的经验这套流程我前后部署了好几次给不同的机器做过方案有些经验是踩过坑才总结出来的。第一不要一上来就跑最大参数模型。先用小模型4B或者8B验证环境把整个流程跑通再切换到大模型。这样排查问题时会省去大量时间因为环境问题和大模型问题往往混在一起很难分清。第二conda环境命名和模型目录命名要规范。我见过有人创建了env环境模型放在model目录一个月后自己都忘了装了什么版本。建议在环境名中加上用途和日期比如vllm-qwen3-202406这样复用的时候一眼就能看懂。第三日志记录非常重要。vLLM的API服务默认会打印请求日志和token使用量注意看一下/v1/models接口返回的内容。日志里通常包含模型加载耗时、GPU显存分配信息等是排查问题的第一手资料。第四如果只是想在个人电脑上快速体验Qwen3也可以考虑Ollama这类更轻量的部署方案。但如果你要的是高并发、自定义采样策略、批量推理这些生产级能力vLLM仍然是最合适的选择。两者并不是互斥的我目前就是Ollama做日常实验vLLM做正式服务。把这一套流程跑通之后你手里就有了一个可靠的大模型推理服务后续不管是接业务API、做模型评测还是继续尝试更大规模的模型并发调优都有了坚实的基础。本文还有配套的精品资源点击获取