概述
尝试在单卡3090 24G上部署模型。测试了两个模式:cyankiwi/Qwen3.8-27B-AWQ-INT4 和 cyankiwi/Qwen3.5-9B-AWQ-BF16-INT4。
测试目的是识别图片内容,同时分析是否涉及"涉及"内容。
参考
环境
- 操作系统:Ubuntu22.04
- 显卡驱动:NVIDIA-SMI 595.91.07
- Docker版本:Docker version 29.6.1, build 8900f1d
容器镜像
- ghcr.io/open-webui/open-webui:main
- lmsysorg/sglang:v0.5.18
- vllm/vllm-openai:v0.24.0
部署 cyankiwi/Qwen3.8-27B-AWQ-INT4
使用SGLang部署cyankiwi/Qwen3.8-27B-AWQ-INT4,最大只能支持8K上下文。如果做文本处理,还勉强能够支持,但无法胜任识别图片的需求。
bash
cat /public/SGLang/script/start_qwen38-sglang.sh
bash
#!/bin/bash
IMAGE="lmsysorg/sglang:v0.5.18"
docker run -d --gpus device=0 --shm-size 32g -p 8000:8000 \
--name qwen38-27b-awq-int4 \
-v /public/model/models/Qwen3.8-27B-AWQ-INT4:/models/Qwen3.8-27B \
$IMAGE \
sglang serve \
--model-path /models/Qwen3.8-27B \
--served-model-name Qwen3.8 \
--trust-remote-code \
--tp 1 \
--mem-fraction-static 0.88 \
--max-running-requests 1 \
--max-mamba-cache-size 8 \
--mamba-radix-cache-strategy extra_buffer_lazy \
--disable-prefill-cuda-graph \
--cuda-graph-max-bs-decode 1 \
--chunked-prefill-size 4096 \
--attention-backend flashinfer \
--kv-cache-dtype fp8_e4m3 \
--context-length 8192 \
--reasoning-parser qwen3 \
--tool-call-parser qwen3_coder \
--mamba-ssm-dtype bfloat16 \
--host 0.0.0.0 --port 8000 \
--api-key "your api key"
Docker 启动参数
| 参数 | 示例值 | 说明 |
|---|---|---|
docker run |
- | 创建并启动一个新的 Docker 容器 |
-d |
- | 后台运行容器,返回容器 ID |
--gpus device=0 |
device=0 |
只把宿主机的第 0 号 GPU 分配给容器使用 |
--shm-size 32g |
32g |
设置容器 /dev/shm 共享内存为 32GB,避免多进程/共享内存通信不足 |
-p 8000:8000 |
8000:8000 |
将宿主机 8000 端口映射到容器 8000 端口 |
--name |
qwen38-27b-awq-int4 |
指定容器名称 |
-v |
/public/model/models/Qwen3.8-27B-AWQ-INT4:/models/Qwen3.8-27B |
把宿主机模型目录挂载到容器内 /models/Qwen3.8-27B |
$IMAGE |
环境变量/占位符 | 实际使用的 SGLang Docker 镜像名,需要替换为真实镜像 |
sglang serve |
- | 容器内执行的命令,启动 SGLang OpenAI 兼容 API 服务 |
SGLang 服务参数
| 参数 | 示例值 | 说明 |
|---|---|---|
--model-path |
/models/Qwen3.8-27B |
容器内模型路径,指向挂载进来的模型目录 |
--served-model-name |
Qwen3.8 |
API 中对外暴露的模型名称,客户端请求时使用该名称 |
--trust-remote-code |
- | 允许加载并执行模型仓库中的自定义 Python 代码 |
--tp |
1 |
Tensor Parallel 张量并行度为 1,即单卡运行,不拆分模型 |
--mem-fraction-static |
0.88 |
静态显存池占 GPU 可用显存的比例,越高缓存越多,但过高可能 OOM |
--max-running-requests |
1 |
最大同时运行的请求数为 1,限制并发,适合单请求/低显存场景 |
--max-mamba-cache-size |
8 |
Mamba/SSM 状态缓存的最大容量或槽位数,具体含义依 SGLang 版本而定 |
--mamba-radix-cache-strategy |
extra_buffer_lazy |
Mamba 层 Radix Cache 策略,使用额外缓冲并惰性管理,用于优化缓存复用和显存 |
--disable-prefill-cuda-graph |
- | 禁用 prefill 阶段的 CUDA Graph,可能降低显存占用或规避兼容问题 |
--cuda-graph-max-bs-decode |
1 |
decode 阶段 CUDA Graph 捕获的最大 batch size 为 1,适合单并发 |
--chunked-prefill-size |
4096 |
分块预填充大小,每个 chunk 处理 4096 token,降低长 prompt 峰值显存 |
--attention-backend |
flashinfer |
使用 FlashInfer 作为注意力计算后端 |
--kv-cache-dtype |
fp8_e4m3 |
KV Cache 使用 FP8 E4M3 精度,减少显存占用,可能轻微影响精度 |
--context-length |
8192 |
最大上下文长度为 8192 token |
--reasoning-parser |
qwen3 |
使用 Qwen3 推理内容解析器,解析 thinking/reasoning 输出 |
--tool-call-parser |
qwen3_coder |
使用 Qwen3 Coder 工具调用解析器,把模型输出解析为结构化 tool calls |
--mamba-ssm-dtype |
bfloat16 |
Mamba/SSM 状态或计算使用 bfloat16 精度 |
--host |
0.0.0.0 |
服务监听所有网卡地址,允许容器外访问 |
--port |
8000 |
服务监听端口 |
--api-key |
"your api key" |
API 访问密钥,客户端需携带该密钥请求;生产环境应替换为强密钥 |
部署 cyankiwi/Qwen3.5-9B-AWQ-BF16-INT4
使用vLLM部署cyankiwi/Qwen3.5-9B-AWQ-BF16-INT4,支持32K上下文。可以稳定支持2个并发,每次处理1张图片的需求。
bash
cat /public/vLLM/docker_start_test.sh
bash
#!/bin/bash
# set -x
IMAGE="vllm/vllm-openai:v0.24.0"
MODEL="Qwen3.5-9B-AWQ-BF16-INT4"
NAME="Qwen3.5-9B-AWQ"
API_KEY="your api key"
# 先清理可能存在的同名旧容器,防止冲突
docker rm -f $NAME 2>/dev/null
docker run -d \
--restart always \
--name $NAME \
--gpus all \
-p 8000:8000 \
-v /public/model/models/$MODEL:/model \
$IMAGE \
/model \
--port 8000 \
--host 0.0.0.0 \
--api-key "$API_KEY" \
--quantization compressed-tensors \
--dtype float16 \
--kv-cache-dtype float16 \
--tensor-parallel-size 1 \
--disable-custom-all-reduce \
--max-num-seqs 2 \
--max-num-batched-tokens 8192 \
--block-size 16 \
--enable-chunked-prefill \
--gpu-memory-utilization 0.85 \
--max-model-len 32768 \
--no-enable-prefix-caching \
--reasoning-parser qwen3 \
--tool-call-parser qwen3_xml \
--enable-auto-tool-choice \
--served-model-name $NAME \
--trust-remote-code \
--limit-mm-per-prompt '{"image": 1, "video": 0}' \
--mm-processor-kwargs '{"min_pixels": 313600, "max_pixels": 1200000}' \
--speculative-config '{"method": "mtp", "num_speculative_tokens": 1}'
# --enforce-eager
Docker 启动参数
| 参数 | 示例值 | 说明 |
|---|---|---|
docker run |
- | 创建并启动一个新的 Docker 容器 |
-d |
- | 后台运行容器,返回容器 ID |
--restart always |
always |
容器退出时总是自动重启,适合长期服务 |
--name |
$NAME |
指定容器名称,由环境变量 $NAME 提供 |
--gpus all |
all |
将宿主机所有 GPU 分配给容器使用 |
-p 8000:8000 |
8000:8000 |
将宿主机 8000 端口映射到容器 8000 端口 |
-v |
/public/model/models/$MODEL:/model |
把宿主机模型目录挂载到容器内 /model,$MODEL 为模型目录名 |
$IMAGE |
环境变量/占位符 | 实际使用的 vLLM Docker 镜像名,需要替换为真实镜像 |
| 容器内命令 | /model --port 8000 ... |
镜像入口点通常为 vLLM 的 API 服务器,/model 是模型路径位置参数 |
vLLM 服务参数
| 参数 | 示例值 | 说明 |
|---|---|---|
/model |
- | 位置参数,指定容器内模型路径 |
--port |
8000 |
服务监听端口 |
--host |
0.0.0.0 |
服务监听所有网卡地址,允许容器外访问 |
--api-key |
"$API_KEY" |
API 访问密钥,由环境变量 $API_KEY 提供;生产环境应使用强密钥 |
--quantization |
compressed-tensors |
量化方法,使用 compressed-tensors 格式加载量化模型 |
--dtype |
float16 |
模型计算数据类型为 float16 |
--kv-cache-dtype |
float16 |
KV Cache 使用 float16 精度 |
--tensor-parallel-size |
1 |
张量并行度为 1,即单卡运行,不拆分模型 |
--disable-custom-all-reduce |
- | 禁用自定义 all-reduce 通信,可能回退到默认 NCCL 实现 |
--max-num-seqs |
2 |
最大同时处理的序列数为 2,限制并发 |
--max-num-batched-tokens |
8192 |
单个批次最大 token 数为 8192 |
--block-size |
16 |
PagedAttention 的块大小为 16 |
--enable-chunked-prefill |
- | 启用分块预填充,降低长 prompt 的峰值显存 |
--gpu-memory-utilization |
0.85 |
GPU 显存利用率目标为 0.85,即使用 85% 的显存 |
--max-model-len |
32768 |
最大模型上下文长度为 32768 token |
--no-enable-prefix-caching |
- | 禁用前缀缓存,不复用相同前缀的 KV Cache |
--reasoning-parser |
qwen3 |
使用 Qwen3 推理内容解析器,解析 thinking/reasoning 输出 |
--tool-call-parser |
qwen3_xml |
使用 Qwen3 XML 工具调用解析器,把模型输出解析为结构化 tool calls |
--enable-auto-tool-choice |
- | 启用自动工具选择,允许模型自动决定是否调用工具 |
--served-model-name |
$NAME |
API 中对外暴露的模型名称,由环境变量 $NAME 提供 |
--trust-remote-code |
- | 允许加载并执行模型仓库中的自定义 Python 代码 |
--limit-mm-per-prompt |
'{"image": 1, "video": 0}' |
每个 prompt 限制多模态输入:最多 1 张图片,0 个视频 |
--mm-processor-kwargs |
'{"min_pixels": 313600, "max_pixels": 1200000}' |
多模态处理器参数,设置图像最小和最大像素数 |
--speculative-config |
'{"method": "mtp", "num_speculative_tokens": 1}' |
投机解码配置,使用 MTP 方法,投机 token 数为 1 |
# --enforce-eager |
- | 被注释掉,未生效。若启用会强制使用 eager 模式,禁用 CUDA Graph |
部署OpenWebUI
bash
cat /public/OpenWebUI/script/start_OpenWebUI.sh
bash
#!/bin/bash
docker run -d \
-p 3000:8080 \
--add-host=host.docker.internal:host-gateway \
-e OPENAI_API_BASE_URL=http://host.docker.internal:8000/v1 \
-e OPENAI_API_KEY='your api key' \
-e WEBUI_SECRET_KEY='change-me-to-a-random-string' \
-v open-webui:/app/backend/data \
--name open-webui \
--restart always \
ghcr.io/open-webui/open-webui:main