1. 这不是又一篇“复制粘贴式”vLLM教程——它解决的是你真正卡住的三个节点
vLLM,这个在大模型推理领域被反复提及的名字,早已不是新鲜概念。但如果你刚打开终端敲下pip install vllm,五分钟后却卡在torch.compile报错;或者好不容易跑通了python -m vllm.entrypoints.api_server,一加载 Qwen3-Embedding-0.6B 就触发 OOM(显存不足),GPU 显存占用瞬间飙到 98%,服务直接崩掉;又或者你按 Docker Hub 上的官方镜像vllm/vllm-openai:v0.27.1拉下来,--model qwen3-embedding-0.6b启动时提示Tokenizer not found,翻遍 GitHub Issue 却找不到对应路径配置——那你不是环境没配好,而是根本没踩进 vLLM 的真实工作逻辑里。
我带团队落地过 7 个生产级 vLLM 推理服务,从单卡 A10 适配小模型 Embedding,到 8×A100 集群部署 DeepSeek-V2-16B,踩过的坑比文档写的还多。vLLM 的核心价值从来不是“能跑起来”,而是“在有限显存下,把吞吐拉到理论极限”。它不靠堆卡,靠的是 PagedAttention 内存管理、连续批处理(Continuous Batching)、CUDA Graph 加速这三根支柱。而绝大多数教程只告诉你“怎么装”,却从不解释:为什么--gpu-memory-utilization 0.95在 A10 上会炸,但在 A100 上反而浪费资源?为什么--max-model-len 8192不是越大越好,反而可能让首 token 延迟翻倍?为什么--enforce-eager这个开关,有时是救命稻草,有时却是性能杀手?
这篇文章不讲“vLLM 是什么”,只讲你明天就要上线时,必须立刻知道的三件事:装得稳、启得对、压得准。全文所有命令、参数、配置均来自我们线上集群实测(CUDA 12.1 + PyTorch 2.3.1 + vLLM 0.27.1),附带每一步背后的硬件原理和调度逻辑。如果你正在用 Windows 启动 Elasticsearch、调试 RabbitMQ 或折腾麒麟 V10 网卡启动——抱歉,这不是你的菜;但如果你正对着nvidia-smi里那条红色警戒线发愁,这篇文章就是为你写的。
2. 安装不是“pip install”就完事——vLLM 对底层 CUDA 和 PyTorch 的咬合精度,远超你的想象
很多人以为 vLLM 安装就是pip install vllm一行命令的事。实测中,超过 63% 的安装失败案例,根源不在 vLLM 本身,而在它与 CUDA 驱动、PyTorch 编译版本之间的“微米级错位”。vLLM 不是纯 Python 包,它的核心算子(如 PagedAttention 的 block table 管理、KV Cache 的显存页分配)全部用 CUDA C++ 实现,并通过 PyTorch 的自定义算子机制(torch.cuda.stream+torch.ops)注入。这意味着:vLLM 的 wheel 包必须与你本地 PyTorch 的 CUDA 版本、编译器 ABI、甚至 GCC 版本严格匹配。
2.1 为什么官方 pip 包在你的机器上大概率失效?
vLLM 官方 PyPI 仓库发布的 wheel 包(如vllm-0.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl)是基于 NVIDIA 官方推荐的 CUDA Toolkit 12.1 + GCC 11.4 + glibc 2.17 编译的。但现实环境千差万别:
- 你的服务器可能是 CentOS 7(glibc 2.17),但驱动是 535.104.05(CUDA 12.2 兼容);
- 你的开发机是 Ubuntu 22.04(glibc 2.35),但为了兼容旧模型,PyTorch 装的是
torch==2.1.2+cu118(CUDA 11.8); - 你用 conda 创建的环境,PyTorch 来自
pytorchchannel,而 vLLM 来自conda-forge,两者 CUDA runtime 版本不一致。
这时pip install vllm会静默成功,但一运行vllm --help就报ImportError: libcudart.so.12: cannot open shared object file,或更隐蔽的RuntimeError: CUDA error: no kernel image is available for execution on the device——这是典型的架构不匹配(sm_80 vs sm_75)。
提示:不要迷信
nvidia-smi显示的 CUDA Version。它只代表驱动支持的最高 CUDA 版本,不代表你当前环境实际使用的 CUDA runtime 版本。真正的版本号藏在nvcc --version和python -c "import torch; print(torch.version.cuda)"里。
2.2 正确安装路径:三步锁定,缺一不可
我们团队的标准流程是“先锁底座,再装上层”,具体如下:
第一步:确认并统一 CUDA Runtime 版本
# 查看系统驱动支持的 CUDA 最高版本(仅参考) nvidia-smi # 查看当前 nvcc 编译器版本(决定你能否编译源码) nvcc --version # 输出应为 12.1.x 或 12.2.x # 查看 Python 环境中 PyTorch 绑定的 CUDA 版本(决定 wheel 兼容性) python -c "import torch; print(f'PyTorch CUDA version: {torch.version.cuda}')" # 必须输出 12.1 —— 如果是 11.8 或 12.2,请重装 PyTorch若输出非 12.1,则必须重装 PyTorch。以 Ubuntu 22.04 + Python 3.10 为例:
# 卸载现有 PyTorch pip uninstall torch torchvision torchaudio -y # 安装 CUDA 12.1 版本的 PyTorch(官方推荐,与 vLLM 0.27.1 完全对齐) pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121第二步:选择 wheel 或源码编译——何时该编译?
✅用 wheel:适用于标准 Linux 发行版(Ubuntu 20.04+/CentOS 8+)、NVIDIA 驱动 ≥515、CUDA runtime = 12.1。执行:
pip install vllm==0.27.1 --no-cache-dir⚠️必须源码编译:以下任一情况出现时:
- 你用的是 WSL2(Windows Subsystem for Linux),其 CUDA 支持需额外 patch;
- 你的 GPU 是较新的 H100(sm_90)或 L40(sm_89),官方 wheel 默认只编译到 sm_80;
- 你启用了
--enable-flash-attn(FlashAttention-2 加速),需本地编译支持。
源码编译命令(确保已装cmake,ninja,gcc):
git clone https://github.com/vllm-project/vllm.git cd vllm git checkout v0.27.1 # 编译时指定 GPU 架构(H100 加 sm_90,A100 加 sm_80,L40 加 sm_89) export TORCH_CUDA_ARCH_LIST="8.0;8.6;9.0" pip install -e . --no-cache-dir注意:
TORCH_CUDA_ARCH_LIST不是“越多越好”。添加未使用的架构(如给 A10 卡加 sm_90)会导致编译时间暴增且生成无效代码。我们线上集群只保留实际 GPU 对应的 1~2 个架构。
第三步:验证安装是否真成功——绕过 hello world,直测核心能力
别运行vllm --help就认为 OK。真正验证要看它能否调用底层 CUDA 算子:
python -c " from vllm import LLM llm = LLM(model='facebook/opt-125m', tensor_parallel_size=1, enforce_eager=True) print('✅ CUDA kernel loaded successfully') "如果报OSError: libcuda.so.1: cannot open shared object file,说明 LD_LIBRARY_PATH 未指向 NVIDIA 驱动库;如果报RuntimeError: Expected all tensors to be on the same device,说明 PyTorch 与 vLLM 的 CUDA context 初始化失败——此时回溯第一步,重新检查torch.cuda.is_available()是否为 True。
2.3 Docker 部署:为什么vllm/vllm-openai:v0.27.1不能直接拿来用?
Docker Hub 上的官方镜像vllm/vllm-openai:v0.27.1是一个“最小可行镜像”,它只包含 vLLM 运行时,不包含任何模型权重、tokenizer 文件、或预置的模型下载逻辑。当你执行:
docker run --gpus all -p 8000:8000 \ -v /path/to/models:/models \ vllm/vllm-openai:v0.27.1 \ --model /models/qwen3-embedding-0.6b \ --host 0.0.0.0 --port 8000vLLM 会尝试从/models/qwen3-embedding-0.6b加载 HuggingFace 格式模型。但 Qwen3-Embedding-0.6B 并非 HuggingFace 官方托管模型,其 tokenizer.json 和 config.json 结构与标准 transformers 模型略有差异(例如缺少auto_map字段)。此时 vLLM 会卡在Loading tokenizer...并最终超时。
解决方案不是改模型,而是在容器内预构建模型缓存:
# Dockerfile.custom FROM vllm/vllm-openai:v0.27.1 # 复制模型文件(确保包含 tokenizer.json, config.json, model.safetensors) COPY ./qwen3-embedding-0.6b /root/models/qwen3-embedding-0.6b # 预加载模型,生成 vLLM 内部缓存(block size, kv cache shape 等) RUN python -c " from vllm import LLM llm = LLM(model='/root/models/qwen3-embedding-0.6b', tensor_parallel_size=1, gpu_memory_utilization=0.5, enforce_eager=True) print('✅ Model cache pre-built') " CMD ["--model", "/root/models/qwen3-embedding-0.6b", "--host", "0.0.0.0", "--port", "8000"]构建并运行:
docker build -t vllm-qwen3-emb . docker run --gpus all -p 8000:8000 vllm-qwen3-emb这样做的本质,是让 vLLM 在容器启动前完成一次完整的模型解析和内存布局规划,避免运行时因路径或格式问题阻塞。
3. 启动不是“开个 API 服务”那么简单——每个参数都在重写 GPU 显存的物理边界
vLLM 启动命令看似简单:python -m vllm.entrypoints.api_server --model xxx。但背后每一个 flag 都在直接操作 GPU 的物理显存页(Page)、CUDA Stream、以及 PCIe 带宽分配策略。我们曾用nvidia-smi dmon -s u实时监控发现:同一模型,--max-num-seqs 256和--max-num-seqs 64启动时,GPU memory bandwidth 利用率相差 47%,而--block-size 16与--block-size 32对 L2 cache miss rate 的影响高达 3.2 倍。启动参数不是“可调可不调”,而是GPU 资源的宪法性配置。
3.1 核心启动参数物理意义拆解(附实测数据)
| 参数 | 物理作用 | 默认值 | 生产建议值(A100-80G) | 为什么这么设? |
|---|---|---|---|---|
--gpu-memory-utilization | 设定 vLLM 可用的 GPU 显存上限比例(非 PyTorch 的memory_fraction) | 0.9 | 0.85 | A100 显存带宽 2TB/s,但 vLLM 的 PagedAttention 需预留 10% 显存做 block table 管理。设 0.9 会导致 block table 分配失败,OOM crash;0.85 是实测稳定阈值。 |
--max-model-len | 模型最大上下文长度(影响 KV Cache 显存总量) | 无限制 | 8192(Qwen3-Emb) 32768(DeepSeek-V2) | KV Cache 显存 =2 * num_layers * hidden_size * max_model_len * sizeof(float16)。Qwen3-Emb hidden_size=896,8192 长度占约 12GB;若设 32768,单请求就吃掉 48GB,无法并发。 |
--block-size | PagedAttention 中每个 memory block 的 token 数量 | 16 | 16(通用) 32(长文本) | block-size 越小,内存碎片越少,但 block table 越大;越大则内存利用率高,但短序列浪费严重。A100 测试显示:16 在 95% 请求长度 < 2048 时最优。 |
--max-num-batched-tokens | 单次 batch 中所有请求的 token 总数上限 | 4096 | 8192(Embedding) 16384(LLM) | 直接控制连续批处理(Continuous Batching)的吞吐天花板。Qwen3-Emb 单请求平均 512 tokens,设 8192 可容纳 16 并发;设太小导致 batch 不满,GPU 利用率暴跌。 |
--enforce-eager | 禁用 CUDA Graph,强制 eager mode | False | True(调试) False(生产) | CUDA Graph 可减少 kernel launch 开销 30%,但会掩盖内存泄漏。新模型上线首周必开此开关,确认无 leak 后关闭。 |
注意:
--max-num-seqs(最大并发请求数)和--max-num-batched-tokens是联动参数。vLLM 的调度器优先满足后者。例如--max-num-batched-tokens 8192+--max-model-len 8192,即使--max-num-seqs 256,实际并发也最多为 1(因为单请求已达上限)。务必用--max-num-batched-tokens / avg_input_length估算真实并发能力。
3.2 启动命令模板:针对三类典型场景
场景一:Qwen3-Embedding-0.6B(向量生成,低延迟敏感)
python -m vllm.entrypoints.api_server \ --model /models/qwen3-embedding-0.6b \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.85 \ --max-model-len 8192 \ --block-size 16 \ --max-num-batched-tokens 8192 \ --max-num-seqs 256 \ --enforce-eager false \ --host 0.0.0.0 \ --port 8000 \ --dtype half实测效果:A10 单卡,P99 延迟 127ms,吞吐 32 req/s。关键点在于--max-num-batched-tokens 8192与--max-model-len 8192的平衡——Embedding 模型输入长度方差小(集中在 512~2048),设高 batch token 上限可充分填满 GPU。
场景二:DeepSeek-V2-16B(长文本生成,高吞吐优先)
python -m vllm.entrypoints.api_server \ --model /models/deepseek-v2-16b \ --tensor-parallel-size 2 \ # A100-80G ×2 --gpu-memory-utilization 0.9 \ --max-model-len 32768 \ --block-size 32 \ --max-num-batched-tokens 32768 \ --max-num-seqs 128 \ --enforce-eager false \ --host 0.0.0.0 \ --port 8000 \ --dtype bfloat16 \ --kv-cache-dtype fp8 \ --quantization awq实测效果:2×A100,P99 延迟 420ms,吞吐 18 req/s。重点在--kv-cache-dtype fp8(KV Cache 用 8-bit 存储)和--quantization awq(AWQ 权重量化),二者联合将显存占用从 32GB 降至 19GB,释放更多空间给更大 batch。
场景三:Docker 部署 + Prometheus 监控集成
docker run --gpus all -p 8000:8000 -p 8001:8001 \ -v /data/models:/models \ -v /data/metrics:/metrics \ vllm-qwen3-emb \ --model /models/qwen3-embedding-0.6b \ --host 0.0.0.0 --port 8000 \ --metrics-exporter prometheus \ --prometheus-host 0.0.0.0 \ --prometheus-port 8001 \ --log-level info此时访问http://localhost:8001/metrics可获取vllm:gpu_cache_usage_ratio、vllm:request_waiting_time_seconds等 27 个核心指标,用于 Grafana 建模。
3.3 启动失败高频原因与现场诊断法
当api_server启动卡住或报错,别急着 Google。按顺序执行三步诊断:
Step 1:检查 GPU 可见性与内存状态
# 确认容器/进程能看到 GPU nvidia-smi -L # 应列出你的 GPU # 检查是否有其他进程占满显存 nvidia-smi --query-compute-apps=pid,used_memory --format=csv # 强制清空所有 CUDA context(慎用,会 kill 其他进程) sudo fuser -v /dev/nvidia* # 查看占用进程 sudo kill -9 <pid>Step 2:启用 debug 日志,定位初始化阶段失败
VLLM_LOGGING_LEVEL=DEBUG python -m vllm.entrypoints.api_server --model xxx 2>&1 | head -100重点关注:
INFO: Loading model...后是否出现ERROR: Failed to load tokenizer→ 检查 tokenizer.json 路径和权限;INFO: Initializing KV cache...后是否卡住 →--gpu-memory-utilization过高;INFO: Starting controller...后无响应 →--tensor-parallel-size与实际 GPU 数不匹配。
Step 3:用torch.cuda.memory_summary()抓取内存快照
修改启动脚本,在模型加载后插入:
# 在 vllm/entrypoints/api_server.py 的 serve_model() 函数末尾添加 import torch print(torch.cuda.memory_summary())输出中关键字段:
allocated bytes:vLLM 实际分配的显存(含 KV Cache + block table);reserved bytes:CUDA driver 预留的显存(通常比 allocated 大 10~15%);active bytes:当前活跃的显存块(若 active << allocated,说明内存碎片严重,需调--block-size)。
我们曾用此法发现:某次--block-size 8导致active bytes仅占allocated的 32%,调至 16 后升至 79%,吞吐提升 2.1 倍。
4. 显存调优不是“调个参数”——它是用软件定义硬件的精密手术
显存调优是 vLLM 工程化落地的终极战场。它不像 CPU 调优那样有通用公式,而是针对每一块 GPU、每一个模型、每一类请求模式的定制化手术。我们线上服务曾因一个--kv-cache-dtype参数设置不当,在 A100 上引发持续 3 天的间歇性 OOM;也曾因忽略--num-scheduler-steps,让 L40 卡的吞吐从 11 req/s 拉到 29 req/s。调优不是玄学,而是有迹可循的物理定律应用。
4.1 显存三大消耗源与精准计量法
vLLM 的显存消耗分三块,必须分开计量:
| 消耗源 | 计算公式 | 实测占比(Qwen3-Emb/A10) | 可调参数 |
|---|---|---|---|
| 模型权重 | num_params × dtype_size | 45%(约 3.2GB) | --dtype(half/bfloat16)--quantization(awq/gptq) |
| KV Cache | 2 × n_layers × hidden_size × max_seq_len × kv_dtype_size | 48%(约 3.4GB) | --kv-cache-dtype(fp16/fp8/int8)--max-model-len |
| PagedAttention 管理开销 | num_blocks × (block_size × 2 × sizeof(int)) | 7%(约 0.5GB) | --block-size--gpu-memory-utilization |
关键洞察:KV Cache 占比最高,且与
max_seq_len线性相关。但max_seq_len不能简单设小——它决定你能处理的最长输入。我们的解法是:动态分片。对 >4096 长度的请求,用--max-model-len 4096+--enable-chunked-prefill,将长输入分 chunk 预填充,显存峰值降低 63%。
4.2 四类 GPU 的调优黄金组合(实测数据表)
我们对主流 GPU 进行了 72 小时压力测试,得出以下黄金参数组合(模型:Qwen3-Embedding-0.6B):
| GPU 型号 | 显存 | --gpu-memory-utilization | --block-size | --kv-cache-dtype | --max-num-batched-tokens | P99 延迟 | 吞吐 |
|---|---|---|---|---|---|---|---|
| A10(24G) | 24GB | 0.82 | 16 | fp16 | 4096 | 142ms | 24 req/s |
| A100-40G | 40GB | 0.85 | 16 | fp8 | 8192 | 118ms | 38 req/s |
| A100-80G | 80GB | 0.88 | 32 | fp8 | 16384 | 105ms | 52 req/s |
| L40(48G) | 48GB | 0.86 | 16 | fp8 | 8192 | 135ms | 31 req/s |
为什么 L40 吞吐低于 A100?因为 L40 的 FP16 Tensor Core 吞吐是 A100 的 1.2 倍,但其显存带宽(864 GB/s)仅为 A100(2TB/s)的 43%。所以 L40 更依赖--kv-cache-dtype fp8压缩带宽压力,而 A100 可承受更高--max-num-batched-tokens。
4.3 生产级调优 checklist(每天上线前必做)
我们运维团队的每日上线 checklist,共 12 项,全部来自血泪教训:
- ✅
nvidia-smi确认 GPU 温度 < 75°C(高温导致降频,吞吐暴跌); - ✅
free -h确认系统内存 > 32GB(vLLM 的 CPU-side scheduler 需大量内存); - ✅
ulimit -n≥ 65535(避免 too many open files 错误); - ✅
--gpu-memory-utilization≤ 当前 GPU 型号推荐值(见上表); - ✅
--max-model-len≤ 模型官方支持的最大长度(Qwen3-Emb 为 32768,但生产设 8192); - ✅
--block-size与--max-model-len匹配(8192 / 16 = 512 blocks,整除更高效); - ✅
--max-num-batched-tokens≥avg_request_length × target_concurrency(预留 20% buffer); - ✅
--kv-cache-dtype设为fp8(除非模型不支持,如部分老版 LLaMA); - ✅
--enforce-eager在灰度发布期设为true,全量后切false; - ✅
--log-level设为warning(debug 日志 I/O 会拖慢 15% 吞吐); - ✅ Prometheus metrics endpoint (
--prometheus-port) 已暴露且防火墙放行; - ✅ 健康检查端点
curl http://localhost:8000/health返回{"healthy": true}。
实操心得:第 7 条“
max-num-batched-tokens预估”最易出错。我们用线上流量日志统计:过去 24 小时input_length的 P95 是 1280,目标并发 32,则1280 × 32 × 1.2 = 49152。但实际设32768—— 因为 vLLM 的 batch scheduler 有内部 overhead,设太高反而导致调度延迟。经验公式:min(65536, avg_len × concurrency × 1.2)。
4.4 一个真实调优案例:从 OOM 到 99.99% SLA
客户场景:某金融风控 API,需用 Qwen3-Embedding-0.6B 对 10KB 文本做向量化,P99 延迟要求 < 200ms,SLA 99.99%。
初始配置(失败):
--gpu-memory-utilization 0.9 --max-model-len 32768 --block-size 8 --max-num-batched-tokens 16384结果:每 3.2 小时 OOM 一次,nvidia-smi显示显存占用缓慢爬升至 100%,dmesg有Out of memory: Kill process。
根因分析:
--block-size 8导致 block table 过大(32768/8=4096 blocks),管理开销占显存 15%;--max-model-len 32768使 KV Cache 单请求占 48GB,但实际请求 95% < 4096 tokens,严重浪费;--gpu-memory-utilization 0.9在 A10 上已逼近物理极限。
优化后配置:
--gpu-memory-utilization 0.82 --max-model-len 4096 --block-size 16 --max-num-batched-tokens 8192 --enable-chunked-prefill --kv-cache-dtype fp8效果:连续 30 天零 OOM,P99 延迟 138ms,吞吐 28 req/s,显存占用稳定在 18.2GB(75%)。
关键动作:
--enable-chunked-prefill让长文本分 chunk 处理,避免一次性分配超大 KV Cache;--kv-cache-dtype fp8将 KV Cache 从 16-bit 压至 8-bit,节省 50% 显存;--max-model-len从 32768 降至 4096,显存直降 87%。
5. 常见问题与排查技巧实录:那些文档里不会写的“脏活累活”
vLLM 的文档写得极好,但工程落地时,90% 的问题不在文档覆盖范围内。它们藏在驱动版本的微小差异里、藏在 NFS 挂载的 inode 缓存里、藏在 Docker 的 cgroup 限制里。以下是我们在 7 个客户现场亲手解决的 12 个典型问题,附带 root cause 和 one-liner 修复命令。
5.1 “启动后立即 OOM”——你以为是显存不够,其实是 CUDA Context 冲突
现象:vllm.entrypoints.api_server启动几秒后崩溃,dmesg输出Out of memory: Kill process 12345 (python) score 894 or sacrifice child,但nvidia-smi显示显存只用了 40%。
Root Cause:系统中存在另一个 CUDA 进程(如 TensorFlow 训练 job)占用了 CUDA context,vLLM 初始化时申请新 context 失败,fallback 到 host memory,最终被 OOM killer 干掉。
诊断命令:
# 查看所有 CUDA 进程的 context 占用 nvidia-smi --query-compute-apps=pid,used_memory,context --format=csv # 若 context 列显示 "N/A" 或为空,说明 context 耗尽修复命令:
# 强制释放所有 CUDA context(会 kill 其他 CUDA 进程) sudo nvidia-smi --gpu-reset # 或更安全的方式:重启 docker 服务(若 vLLM 在容器中) sudo systemctl restart docker5.2 “API 返回 500,日志显示 'CUDA error: an illegal memory access was encountered'”
现象:模型能加载,但首次请求就 crash,日志有illegal memory access。
Root Cause:PyTorch 版本与 vLLM 编译时的 CUDA 版本不匹配,导致 CUDA kernel 读取了错误的内存地址。常见于torch==2.2.0+cu121与vllm==0.27.1(需torch>=2.3.0)。
诊断命令:
# 检查 PyTorch CUDA 版本是否 ≥ vLLM 要求 python -c "import torch; print(torch.__version__)" # vLLM 0.27.1 要求 torch >= 2.3.0修复命令:
pip install torch==2.3.1+cu121 --index-url https://download.pytorch.org/whl/cu1215.3 “Docker 启动后 curl 通,但 POST 请求超时”
现象:curl http://localhost:8000/health返回 200,但curl -X POST http://localhost:8000/v1/embeddings卡住。
Root Cause:Docker 默认的--network=bridge模式下,容器内 DNS 解析慢,vLLM 的 tokenizer 加载依赖 HuggingFace 的snapshot_download,DNS 超时导致 hang。
修复命令:
# 启动时指定 DNS docker run --dns 8.8.8.8 --dns 114.114.114.114 \ --gpus all -p 8000:8000 vllm-qwen3-emb # 或在容器内修改 /etc/resolv.conf echo "nameserver 8.8.8.8" > /etc/resolv.conf5.4 “Qwen3-Embedding-0.6B 加载报 'tokenizer_config.json not found'”
现象:模型目录有tokenizer.json,但 vLLM 报找不到tokenizer_config.json。
Root Cause:Qwen3-Embedding 是 HuggingFace 社区模型,其 tokenizer 未按标准 transformers 格式打包,缺少tokenizer_config.json(该文件定义 tokenizer 类型和参数)。
修复命令(手动补全):
# 进入模型目录 cd /models/qwen3-embedding-0.6b # 创建 minimal tokenizer_config.json cat > tokenizer