vLLM 启动 GGUF 模型踩坑记:从报错到 100% GPU 占用的原因解析

摘要: 本文记录了使用 vLLM 部署本地 GGUF 格式大模型的踩坑过程。从最初的路径格式错误,到参数解析问题,再到 NumPy 版本兼容性引发的 AttributeError,最终解决了启动问题。然而,启动后 GPU SM 占用率长时间 100%,这并非卡死,而是 vLLM 进行关键优化步骤(内存分析与 CUDA 图捕捉)的正常现象。最终成功启动服务并明确了 API Base URL。

背景: 想要使用强大的 vLLM 框架来部署一个本地的 GGUF 格式量化大模型(例如 all-hands_openhands-lm-32b-v0.1-Q4_K_M.gguf),并提供 OpenAI 风格的 API 服务。

环境: Conda 环境,vLLM 0.7.2,多 GPU(使用 tensor-parallel-size=2

踩坑一:GGUF 路径格式与 Repo ID 混淆

最初尝试使用模型所在的 目录 作为 vllm serve 的参数:

bash 复制代码
vllm serve /home/kent/_Project/hf_model/bartowski/all-hands_openhands-lm-32b-v0.1-GGUF \
    --host 0.0.0.0 --port 8000 \
    # ... 其他参数

报错:

复制代码
huggingface_hub.errors.HFValidationError: Repo id must be in the form 'repo_name' or 'namespace/repo_name': '/home/kent/_Project/hf_model/bartowski/all-hands_openhands-lm-32b-v0.1-GGUF'. Use `repo_type` argument if needed.

原因: vLLM 默认将 serve 后的第一个参数视为 Hugging Face Hub 的仓库 ID 或本地包含 config.json 等文件的模型目录。直接提供 GGUF 文件所在的目录路径不符合预期。

解决: 需要提供指向 .gguf 文件本身的完整路径

踩坑二:vllm serve 的参数解析 - model_tag 的要求

修正路径后,尝试使用 --model 参数指定 GGUF 文件:

bash 复制代码
vllm serve \
    --model /path/to/your_model.gguf \
    --host 0.0.0.0 --port 8000 \
    # ... 其他参数

报错:

复制代码
usage: vllm serve <model_tag> [options]
vllm serve: error: the following arguments are required: model_tag

原因: vLLM 的 serve 子命令强制要求一个位置参数 model_tag(即 serve 后面的第一个无 -- 前缀的参数)来指定模型。即使使用了 --model,这个位置参数也不能省略。

解决: 将 GGUF 文件的完整路径作为 serve 后面的第一个位置参数 ,并移除 --model 选项。

bash 复制代码
vllm serve \
    /home/kent/_Project/hf_model/bartowski/all-hands_openhands-lm-32b-v0.1-GGUF/all-hands_openhands-lm-32b-v0.1-Q4_K_M.gguf \
    --host 0.0.0.0 --port 8000 \
    # ... 其他参数

踩坑三:NumPy 版本兼容性问题

修正命令后再次运行,遇到新的报错:

复制代码
AttributeError: `newbyteorder` was removed from the ndarray class in NumPy 2.0. Use `arr.view(arr.dtype.newbyteorder(order))` instead.

原因: 环境中安装了 NumPy 2.0 或更高版本。而 vLLM 依赖的某个库(如 transformers 或其依赖 gguf-py)内部代码使用了 NumPy 1.x 版本中存在的 .newbyteorder() 方法,该方法在 NumPy 2.0 中已被移除。

解决: 降级 NumPy 版本到 2.0 之前。推荐使用一个稳定的 1.x 版本,如 1.26.4。

bash 复制代码
# 在激活的 Conda 环境中执行
pip install "numpy<2.0"
# 或者指定版本
# pip install numpy==1.26.4

踩坑四(解惑):启动后 GPU SM 长时间 100%

在解决了上述所有报错后,vllm serve 命令终于开始正常执行。模型权重成功加载,但观察 nvidia-sminvtop 发现 GPU 的 SM 占用率长时间维持在 100%,似乎服务卡住了。

原因: 这并非卡死,而是 vLLM 在进行必要的、但非常耗时的启动优化步骤。主要包括:

  1. 内存分析 (Memory Profiling):

    • 目的: 精确计算在当前 GPU 和配置下,除了模型权重外,有多少显存可以安全地分配给 KV Cache,以最大化吞吐量和并发数。
    • 表现: 在日志中可以看到类似 Memory profiling takes XXX.XX seconds 的信息。这个过程需要模拟计算,会长时间占用 GPU。在我们的案例中,这步耗时近 4 分钟。
    log 复制代码
    INFO 04-01 22:18:59 worker.py:267] Memory profiling takes 231.99 seconds
    INFO 04-01 22:18:59 worker.py:267] ... the rest of the memory reserved for KV Cache is 7.46GiB.
  2. CUDA 图捕捉 (Capturing Cudagraphs):

    • 目的: 将模型推理过程中的一系列 GPU 操作预先录制成一个"图"(Graph)。后续处理请求时,可以直接重放这个图,大幅减少 CPU 到 GPU 的调度开销,提升性能。
    • 表现: 日志中会出现 Capturing cudagraphs for decoding... 和一个进度条。这个过程同样需要实际运行推理,会长时间占用 GPU。在我们的案例中,这步耗时约 1 分 12 秒。
    log 复制代码
    INFO 04-01 22:19:02 model_runner.py:1434] Capturing cudagraphs for decoding...
    Capturing CUDA graph shapes: 100%|████████████| 35/35 [01:12<00:00,  2.07s/it]
    INFO 04-01 22:20:14 model_runner.py:1562] Graph capturing finished in 72 secs...

