主题
vLLM + AMD GPU vGPU 部署与运维手册
GPU: AMD Radeon RX 7900 XTX (24GB VRAM, gfx1100) 节点: szb122009 (192.168.122.9) 框架: vLLM v0.6.6 + ROCm 6.3.2 + Open WebUI v0.11.0 集群: RKE2 (Kubernetes) 基础镜像: ROCm 6.3.2 + PyTorch 2.4.0 + Ubuntu 24.04 最后更新: 2026-08-18
目录
一、架构概览
用户浏览器
│
▼ https://ai.ai-ear.cn (DNS → 8.153.84.140)
┌──────────────────────────────────────────┐
│ 公网服务器 (8.153.84.140) │
│ Traefik (:443 TLS) │
│ dynamic.yaml → ai-open-webui router │
│ → svc-18080 → 127.0.0.1:18080 │
└──────────────────┬───────────────────────┘
│ frp tunnel (remotePort 18080)
▼
┌──────────────────────────────────────────────────────────────────┐
│ szb122009 (192.168.122.9) │
│ frps (:7000) ← frpc : open-webui-18080 │
│ │
│ hostPath 挂载: │
│ /opt/models/huggingface/ ──► /models/huggingface/ (容器内) │
│ ├── deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B/ (1.5B, 3GB) │
│ ├── Qwen/Qwen2.5-3B-Instruct/ (3B, 6GB) │
│ └── Qwen/Qwen2.5-7B-Instruct/ (7B, 14GB) │
│ /opt/open-webui/ ──► /app/backend/data/ (容器内) │
│ /dev/dri, /dev/kfd ──► GPU 设备直通 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ vLLM Pod │ │ vLLM Pod │ │ Open WebUI │ │
│ │ DeepSeek-R1 │ │ Qwen2.5-3B │ │ (Frontend) │ │
│ │ ~3GB VRAM │ │ ~6GB VRAM │ │ CPU only │ │
│ │ (replicas=0) │ │ (replicas=0) │ │ NodePort │ │
│ └──────────────┘ └──────────────┘ │ :30080 │ │
│ └──────┬───────┘ │
│ ┌──────────────┐ │ │
│ │ vLLM Pod │ ← 默认启动 (推荐) │ │
│ │ Qwen2.5-7B │ │ │
│ │ ~14GB VRAM │ │ │
│ │ (replicas=1) │ │ │
│ └──────┬───────┘ │ │
│ │ │ │
│ ┌──────▼───────────────────────────────────▼──┐ │
│ │ AMD RX 7900 XTX 24GB (gfx1100) │ │
│ └─────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘关键设计: 同一时间只启动一个 vLLM 模型 Pod,通过
deploy.sh switch命令切换。 三个模型共享同一张 GPU,但不同时运行,避免显存不足。 默认推荐 Qwen2.5-7B (中文能力强、推理/编码/对话均衡、24GB 显存充足)。
存储方案 (hostPath)
| 宿主机路径 | 容器挂载路径 | 用途 |
|---|---|---|
/opt/models/huggingface/ | /models/huggingface/ | HuggingFace 模型文件 |
/opt/open-webui/ | /app/backend/data/ | Open WebUI 持久化数据 (含 SQLite DB) |
/dev/dri | /dev/dri | AMD DRI 渲染节点 |
/dev/kfd | /dev/kfd | AMD KFD 计算节点 |
镜像信息
| 镜像 | Harbor 地址 | 说明 |
|---|---|---|
| ROCm + PyTorch 基础镜像 | 192.168.122.156:30000/rocm/pytorch:rocm6.3.2_ubuntu24.04_py3.12_pytorch_release_2.4.0 | ~71.5 GB |
| vLLM 应用镜像 | 192.168.122.156:30000/cnrancher/vllm-rocm:v0.6.6 | 源码编译 |
| Open WebUI | 192.168.122.156:30000/cnrancher/open-webui:main | 官方镜像转推 |
vLLM 启动参数一览 (Qwen2.5-7B, 默认模型)
| 参数 | 当前值 | 说明 |
|---|---|---|
--model | /models/huggingface/Qwen/Qwen2.5-7B-Instruct | 模型本地路径 |
--served-model-name | qwen2.5-7b | API 中暴露的模型名 |
--gpu-memory-utilization | 0.90 | GPU 显存利用率上限 (90%, 单模型独占) |
--max-model-len | 16384 | 最大上下文 token 数 (7B 可用 16K) |
--dtype | float16 | 数据类型 |
--enforce-eager | (flag) | 禁用 CUDA/HIP Graph,兼容 ROCm |
--enable-auto-tool-choice | (flag) | 支持 Open WebUI 的 tool_choice="auto" |
--tool-call-parser | hermes | Tool calling 解析器 |
--disable-frontend-multiprocessing | (flag) | 绕过 ROCm IPC 序列化问题 |
环境变量一览
| 变量名 | 值 | 说明 |
|---|---|---|
HSA_OVERRIDE_GFX_VERSION | 11.0.0 | RX 7900 XTX 实际是 gfx1100,需伪装以兼容 ROCm |
VLLM_TARGET_DEVICE | rocm | 告知 vLLM 使用 ROCm 后端 |
PYTORCH_ROCM_ARCH | gfx1100 | PyTorch ROCm 架构标识 |
HF_HOME | /models/huggingface | HuggingFace 缓存目录 |
HF_HUB_OFFLINE | 1 | 离线模式,禁止下载 |
TRANSFORMERS_OFFLINE | 1 | Transformers 离线模式 |
VLLM_USE_TRITON_FLASH_ATTN | 0 | 禁用 Triton Flash Attention (ROCm 不兼容) |
二、部署文件清单
vllm-deploy/
├── Dockerfile # vLLM + ROCm 镜像构建文件 (基于 ROCm 6.3.2, 源码编译)
├── build-and-push.sh # 构建 vLLM 应用镜像并推送 (含源码编译步骤)
├── tag-and-push.sh # 基础镜像打标签并推送到 Harbor
├── deploy.sh # 一键部署脚本 (注册 vGPU + 部署全部服务, 默认启动 qwen7b)
├── vllm-deepseek.yaml # DeepSeek-R1-1.5B vLLM Deployment + Service (replicas=0)
├── vllm-qwen.yaml # Qwen2.5-3B vLLM Deployment + Service (replicas=0)
├── vllm-qwen7b.yaml # Qwen2.5-7B vLLM Deployment + Service (replicas=1, 默认)
├── open-webui.yaml # Open WebUI 前端 Deployment + Service
└── README.md # 本文档 (部署与运维手册)三、运行时补丁详解 (Runtime Patches)
vLLM v0.6.6 在 ROCm + AMD RX 7900 XTX (gfx1100) 环境下存在多个兼容性问题。 我们通过容器启动时的运行时补丁来解决,无需重新构建镜像。
Patch 0: torch._inductor.config 兼容性修复
文件: /opt/vllm/vllm/plugins/__init__.py
问题: vLLM 启动时直接访问 torch._inductor.config.compile_threads,但 ROCm 版本的 PyTorch 没有 _inductor 模块,导致 AttributeError: module 'torch' has no attribute '_inductor'。
修复 (sed 命令):
bash
sed -i "s/torch._inductor.config.compile_threads = 1/\
if hasattr(torch._inductor, 'config'): torch._inductor.config.compile_threads = 1/" \
/opt/vllm/vllm/plugins/__init__.py原理: 添加 hasattr 保护检查,仅在 _inductor 模块存在时才设置参数。
Patch 1: all_special_tokens_extended 孤立装饰器 Bug ⭐ (最关键)
文件: /opt/vllm/vllm/transformers_utils/tokenizer.py
问题: vLLM 的 tokenizer.py 中有一个 all_special_tokens_extended 属性方法,它调用了 tokenizer_all_special_tokens_extended() 函数。在 ROCm 环境下,某些 transformers 版本的 tokenizer 对象没有这个属性,导致 AttributeError。
最初的修复尝试 (有 Bug):
python
# 只注释掉了 def 行,没有处理 @property 装饰器
@property ← 这个装饰器变成"孤儿"
# def all_special_tokens_extended(self): ← 已注释
# return ... ← 已注释
def max_token_id(self): ← @property 附着到了这里!
...Bug 后果: @property 装饰器附着到了下一个方法 max_token_id 上,使 max_token_id 变成了一个 property 对象而不是可调用的方法。推理时报错:
TypeError: 'property' object is not callable正确修复 (当前方案):
python
# 同时注释掉 @property 装饰器和 def 及其函数体
for each line in source:
if 'all_special_tokens_extended' in line:
# 检查前一行是否是 @property,如果是则也注释掉
if new_lines[-1].strip() == '@property':
new_lines[-1] = '# PATCHED: ' + new_lines[-1]
new_lines.append('# PATCHED: ' + line)
# 跳过函数体 (缩进的后续行)
while next_line is indented body:
new_lines.append('# PATCHED: ' + next_line)教训: 修改 Python 装饰器相关代码时,必须同时处理装饰器和被装饰的函数,不能只注释其中一部分。
Patch 2: multiprocessing client IPC 序列化错误
文件: /opt/vllm/vllm/engine/multiprocessing/client.py
问题: vLLM 的前端多进程客户端使用 IPC (Inter-Process Communication) 传输请求输出。 在 ROCm 环境下,某些异常对象无法正确序列化/反序列化,导致 raise request_output 时出现 TypeError。
修复:
python
# 原始代码:
if isinstance(request_output, BaseException):
raise request_output
# 修复后:
if isinstance(request_output, BaseException):
try:
raise request_output
except TypeError:
raise RuntimeError(
f"Engine error: {type(request_output).__name__}: {request_output}"
) from None最终方案: 由于 --disable-frontend-multiprocessing 彻底禁用了多进程前端,此 Patch 作为额外保险保留。
Patch 3 (启动参数): --disable-frontend-multiprocessing
问题: vLLM 默认使用多进程架构 (frontend + engine worker),通过 IPC 管道通信。 ROCm 的 tensor 序列化与 CUDA 不同,IPC 管道传输 tensor 时会失败。
修复: 添加 --disable-frontend-multiprocessing 启动参数,强制 vLLM 使用单进程模式。
副作用: 前端请求处理和推理引擎在同一进程中运行,高并发时可能略有延迟, 但对于单用户/小团队场景完全可接受。
Patch 4 (启动参数): --enable-auto-tool-choice + --tool-call-parser hermes
问题: Open WebUI 默认在请求中发送 "tool_choice": "auto"。如果 vLLM 未启用 tool calling 支持,会返回 400 错误:
"auto" tool choice requires --enable-auto-tool-choice and --tool-call-parser to be set修复: 添加 --enable-auto-tool-choice --tool-call-parser hermes。 Qwen 系列模型使用 Hermes 格式的 tool calling。
四、排查思路与操作步骤
4.1 排查时间线
| 阶段 | 问题 | 排查方法 | 解决 |
|---|---|---|---|
| 1 | Pod CrashLoopBackOff | kubectl logs 查看 vLLM 启动日志 | Patch 0: torch._inductor.config |
| 2 | 推理请求 500 | curl 直接调用 API + 查看 traceback | Patch 1: all_special_tokens_extended |
| 3 | TypeError: 'property' object is not callable | 分析 Python 装饰器机制 | Patch 1 修正: 同时注释 @property |
| 4 | IPC serialization error | 日志中 TypeError 在 client.py | Patch 2 + --disable-frontend-multiprocessing |
| 5 | Open WebUI 400 Bad Request | Open WebUI 日志 tool_choice 报错 | Patch 4: --enable-auto-tool-choice |
| 6 | Open WebUI 连接 vllm-deepseek 失败 | 检查 DB 中的 URL 配置 | 清理 SQLite 中的残留 URL |
| 7 | 上下文长度超限 | 错误提示 maximum context length is 4096 | 增大 --max-model-len 到 8192 |
4.2 排查命令速查
bash
# 通用 kubectl 前缀 (在 192.168.122.37 上执行)
KUBECTL="/var/lib/rancher/rke2/bin/kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml"
# 查看 Pod 状态
$KUBECTL get pods -o wide
# 查看 vLLM 日志 (最近 50 行)
$KUBECTL logs deployment/vllm-qwen7b --tail=50
# 查看 vLLM 错误日志
$KUBECTL logs deployment/vllm-qwen7b --tail=100 | grep -i "error\|traceback\|exception"
# 查看 Open WebUI 日志
$KUBECTL logs deployment/open-webui --tail=50
# 过滤 Open WebUI 中的错误
$KUBECTL logs deployment/open-webui --tail=100 | grep -i "error\|500\|400\|TypeError"
# 实时跟踪日志
$KUBECTL logs -f deployment/vllm-qwen7b
# 进入 Pod 调试
$KUBECTL exec -it deployment/vllm-qwen7b -- bash
# 从 Open WebUI Pod 内部测试 vLLM API
$KUBECTL exec deployment/open-webui -- \
curl -s http://vllm-qwen7b:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "qwen2.5-7b", "messages": [{"role": "user", "content": "1+1=?"}], "max_tokens": 20}'
# 检查 GPU 显存使用
$KUBECTL exec deployment/vllm-qwen7b -- \
cat /sys/class/drm/card1/device/mem_info_vram_used4.3 Open WebUI 数据库配置修复
场景: 切换模型后,Open WebUI 仍然尝试连接旧的 vLLM URL。
原因: Open WebUI 首次启动时将环境变量写入 SQLite 数据库,之后使用数据库配置。 kubectl set env 只更新环境变量,不更新数据库。
修复脚本 (通过 kubectl exec 在 Pod 内执行):
python
import sqlite3
conn = sqlite3.connect("/app/backend/data/webui.db")
c = conn.cursor()
# 只保留当前模型的 URL (示例: 切换到 qwen)
c.execute("UPDATE config SET value = ? WHERE key = ?",
('["http://vllm-qwen7b:8000/v1"]', 'openai.api_base_urls'))
c.execute("UPDATE config SET value = ? WHERE key = ?",
('["dummy"]', 'openai.api_keys'))
c.execute("UPDATE config SET value = ? WHERE key = ?",
('{"0": {"enable": true}}', 'openai.api_configs'))
conn.commit()
c.execute("SELECT key, value FROM config WHERE key LIKE 'openai%'")
for row in c.fetchall():
print(row)
conn.close()提示: 修复数据库后需要重启 Open WebUI:
$KUBECTL rollout restart deployment/open-webui
4.4 vGPU 资源重新注册
kubelet 重启后,手动 patch 的 amd.com/gpu 资源会丢失,Pod 会因资源不足而 Pending。
bash
$KUBECTL patch node szb122009 --type=merge --subresource=status \
-p '{"status":{"capacity":{"amd.com/gpu":"4"},"allocatable":{"amd.com/gpu":"4"}}}'验证:
bash
$KUBECTL get node szb122009 -o jsonpath='{.status.allocatable}' | python3 -m json.tool
# 应看到 "amd.com/gpu": "4"五、操作脚本说明
5.1 deploy.sh — 一键部署脚本
用法:
bash
# 首次部署 (默认启动 qwen7b)
./deploy.sh
# 切换到 qwen7b 模型 (推荐,日常最佳)
./deploy.sh switch qwen7b
# 切换到 qwen 模型 (轻量级)
./deploy.sh switch qwen
# 切换到 deepseek 模型 (推理)
./deploy.sh switch deepseek执行流程:
- 注册 vGPU 资源 (
amd.com/gpu: 4) - 验证节点资源
- 部署 vLLM DeepSeek (replicas=0, 不启动)
- 部署 vLLM Qwen 3B (replicas=0, 不启动)
- 部署 vLLM Qwen 7B (replicas=1, 默认启动)
- 部署 Open WebUI
- 等待 Deployment 就绪
切换模型流程 (deploy.sh switch):
- 将当前模型 Pod 缩容到 0 (释放 GPU)
- 将目标模型 Pod 扩容到 1 (占用 GPU)
- 更新 Open WebUI 环境变量指向新模型
5.2 build-and-push.sh — 镜像构建脚本
用途: 从源码编译 vLLM 并构建 Docker 镜像,推送到 Harbor。
前提:
- 基础镜像已推送到 Harbor (ROCm 6.3.2 + PyTorch 2.4.0)
- 当前机器已安装 Docker 且能访问 Harbor
- 网络可访问 Gitee (用于 clone vLLM 源码)
执行流程:
- 检查基础镜像是否存在
- 启动构建容器 (特权模式 + GPU 直通)
- 安装构建依赖 (ccache, git-lfs)
- 克隆 vLLM v0.6.6 源码
- 源码编译 vLLM (ROCm gfx1100) — 约 10-30 分钟
- 创建 entrypoint 脚本
- 验证 vLLM 安装
- Commit 镜像并推送到 Harbor
5.3 tag-and-push.sh — 基础镜像标签推送
用途: 将华为云镜像源的 ROCm PyTorch 基础镜像打标签并推送到 Harbor。
六、后期维护手册
6.1 日常巡检清单
| 检查项 | 命令 | 预期结果 |
|---|---|---|
| Pod 状态 | $KUBECTL get pods -o wide | 所有 Pod 1/1 Running |
| vLLM 健康检查 | $KUBECTL exec deployment/vllm-qwen7b -- curl -s http://localhost:8000/health | 返回 200 |
| vLLM API 测试 | $KUBECTL exec deployment/open-webui -- curl -s http://vllm-qwen7b:8000/v1/models | 返回模型列表 |
| GPU 显存使用 | $KUBECTL exec deployment/vllm-qwen7b -- cat /sys/class/drm/card1/device/mem_info_vram_used | < 22 GB |
| 磁盘空间 | ssh root@192.168.122.9 'df -h /opt' | 使用率 < 80% |
| Open WebUI 日志 | $KUBECTL logs deployment/open-webui --tail=20 | grep -i error | 无严重错误 |
| vLLM 日志 | $KUBECTL logs deployment/vllm-qwen7b --tail=20 | grep -i error | 无严重错误 |
6.2 模型切换操作
bash
# 切换到 Qwen2.5-7B (推荐,日常最佳)
./deploy.sh switch qwen7b
# 切换到 Qwen2.5-3B (轻量级)
./deploy.sh switch qwen
# 切换到 DeepSeek-R1 (推理模型)
./deploy.sh switch deepseek
# 注意: 切换后还需更新 Open WebUI 数据库 (如果 kubectl set env 未生效)
# 见 4.3 节 "Open WebUI 数据库配置修复"6.3 添加新模型
步骤:
- 下载模型到节点
/opt/models/huggingface/目录 - 复制
vllm-qwen.yaml为新模型创建 YAML - 修改以下字段:
metadata.name: 新模型标识 (如vllm-llama)spec.selector.matchLabels.model: 对应标签containers.command中的--model路径--served-model-name: API 中暴露的名称
- 在
deploy.sh的switch_model函数中添加新 case kubectl apply -f部署新模型 (replicas=0)
示例 — 添加 Llama 3:
yaml
# vllm-llama.yaml (关键字段)
metadata:
name: vllm-llama
spec:
replicas: 0 # 默认不启动
selector:
matchLabels:
app: vllm
model: llama
template:
spec:
containers:
- name: vllm
command:
- bash
- -c
- |
# ... (同 qwen 的 patches) ...
exec python3 -m vllm.entrypoints.openai.api_server \
--model /models/huggingface/meta-llama/Llama-3-8B-Instruct \
--served-model-name llama-3 \
--host 0.0.0.0 --port 8000 \
--gpu-memory-utilization 0.45 \
--max-model-len 8192 \
--dtype float16 \
--enforce-eager \
--enable-auto-tool-choice \
--tool-call-parser hermes \
--disable-frontend-multiprocessing6.4 Open WebUI 升级
bash
# 拉取新版本
docker pull ghcr.io/open-webui/open-webui:main
docker tag ghcr.io/open-webui/open-webui:main 192.168.122.156:30000/cnrancher/open-webui:main
echo 'xxx' | docker login 192.168.122.156:30000 -u admin --password-stdin
docker push 192.168.122.156:30000/cnrancher/open-webui:main
# 在 K8s 集群节点重新部署
$KUBECTL rollout restart deployment/open-webui
$KUBECTL rollout status deployment/open-webui --timeout=120s注意: Open WebUI 数据持久化在
/opt/open-webui/,升级不会丢失配置和聊天记录。
6.5 vLLM 版本升级
bash
# 1. 修改 build-and-push.sh 中的 IMAGE_TAG 为新版本
# 2. 执行构建 (约 30 分钟)
bash build-and-push.sh
# 3. 更新 YAML 文件中的 image tag
# vllm-qwen.yaml / vllm-deepseek.yaml:
# image: 192.168.122.156:30000/cnrancher/vllm-rocm:v0.7.0 ← 新版本
# 4. 重新部署
./deploy.sh注意: 新版本可能需要调整运行时补丁。升级前建议先在测试环境验证。
6.6 备份与恢复
bash
# 备份 Open WebUI 数据
tar czf open-webui-backup-$(date +%Y%m%d).tar.gz -C /opt open-webui/
# 备份 YAML 配置
cp -r /root/vllm-deploy /root/vllm-deploy-backup-$(date +%Y%m%d)
# 恢复 Open WebUI 数据
tar xzf open-webui-backup-YYYYMMDD.tar.gz -C /opt/
$KUBECTL rollout restart deployment/open-webui6.7 常见问题处理
| 问题 | 症状 | 解决方案 |
|---|---|---|
| Pod Pending | amd.com/gpu 资源不足 | 重新注册 vGPU 资源 (见 4.4) |
| Pod CrashLoopBackOff | 启动失败反复重启 | 查看日志,检查补丁是否正确应用 |
| Open WebUI 无法连接 vLLM | 连接超时/拒绝 | 检查 DB 中的 URL 配置 (见 4.3) |
| 推理结果异常 | 乱码/重复/截断 | 检查 --max-model-len 和 --max-tokens 参数 |
| GPU 显存溢出 | OOM Killed | 降低 --gpu-memory-utilization 或 --max-model-len |
| 响应缓慢 | 首 token 延迟 > 5s | 见性能调优章节 |
七、性能调优手册
7.1 GPU 显存分配
当前配置 (Qwen2.5-7B, 默认模型):
--gpu-memory-utilization 0.90→ 使用 90% × 24GB = 21.6 GB- 模型权重: ~14 GB (Qwen2.5-7B FP16)
- KV Cache: ~7.6 GB (剩余空间,支持 16K 上下文)
调整建议:
| 场景 | gpu-memory-utilization | 效果 |
|---|---|---|
| 单模型独占 GPU (当前) | 0.90 | 最大 KV Cache,支持长上下文/高并发 |
| 单模型 + 留余量 | 0.75 | 平衡性能和稳定性 |
| 保守配置 | 0.45 | 低显存占用,适合测试 |
修改方法: 编辑 YAML 中的 --gpu-memory-utilization 参数,然后 kubectl apply -f 并重启。
7.2 批处理与并发
bash
# 增大最大并行请求数 (默认 256)
--max-num-seqs 64
# 增大批处理大小 (默认自动)
--max-num-batched-seqs 128
# 启用连续批处理 (默认已启用)
--enable-chunked-prefill7.3 推理加速选项
bash
# 启用 Prefix Caching (相同前缀的请求共享 KV Cache)
--enable-prefix-caching
# 调整调度策略 (优化首 token 延迟)
--scheduling-policy fcfs # 默认 FCFS; 可选: priority7.4 量化模型 (减少显存占用)
| 量化方式 | 显存节省 | 精度损失 | 适用场景 |
|---|---|---|---|
| FP16 (当前) | 基准 | 无 | 精度优先 |
| INT8 (W8A8) | ~50% | 极小 | 平衡方案 |
| INT4 (GPTQ/AWQ) | ~75% | 较小 | 显存紧张 |
| GGUF Q4_K_M | ~75% | 较小 | llama.cpp 专用 |
使用量化模型示例:
bash
# 下载 GPTQ-Int4 版本的 Qwen 后修改:
--model /models/huggingface/Qwen/Qwen2.5-3B-Instruct-GPTQ-Int4 \
--quantization gptq7.5 监控与诊断
bash
# 查看 vLLM 内置指标 (通过日志)
$KUBECTL logs deployment/vllm-qwen7b | grep "metrics.py"
# 输出示例:
# Avg prompt throughput: 12.5 tokens/s
# Avg generation throughput: 35.2 tokens/s
# Running: 1 reqs, GPU KV cache usage: 5.2%
# 查看 GPU 实时状态 (需要 rocm-smi)
$KUBECTL exec deployment/vllm-qwen7b -- rocm-smi
# 查看 GPU 显存详细使用
$KUBECTL exec deployment/vllm-qwen7b -- \
cat /sys/class/drm/card1/device/mem_info_vram_used
# 性能基准测试 (测量响应时间)
$KUBECTL exec deployment/open-webui -- curl -s -w "\nTime: %{time_total}s\n" \
http://vllm-qwen7b:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"qwen2.5-7b","messages":[{"role":"user","content":"写一篇500字的文章"}],"max_tokens":512}'7.6 性能基准参考 (AMD RX 7900 XTX)
| 模型 | 首 token 延迟 | 生成速度 (tokens/s) | 显存占用 |
|---|---|---|---|
| Qwen2.5-7B (FP16, 默认) | ~1-2s | ~20-35 | ~14 GB |
| Qwen2.5-3B (FP16) | ~0.5-1s | ~30-50 | ~6 GB |
| DeepSeek-R1-1.5B (FP16) | ~0.3-0.5s | ~40-60 | ~3 GB |
八、上下文长度配置手册
8.1 核心概念
- Context Length: 模型能处理的最大 token 数 (输入 + 输出)
- Prompt Tokens: 用户输入 + 系统提示 + 历史对话占用的 token
- Completion Tokens: 模型生成的 token
- KV Cache: 存储中间计算结果,随上下文长度线性增长
8.2 当前配置
bash
--max-model-len 16384 # 当前值: 支持 16K token 上下文 (Qwen2.5-7B)显存占用估算 (Qwen2.5-7B):
模型权重: ~14 GB (固定)
KV Cache (16K): ~7 GB (线性增长)
─────────────────────────
总计: ~21 GB (gpu-memory-utilization=0.90 → 上限 21.6 GB)8.3 不同上下文长度的显存需求 (Qwen2.5-7B)
| max-model-len | KV Cache 大小 | 总显存需求 | gpu-memory-utilization 建议 |
|---|---|---|---|
| 4096 | ~2 GB | ~16 GB | 0.70 |
| 8192 | ~4 GB | ~18 GB | 0.80 |
| 16384 (当前) | ~7 GB | ~21 GB | 0.90 |
| 32768 | ~14 GB | ~28 GB | 超出显存,不可行 |
8.4 调整上下文长度
减小到 8K (节省显存,适合简单对话):
bash
# 修改 YAML 中的启动参数
--max-model-len 8192 \
--gpu-memory-utilization 0.80 \当前配置: 16K (默认,日常使用最佳平衡):
bash
--max-model-len 16384 \
--gpu-memory-utilization 0.90 \⚠️ 警告: 7B 模型在 24GB GPU 上不支持 32K 上下文 (需 ~28GB)。 如遇到 OOM Killed,降低
--gpu-memory-utilization或--max-model-len。
8.5 Open WebUI 端上下文设置
Open WebUI 默认使用模型的完整上下文长度。如需限制:
在 Open WebUI 管理界面中:
- Settings → Models → 选择模型
- 调整 "Context Length" 滑块
或通过 API 限制:
bash
# 在请求中指定 max_tokens
curl http://vllm-qwen7b:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5-7b",
"messages": [...],
"max_tokens": 1024
}'8.6 长对话处理策略
当对话历史超过上下文长度时:
| 策略 | 说明 | 实现方式 |
|---|---|---|
| 截断历史 | 只保留最近 N 轮对话 | Open WebUI 自动处理 |
| 摘要压缩 | 将旧对话摘要后保留 | Open WebUI Memory 功能 |
| 增大上下文 | 提高 --max-model-len | 修改 YAML 并重启 |
| 新建对话 | 清空历史重新开始 | 用户手动操作 |
8.7 上下文长度错误排查
错误信息:
This model's maximum context length is 4096 tokens.
However, you requested 5806 tokens in the messages.
Please reduce the length of the messages.解决步骤:
- 检查当前
--max-model-len值:bash$KUBECTL logs deployment/vllm-qwen7b | grep "max_model_len" - 增大
--max-model-len(编辑 YAML →kubectl apply -f) - 同时调整
--gpu-memory-utilization以匹配显存需求 - 重启 Pod 使配置生效
九、已知限制与后续优化
9.1 当前限制
| 限制 | 原因 | 影响 | 缓解措施 |
|---|---|---|---|
| 单模型独占 GPU | 显存不足 | 无法同时运行多个模型 | deploy.sh switch 手动切换 |
| vGPU 手动注册 | HAMi 不支持 AMD | kubelet 重启后需重新注册 | 考虑 AMD Device Plugin |
| HIP Graph 不可用 | gfx1100 不稳定 | 无法使用 CUDA Graph 加速 | 使用 --enforce-eager |
| Triton Flash Attn 不可用 | ROCm 不兼容 | 注意力计算较慢 | 可接受的性能损失 |
| 多进程 IPC 不可用 | ROCm 序列化问题 | 单进程运行 | --disable-frontend-multiprocessing |
| RAG embedding 下载失败 | 容器无外网 | RAG 功能不可用 | 预下载 embedding 模型到本地 |
9.2 后续优化路线图
- 部署 AMD GPU Device Plugin — 实现
amd.com/gpu资源自动注册 - 模型量化 (GPTQ-Int4) — 减少 ~75% 显存占用,可能允许同时运行多模型
- vLLM 版本升级 — v0.7.x+ 可能修复 ROCm 兼容性问题,支持 HIP Graph
- 持久化存储 — 使用 Longhorn/NFS PVC 替代 hostPath
- 负载均衡 — 部署多个 vLLM 实例 + Ingress Controller
- 监控告警 — 集成 Prometheus + Grafana
- RAG 功能 — 预下载 embedding 模型到本地
附录 A: 公网暴露配置
| 组件 | 文件 | 说明 |
|---|---|---|
| DNS | 阿里云 DNS | ai.ai-ear.cn A → 8.153.84.140 |
| frpc | /etc/frp/frpc.toml | open-webui-18080 隧道 (localIP=192.168.122.9, localPort=30080) |
| Traefik | /etc/traefik/dynamic.yaml | ai-open-webui 路由 + TLS |
| 证书 | /etc/pki/nginx/ai.ai-ear.cn.crt | 自签名证书 (365天) |
| K8s Service | open-webui.yaml | NodePort 30080 |
附录 B: 快速恢复命令
bash
# 通用 kubectl 前缀 (在 192.168.122.37 上执行)
KUBECTL="/var/lib/rancher/rke2/bin/kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml"
# 一键重新部署
cd /root/vllm-deploy && bash deploy.sh
# 注册 vGPU (kubelet 重启后)
$KUBECTL patch node szb122009 --type=merge --subresource=status \
-p '{"status":{"capacity":{"amd.com/gpu":"4"},"allocatable":{"amd.com/gpu":"4"}}}'
# 重启所有服务
$KUBECTL rollout restart deployment/vllm-qwen7b
$KUBECTL rollout restart deployment/open-webui
# 切换到 Qwen2.5-7B (默认)
cd /root/vllm-deploy && bash deploy.sh switch qwen7b
# 测试 API
$KUBECTL exec deployment/open-webui -- \
curl -s http://vllm-qwen7b:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"qwen2.5-7b","messages":[{"role":"user","content":"你好"}],"max_tokens":50}'