ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Windows部署vLLM跑Qwen3-8B-FP8:WSL2+Docker实战指南

Windows部署vLLM跑Qwen3-8B-FP8:WSL2+Docker实战指南 Qwen3-8B-FP8这个组合听起来就是个典型的“官方不支持但社区硬要跑”的场景。vLLM的项目文档里明确写着支持LinuxWindows要跑几乎全靠曲线救国。我自己第一次在Windows上折腾vLLM时也一度怀疑是不是该直接装个Ubuntu双系统但后来WSL2 Docker Desktop这条路真正跑通之后才发现其实没有想象中那么复杂。这篇文章就是把我从零开始在Windows上部署vLLM并成功跑起Qwen3-8B-FP8的完整过程记录下来包括路线选型、环境配置、启动参数、实测数据以及中间踩过的各种坑。如果你手里有一张NVIDIA显卡建议16GB以上显存想在Windows环境里搞一个本地的大模型推理服务这篇文章应该能帮你省下不少时间。1. Windows跑vLLM的三条路线为什么我锁定了WSL2 Docker1.1 官方不支持的真相vLLM到底依赖了哪些Linux特性先说清楚一个底层问题vLLM为什么没法在Windows原生环境里直接跑这不是懒是技术依赖的问题。vLLM在推理引擎里有几个关键环节深度依赖Linux生态首先是NCCL这是英伟达的多卡通信库在多卡并行或者张量并行时必须用到而NCCL对Windows的支持非常有限官方只保证Linux环境可用其次是共享内存和fork相关机制vLLM的调度器、tokenizer进程管理用到了这类系统调用在Windows下行为会不一样还有一个是CUDA Graph捕获这是vLLM用来降低推理延迟的核心优化手段它在Windows和WSL2下的表现都跟原生Linux有细微差别。所以结论很直接想用官方支持的路径在Windows上跑vLLM基本只有虚拟机或者WSL2这两条路本质上都是跑在一个Linux环境里。虽然有个别社区开发者通过补丁让vLLM在原生Windows上跑通了单卡推理但稍微一折腾多卡、并发、CUDA Graph就崩风险很大我建议普通用户不要走这条路。1.2 三条路线对比原生Linux、WSL2原生安装、WSL2 Docker我身边不少朋友的第一反应是装双系统觉得“既然vLLM只支持Linux那我直接装个Linux不就行了”。理论上是但实际使用中你很快就会遇到麻烦双系统切换太割裂白天要写文档、开会、用Windows软件晚上为了跑个模型还得重启进Linux来回几趟就烦了。而且双系统下如果Windows和Linux各装一套显卡驱动驱动版本和CUDA配置经常互相干扰踩过一次坑就不想再来一次。第二条路线是WSL2里直接用Python装vLLM。这么做的好处是不用Docker那层抽象看起来“更原生”但代价是你需要手动对齐一大堆版本Python版本、PyTorch版本、CUDA Toolkit、cuDNN、vLLM版本。vLLM发布节奏又特别快经常出现pip install以后换个版本就起不来的情况。尤其是CUDA相关依赖WSL2虽然能复用Windows的GPU驱动但容器内的CUDA Toolchain和PyTorch的预编译包必须匹配这一层版本地狱我实在不想再经历一遍。第三条路线就是我最终选的WSL2 Docker Desktop。Docker镜像把vLLM所有依赖都封装好了CUDA Toolkit、PyTorch、NCCL、vLLM代码全都锁死在镜像里你只需要提供GPU和驱动不用关心内部版本如何排列组合。升级vLLM也简单换个镜像标签重跑一遍就行不会污染本地Python环境。唯一的代价是镜像体积稍微大一点首次拉取要等一会儿但这笔账算下来非常划算。我自己的经验是这条路线的交付周期最短出问题的面最小而且遇到问题查资料时社区案例基本都能对上。1.3 为什么选Qwen3-8B-FP8这个模型模型选型上我其实是考虑了很长一段时间的。8B这个规模在消费级显卡上非常合适24GB显存的RTX 4090可以轻松运行16GB的4080/4080 Super也能跑甚至显存再小一点的卡可以通过调低上下文长度来挤一挤。相比7B模型Qwen3-8B的综合能力明显更强写代码、做结构化输出、多轮对话都要稳不少。FP8则是另一个维度的考虑。FP8相比BF16/FP16模型权重体积几乎减半Qwen3-8B-BF16的权重大约16GB而FP8版本大概8GB多一点直接带来的好处就是显存占用大幅下降KV cache可以留出更多空间推理过程中读取权重的带宽压力也小了解码速度理论上能提升百分之二三十。而且Qwen官方这句“Apache 2.0”的license让我可以放心把它用在内部工具和实验环境里不用纠结商用授权问题。需要提醒的是FP8要发挥真正性能最好在支持原生FP8计算的GPU上跑比如RTX 40系列Ada Lovelace架构及更新的显卡。如果你还在用RTX 30系列vLLM对FP8模型的支持方式会打折扣推理时可能需要反量化或者走兼容路径速度优势就没那么明显了。这种情况下我更建议直接用BF16版本的Qwen3-8B。2. 环境搭建装好WSL2与Docker Desktop并确认GPU直通2.1 硬件驱动检查Windows图形驱动与WSL2的联动在开始之前先确认你的显卡驱动是能支撑这一整套方案的。打开PowerShell或者CMD输入nvidia-smi如果能正常显示显卡信息、驱动版本和显存容量说明基本盘没问题。这里有个很多人不知道的细节Windows上安装的NVIDIA驱动本身就包含了WSL2的GPU支持你不需要在WSL2里面再装一遍驱动。WSL2里的nvidia-smi其实是和Windows驱动通信的。所以只要把Windows侧的驱动更新到比较新的版本WSL2里就能直接用GPU。我的建议是直接用GeForce Experience或者NVIDIA官网的Studio驱动版本别太老至少要是支持CUDA 12.x的近期版本。如果nvidia-smi命令在Windows下直接报错那就先去更新驱动不然后面全是白搭。2.2 安装WSL2与Ubuntu发行版WSL2的安装很简单但有一个前提你的Windows版本要够新。Windows 11基本都支持Windows 10的话需要21H2及以上版本。满足条件后用管理员权限打开PowerShell执行wsl --install这条命令默认会装WSL2内核和Ubuntu发行版。如果系统里之前装过WSL1需要手动指定一下默认版本wsl --set-default-version 2安装完成之后会要求你重启系统重启完会进入Ubuntu初始化界面设置一个用户名和密码。这个用户名密码以后经常要用sudo的时候建议设一个自己记得住的。装完以后建议先把WSL2的内核更新到最新。在管理员PowerShell里wsl --update这一步很多人会忽略但确实遇到过旧内核和最新驱动之间配合出问题的情况。接下来进入WSL2终端确认GPU是否已经能被看到。在Ubuntu终端里执行nvidia-smi如果输出里能看到你的显卡型号和驱动版本恭喜你WSL2的GPU直通已经通了。这一步如果报错多半是Windows驱动太旧更新Windows驱动后再wsl --shutdown重启WSL2即可。2.3 安装Docker Desktop并切换到WSL2后端Docker Desktop是Windows上跑Docker最省心的方式。去 Docker官网 下载安装包安装时一路默认即可但有一个关键选项要留意安装过程中会询问使用哪个后端务必选择“Use WSL 2 instead of Hyper-V”如果当时没选也可以在安装完成后在Settings里改。安装完成后打开Docker Desktop进入Settings - General确认“Use the WSL 2 based engine”是勾选状态。然后进入Settings - Resources - WSL Integration把你要用的Ubuntu发行版开关打开。这一步非常关键如果不开启WSL Integration你在Ubuntu里执行docker命令会提示连不上daemon。一切就绪后在WSL2的Ubuntu终端里验证一下Docker是否能用docker version docker compose version能正常输出版本号就说明Docker Desktop和WSL2的后端已经打通了。2.4 GPU直通验证在容器里执行nvidia-smi装好Docker Desktop之后最激动人心的一步就是验证容器里能不能看到GPU。执行下面这条命令docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi这条命令会拉取一个CUDA基础镜像然后在容器里运行nvidia-smi。如果输出能看到你的显卡说明GPU直通的链路已经完整打通了Windows驱动 - WSL2 - Docker容器。这一步如果报错最常见的提示是could not select device driver with capabilities: [[gpu]]。这个错误多半是Docker Desktop没有正确启用WSL2后端或者你用的还是老版本Docker Toolbox而不是Docker Desktop。另外我建议顺手配置一下WSL2的内存限制不然后面跑大模型很容易触发Linux的OOM killer。在Windows用户目录下新建一个.wslconfig文件如果已有就直接编辑写入如下内容[wsl2] memory32GB processors8 swap16GB这里的memory不一定非得是32GB建议设置为你物理内存的60%-80%左右。比如机器有32GB内存就给WSL2分配20GB左右留一部分给Windows本身不然两边一起争内存谁都不好过。改完配置后要在PowerShell里执行wsl --shutdown然后重新打开WSL2终端配置才会生效。这一步很关键我见过好几个人在WSL2里跑模型时内核直接杀进程就是因为默认内存上限太低。3. 拉起Qwen3-8B-FP8docker run启动参数逐条拆解3.1 拉取vLLM的OpenAI兼容镜像环境准备就绪后就该拉vLLM镜像了。vLLM官方提供了OpenAI兼容的API镜像仓库名是vllm/vllm-openai这个镜像里已经包含了OpenAI API Server启动后可以直接用/v1/chat/completions、/v1/completions这类接口和OpenAI的API格式几乎一致非常方便。docker pull vllm/vllm-openai:latest镜像比较大大概有几个GB首次拉取时间取决于网速。如果你网络拉取慢可以给Docker配置registry mirror加速或者换个时间段再试。拉取完成后用docker images确认一下镜像是否已经就位。3.2 启动参数逐条拆解显存、上下文长度、CUDA Graph接下来是启动容器的核心命令。我直接给出一个经过验证的最简可用版本然后再逐条解释每个参数的含义docker run -d \ --name vllm-qwen3 \ --gpus all \ --ipchost \ --shm-size2g \ -p 8000:8000 \ -v ~/docker_volumes/hf_cache:/root/.cache/huggingface \ -e HF_ENDPOINThttps://hf-mirror.com \ vllm/vllm-openai:latest \ --model Qwen/Qwen3-8B-FP8 \ --served-model-name qwen3-8b-fp8 \ --gpu-memory-utilization 0.85 \ --max-model-len 32768参数逐个说一下--gpus all把宿主机所有GPU都暴露给容器。对于只要跑单卡的场景这个参数是必须的否则容器内看不到GPU。--ipchost使用宿主机的IPC命名空间。vLLM的多进程通信会用到共享内存不额外设置时容器默认的IPC隔离可能导致内存映射失败加了这个参数能规避很多莫名其妙的问题。--shm-size2g设置容器的共享内存大小。PyTorch的DataLoader或者一些tokenizer操作会用到/dev/shm默认64MB太小起容器的时候设一个2GB比较稳妥。-p 8000:8000端口映射。把容器里的8000端口映射到Windows宿主机的8000端口这样你在Windows浏览器或者Postman里直接访问localhost:8000就能打到API服务。-v ~/docker_volumes/hf_cache:/root/.cache/huggingface目录挂载。这个是我强烈建议加的。vLLM首次启动会从HuggingFace下载模型权重如果不做持久化挂载每次新建容器都要重新下载。这里挂载的是WSL2内部的文件系统路径不是/mnt/c那种Windows路径。原因很实在WSL2读取Windows文件系统9P协议的I/O性能会比ext4原生文件系统差很多模型文件动辄几个GB如果挂在/mnt/c下加载模型的时候能明显感觉到慢。所以路径我放在了WSL2的Linux文件系统里。-e HF_ENDPOINThttps://hf-mirror.com设置HuggingFace镜像地址。如果的网络环境访问HuggingFace不稳定这一个环境变量能拯救你于水火之中。设置后vLLM下载模型时会自动走镜像站。接下来是容器后vLLM服务本身的启动参数--model Qwen/Qwen3-8B-FP8指定HuggingFace上的模型ID。vLLM会自动检测这个模型的量化格式FP8并匹配对应的加载逻辑。--served-model-name qwen3-8b-fp8这是API中model字段的展示名字。默认会直接用Qwen/Qwen3-8B-FP8这个带斜杠的完整ID但很多API客户端对斜杠处理不友好所以我自己设了一个短名字。后续请求时model字段传qwen3-8b-fp8就行。--gpu-memory-utilization 0.85这个参数控制vLLM最多能用多少比例的显存来分配KV cache。0.85意味着vLLM会把85%的显存用于模型权重和KV cache剩余的留作激活和备用。这里值的取舍是有讲究的设得太高比如0.95虽然能让KV cache更多但也容易在并发峰值时显存溢出设得太低比如0.6又会限制并发能力。24GB显存的卡0.85是我实测比较稳的一个值。--max-model-len 32768设置模型支持的最大上下文长度。Qwen3-8B本身的上下文窗口是128K以上但实际能开多长取决于你的显存。max-model-len设得越大KV cache预留的显存就越多。在24GB显存的卡上配合0.85的显存利用率32K是一个非常推荐的起点。如果显存紧张可以用16384甚至8192换取更多并发空间。启动完成后用docker logs vllm-qwen3查看日志。首次启动会有模型下载过程需要等待一段时间。当日志中出现以下关键信息时基本就能确定服务已经起来了INFO: Uvicorn running on http://0.0.0.0:80003.3 首次启动日志怎么读模型加载、量化检查很多人看到一屏日志不知道看什么我分享几个关键点。在日志里搜索这几个关键词Loading model weights说明已经开始加载模型权重。FP8版本的权重文件大概8GB左右加载速度取决于磁盘I/O和是否已经有缓存。# GPU blocks这是KV cache分配完成后显示的数字代表显存里实际划分了多少个KV cache块。数字越大能支持的并发序列和上下文就越多。# Maximum concurrency这个数字告诉你当前配置下最多支持多少并发序列。如果并发超出这个值vLLM会自动排队处理。还有一个值值得我特别提一下日志中段会出现类似“Using FP8...”的字样这是vLLM识别到模型量化格式后自动启用了FP8计算路径。如果你发现日志里根本没提FP8或者提示的是“dequantize”之类的词那就要留个心眼了如果是老一点的显卡可能走的是兼容路径性能影响比较大。3.4 验证推理curl调用v1接口及思考模式说明服务起来之后我们先用最朴素的curl验证一下能不能正常推理。在Windows PowerShell或者WSL2终端都可以执行curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen3-8b-fp8, messages: [{role: user, content: 用一句话介绍你自己}], max_tokens: 256 }如果一切正常你会收到一个JSON格式的响应里面包含了choices数组每个choice里有message.content字段就是模型生成的回答。这里有一个Qwen3系列独有的点需要特别说一下Qwen3模型默认带有思考模式thinking在生成最终回答之前它可能会先输出一段think.../think的内容然后再输出正常回答。这个设计是为了让模型在回答问题前推理得更充分但也意味着同样的请求开启思考模式会多用不少时间和token。如果你希望API返回内容更干净、更短可以在请求体里加上chat_template_kwargs来关闭思考模式curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen3-8b-fp8, messages: [{role: user, content: 用一句话介绍你自己}], max_tokens: 256, chat_template_kwargs: {enable_thinking: false} }关闭思考模式后模型直接输出最终答案响应速度和token消耗都更可控。我平时做测试和跑一些标准任务时默认就是关掉的只有要分析复杂推理问题时才会打开。4. 实测表现显存占用、推理速度与并发吞吐4.1 单请求实测数据RTX 4090 24GB服务跑通之后我第一时间做了几轮性能测试。先说硬件环境RTX 4090 24GBCPU是i9-13900K内存64GBWindows 11 WSL2 Docker Desktop模型按3.2节参数启动。单请求场景的实测数据如下供大家参考场景显存占用Prefill速度Decode速度max_model_len32768, gpu_mem_util0.85约19GB约3500 tokens/s约140 tokens/smax_model_len16384, gpu_mem_util0.90约17GB约3500 tokens/s约145 tokens/s关闭thought模式短文本问答--约160 tokens/s这个“Decode约140 tokens/s”是什么概念一秒钟大概能输出140个token换算成中文字符大概是每秒100字左右日常对话里体感就是“一段话三秒读完”整体流畅度已经非常接近本地推理的体验上限了。对比一下在Ollama里跑同尺寸模型的解码速度vLLM的continuous batching和PagedAttention优势还是比较明显的。有意思的是如果把max-model-len从32768降到16384decode速度并没有质的提升因为单序列decode主要瓶颈在权重读取带宽不是KV cache的大小。速度真正的提升来自于FP8本身的权重减半——同样的带宽下读一半的数据当然更快。4.2 并发压测与参数调整方向单请求速度只是基础vLLM真正强的地方在于高并发下的吞吐。我用一个简单的Python脚本同时发8个异步请求每个请求生成500个token验证一下并发表现。import asyncio import aiohttp async def ask(session, i): payload { model: qwen3-8b-fp8, messages: [{role: user, content: 讲一个有趣的故事不少于300字}], max_tokens: 500, chat_template_kwargs: {enable_thinking: False} } async with session.post(http://localhost:8000/v1/chat/completions, jsonpayload) as resp: data await resp.json() return len(data[choices][0][message][content]) async def main(): async with aiohttp.ClientSession() as session: results await asyncio.gather(*[ask(session, i) for i in range(8)]) print(results) asyncio.run(main())8并发实测下来的结果是总吞吐量大概在500 tokens/s左右单请求的响应时间有所上升但不会有排队的挫败感。这个吞吐量意味着如果你把vLLM作为一个内部的Agent服务来用同时对十几个客户端提供响应压力也不大。并发场景下需要注意一个参数--max-num-seqs默认值是256它控制了最多同时有多少个序列参与调度。并发量比较大的话可以显式设置一个合理的值比如64或者128避免太多请求同时涌入导致KV cache不够用而触发排队或报错。但如果没有那么多并发需求保持默认就行不需要刻意调小。4.3 不同显存容量的建议配置不是每个人都有24GB的4090所以我整理了不同显存容量下推荐使用的启动参数方便大家对照调整显存容量推荐模型gpu_memory_utilizationmax_model_len备注24GBQwen3-8B-FP80.8532768推荐配置兼顾质量和上下文16GBQwen3-8B-FP80.9016384显存刚够上下文需控制12GBQwen3-8B-FP80.908192能用但上下文偏短考虑7B8GBQwen3-8B-FP80.924096非常紧建议选更小的模型这里说一个我自己的观点显存越小的卡越要考虑FP8的意义。12GB/16GB的卡跑BF16版本可能连16K上下文都开不出来但FP8版本就能在16K甚至32K之间找到一个舒服的平衡点。所以如果你的卡刚好处于这种“高不成低不就”的显存区间FP8其实是最合适的模型选择。5. 踩坑实录从驱动报错到OOM的完整排查链路5.1 启动阶段CUDA driver版本过旧、CUDA graph捕获失败我在整个部署过程中遇到的最烦人的几个问题挑出来逐个还原一下排查链路。第一个坑是启动时直接崩日志末尾有一行报错RuntimeError: Found no NVIDIA driver on your system. Please check that you have an NVIDIA GPU and installed a driver from http://www.nvidia.com/Download/index.aspx这个报错在WSL2环境里挺迷惑的因为你在宿主机里nvidia-smi明明能看到显卡。问题其实出在Windows驱动版本太旧或者WSL2内核与驱动版本不匹配。解决方式是先到NV官网下载最新驱动注意驱动是装在Windows里的不是装进WSL2安装完成后在PowerShell里执行wsl --shutdown再重新打开WSL2终端用nvidia-smi确认能看到显卡然后再启动容器。顺序不能乱要确保先驱动后WSL2。第二个坑更隐蔽。vLLM启动日志走了一半然后报出CUDA graph相关的错误RuntimeError: CUDAGraph failed to capture这个问题在WSL2下出现的概率比原生Linux高因为WSL2的GPU虚拟化层对CUDA graph的支持不如原生环境那么稳定。解决方案是在启动参数里加上--enforce-eager这个参数会关闭CUDA graph捕获改用eager模式执行。代价是单请求延迟会略微增加但换来的是启动稳定性和兼容性。我在WSL2下长期运行就用这个参数其实在8B模型这个量级上速度差异感知不强。第三个坑是启动日志里反复出现“Downloading model”然后卡住不动。这个十有八九是网络问题HuggingFace的域名在某些网络环境下根本连不上。解决方式就是3.2节里提到的HF_ENDPOINThttps://hf-mirror.com环境变量。设置之后模型下载会走镜像站速度还快很多。如果下载到一半中断不用担心vLLM会重新下载完整文件因为HuggingFace的缓存机制是分文件断点续传的下次启动会自动跳过已下载的部分。5.2 运行阶段内存不足、模型下载卡住服务跑起来之后真正的高压时刻是在跑长上下文或高并发时出现的OOM。有一次我把max-model-len调高到65536然后开始连续发请求没过多久容器日志里出现CUDA out of memory. Tried to allocate 2.00 GiB (GPU 0; 24.00 GiB total capacity; 20.11 GiB already allocated; ...)这类问题的排查思路是先用nvidia-smi看当前显存占用确认是模型权重KV cache把显存吃满了还是某个瞬间的峰值把最后的空闲显存挤爆了。如果是前者就需要降低gpu-memory-utilization或max-model-len给临时分配留出空间如果是后者可以在客户端那边限制并发并调低请求的max_tokens。我自己的建议是gpu-memory-utilization不要设到0.95看似很激进地利用了所有显存但一旦遇到突发流量就很容易触发OOM不如留出5%到10%的缓冲空间来得稳。另外还有一个很容易被忽略的OOM是WSL2层面的内存不足而不是显存。症状是容器日志里出现Killed字样或者Docker容器突然退出。这是因为WSL2有全局内存上限如果宿主机的内存也不大跑vLLM的同时再开浏览器、编辑器、编译任务Linux内核会直接杀掉占用内存最多的进程。排查方式是在Windows资源监视器里看内存占用如果超过90%就是WSL2分配的内存不足。这个时候要么加大.wslconfig里的memory值要么给WSL2加点swap要么干脆关掉一些占用内存的Windows应用。5.3 WSL2本身的坑内存上限、容器自启动WSL2的内存上限这个问题我再多说几句因为它真的很隐蔽。默认情况下WSL2会使用宿主机50%左右的内存但如果Windows版本或配置比较特殊可能只有8GB。跑Qwen3-8B-FP8时模型权重加KV cache占用显存不是问题但推理过程中的激活值、tokenizer、Python进程和CUDA context都会占用系统内存。如果WSL2内存上限低就很容易出现整机卡顿或OOM。正确姿势是手动创建.wslconfig文件并明确指定memory和swap写完一定要执行wsl --shutdown再重启WSL2否则不会生效。验证是否生效的方式很简单在WSL2里执行free -h看total的大小是不是你设定的值。容器自启动也是一个日常使用中的痛点。如果用docker run -d方式启动Docker Desktop重启后容器默认是不会自动拉起的。想让vLLM服务在Windows开机后自动就位可以给容器设置重启策略docker update --restart unless-stopped vllm-qwen3这样只要Docker Desktop一启动容器就会自动恢复运行不需要每次手动docker start。6. 日常使用与下一步扩展6.1 把它变成一个常驻本地服务如果vLLM服务只是为了偶尔跑个测试那Docker怎么start/stop都无所谓。但如果你想把它作为一个常驻的本地AI服务比如给内部工具、脚本甚至一个自己搭的Web应用提供LLM能力那就要考虑一些日常管理问题了。我建议给它设置一个固定的启动命令可以把3.2节的docker run命令保存成一个shell脚本每次重建容器时直接执行避免手敲参数时出错。日常管理时记住这几个命令就够了# 查看日志 docker logs -f vllm-qwen3 # 停止容器 docker stop vllm-qwen3 # 启动容器 docker start vllm-qwen3 # 删除容器模型缓存保留在挂载目录里 docker rm vllm-qwen3需要注意一点如果你改了启动参数比如调大gpu-memory-utilization需要先docker rm删掉旧容器再用新的参数重新docker run因为docker run的参数是容器创建时固定的不能动态修改。而模型文件因为挂载在~/docker_volumes/hf_cache所以删除容器不会导致重新下载。6.2 接入GPT-style客户端的OpenAI接口因为vLLM提供的是OpenAI兼容接口所以你可以直接用openai这个Python库来调用不用写裸的curl了。示例代码如下from openai import OpenAI client OpenAI( base_urlhttp://localhost:8000/v1, api_keyEMPTY ) resp client.chat.completions.create( modelqwen3-8b-fp8, messages[ {role: system, content: 你是一个Python技术专家。}, {role: user, content: 帮我写一个快速排序的Python函数。} ], max_tokens1024, extra_body{chat_template_kwargs: {enable_thinking: False}} ) print(resp.choices[0].message.content)这里有两个细节要说。第一api_key字段随便填什么都可以vLLM不会校验它但客户端库要求这个字段必须存在。第二extra_body参数用来传vLLM支持的非OpenAI标准参数比如Qwen3的chat_template_kwargs。如果你用的是LangChain、LlamaIndex这类框架把base_url指向vLLM的地址同样可以把它当作一个普通的OpenAI兼容ChatModel来用。本地部署OpenAI兼容接口意味着你之前写的很多调用OpenAI的代码只需要换一下base_url就能无缝切换到本地跑起来。6.3 多模型与自定义模型加载如果你不满足于只跑Qwen3这一个模型vLLM也支持同时加载多个模型使用--served-model-name配合--multi-model等参数但对于17GB显存或24GB显存的单卡来说同时加载两个8B模型会把KV cache的空间挤压得很厉害实际并发能力会严重下降。我的建议是单卡老老实实一次跑一个模型需要切换的时候用脚本重建容器模型缓存都在本地切换成本也就一两分钟。自定义模型的场景是这样的如果你想加载一个HuggingFace上还没有直接支持FP8判断的模型或者想跑本地路径的模型可以用--model /path/to/model指定本地目录路径。前提是你先把模型文件下载到WSL2的某个目录然后用-v挂载到容器里。命令类似这样docker run -d \ --name vllm-custom \ --gpus all \ --ipchost \ --shm-size2g \ -p 8000:8000 \ -v /home/yourname/models/Qwen3-8B-BF16:/models/Qwen3-8B-BF16 \ vllm/vllm-openai:latest \ --model /models/Qwen3-8B-BF16 \ --served-model-name qwen3-8b-bf16 \ --gpu-memory-utilization 0.85 \ --max-model-len 32768如果你不是用的FP8模型vLLM也支持通过--quantization参数来指定量化方式比如--quantization awq或--quantization gptq。但这里我多说一句不要给原本不是量化版的模型随便指定量化参数那样会加载失败vLLM对量化格式的识别其实很严格正确的做法是把模型目录里的config.json检查清楚看它标注的quantization_config是什么再判断要不要加--quantization参数。6.4 一些参数调优经验最后分享几个我在调参过程中总结的经验。gpu-memory-utilization和max-model-len是两条此消彼长的线。如果你的主要场景是大量短请求比如作为Agent工具被高频调用可以把max-model-len调小到8192或4096把省下来的显存留给KV cache这样并发能力和总吞吐都会明显提升。如果你的场景是分析长文档、代码仓库这种长上下文任务那max-model-len就是刚需此时为了保证不OOM适度降低并发或调低gpu-memory-utilization是合理的。--max-num-seqs这个参数值得研究一下。vLLM默认允许同时调度最多256个序列但这不代表所有序列都在并行计算它只是给scheduler一个更大的窗口。如果发现某个瞬间显存突然飙升可以通过调小这个值来限制并发。我自己在16GB显存卡上试过--max-num-seqs 32就够日常用了再多反而会因为上下文切换和调度开销影响单请求延迟。如果想进一步压低延迟可以在请求级别调整ignore_eos和min_tokens等参数但这些对最终效果影响没有那么大属于锦上添花。还有一点关于WSL2网络的小经验vLLM服务监听的是容器内的8000端口通过-p 8000:8000映射到Windows宿主机。所以不管从PowerShell、浏览器还是本地Python脚本访问localhost:8000走的都是Windows宿主机路径。但如果你是在WSL2内部的其他服务比如另一个运行在WSL2里的应用去访问它直接用localhost:8000也没问题因为WSL2和Windows共享了这套端口转发机制。这算是WSL2 Docker这套架构里最让人省心的地方了。把vLLM跑起来只是第一步真正有价值的是让这个本地推理服务和你的工作流结合起来——用Python SDK调用它、把它接到LangChain里、用Dify这类工具编排成完整的智能体应用。我在实际使用中比较满意的组合是本地vLLM跑Qwen3-8B-FP8作为推理后端代码生成和工具调用都走同一个接口延迟低、数据不外流整个链路从部署到可用一个晚上就可以搞定。最后再提醒一句如果你后续要给这个服务加鉴权或者做更细粒度的流量控制可以在vLLM前面再套一层Nginx或者写个简单的API网关不要让裸的服务直接暴露在不可信的网络环境里。
返回列表