结论: 启动 vLLM 服务(尤其是对于大型模型、启用 Tensor Parallel 或 Prefix Caching 时)需要耐心等待。内存分析和 CUDA 图捕捉是正常的优化过程,期间 GPU 高负载是预期行为。

最终成功与 Base URL

当所有优化步骤完成后,日志会显示:

log 复制代码
INFO 04-01 22:20:14 llm_engine.py:431] init engine (...) took 307.74 seconds
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

这表明服务已成功启动,并监听在 8000 端口。

API Base URL:

  • 如果从服务器本机访问:http://127.0.0.1:8000
  • 如果从局域网其他机器访问:http://<服务器的IP地址>:8000

常用的 OpenAI 兼容端点(例如文本补全)的完整 URL 为:http://<服务器的IP地址>:8000/v1/completions

总结: 部署 vLLM GGUF 模型需要注意命令行参数的正确格式、检查依赖库(尤其是 NumPy)的版本兼容性,并理解启动过程中的优化步骤会导致暂时的 GPU 高负载。耐心等待后,即可获得高效的推理服务。


相关推荐
Mr. Cao code3 小时前
Docker:颠覆传统虚拟化的轻量级革命
linux·运维·ubuntu·docker·容器
抓饼先生4 小时前
Linux control group笔记
linux·笔记·bash
挺6的还4 小时前
25.线程概念和控制(二)
linux
您的通讯录好友4 小时前
conda环境导出
linux·windows·conda
代码AC不AC5 小时前
【Linux】vim工具篇
linux·vim·工具详解
码农hbk6 小时前
Linux signal 图文详解(三)信号处理
linux·信号处理
bug攻城狮6 小时前
Skopeo 工具介绍与 CentOS 7 安装指南
linux·运维·centos
宇宙第一小趴菜6 小时前
08 修改自己的Centos的软件源
linux·运维·centos
bug攻城狮6 小时前
彻底禁用 CentOS 7.9 中 vi/vim 的滴滴声
linux·运维·服务器·centos·vim
XMYX-06 小时前
Linux 物理机如何区分 SSD 与 HDD ——以 DELL PERC H730 Mini 为例
linux·运维