8×Tesla T10 · vLLM SM75 · GPUStack v2.2.3
生产路径:GPUStack 后端 + A 路线(image4 / video0)
阅读导航
| 阶段 | 章节入口 |
|---|---|
| 部署准备 | 0 部署前检查 · 1 克隆仓库 · 2 构建镜像 |
| 平台配置 | 3 启动 Server · 4 创建 API Key · 5 启动 Worker · 6 注册后端 |
| 模型上线 | 7 部署模型 · 8 执行验收 |
| 功能与测试 | 9 面板与工作台 · 10 测速与雷达图 |
| 查询与排错 | 11 参数速查 · 12 排错速查 · 附录 A 参数说明 |
本文提供完整的部署、验证和故障排查步骤。命令均可直接复制;参数说明见附录 A。
| 项目 | 本文采用的配置 |
|---|---|
| GPU | 8×Tesla T10,计算能力 sm_75,单卡显存 16 GiB |
| 主机内存 | 251 GiB |
| 管理平台 | GPUStack v2.2.3 |
| 推理后端 | vLLM SM75 自定义后端 |
| 默认路线 | A 路线:保留图像输入,单请求最多 4 张;禁用视频输入 |
| 交付范围 | 模型部署、控制面板、三个 BenchLocal 校验器、测速、雷达图和故障排查 |
| 性能数据 | 测试条件与对照结果见 §10 |
0 部署前检查
| 检查项 | 要求 | 说明 |
|---|---|---|
| 主机内存 | 约 251 GiB | 参数 --engram-config={"cpu_offload":true} 会将部分权重常驻主机内存;64 GiB 主机可能在加载阶段触发 OOM killer,表现为容器异常退出 |
| 磁盘 | 数据目录所在磁盘可用空间 ≥ 250 GiB | 17 个 *.safetensors 权重文件合计 181,196,007,016 B(约 168.8 GiB),另需预留镜像和缓存空间 |
| 网络 | 记录宿主机内网 IP,本文记为 HOST_IP | Worker 和浏览器都必须能够访问该地址 |
| 数据目录 | 预先创建目录,本文记为 GS_DATA_DIR,例如 /data/gpustack-data;普通用户必须具有写权限 | 如果目录不存在,docker create 阶段即会失败;GPUStack 还可能以 root 身份调整目录属主 |
export HOST_IP=<你的内网 IP> # 换成你这台机实际的内网地址
export GS_DATA_DIR=<你的数据目录> # 例:/data/gpustack-data(要先建好、普通账号可写)
HOST_IP 与 GS_DATA_DIR 是全文统一变量。本文所有命令里“你这台机器”的值都由这两个变量提供,后续命令可直接复制。
构建前先拉取以下两项基础镜像。上游基座落盘后约占 42 GiB;提前拉取可避免构建过程长时间停留在镜像下载阶段。
docker pull vllm/vllm-openai:v0.30.0-cu129@sha256:58fdb6bb123a81aa53f46fa4652ad8cc87e817bd1077c9832c6258ef12c1c688 # 上游基座,落盘约 42 GiB(构建后 SM75 后端约 64 GB)
docker pull quay.io/gpustack/gpustack:v2.2.3 # 平台本体,约 1 GB
以下版本组合已通过本次实测。本文不保证更早、更新或其他发行版同样兼容;调整版本后应重新执行完整验收。
| 组件 | 本次实测通过的版本 | 说明 |
|---|---|---|
| 操作系统 | Ubuntu 24.04.5 LTS(内核 6.8.0-146-generic) | 其他发行版未验证 |
| NVIDIA 驱动 | 580.178.04(CUDA Version 13.0) | 镜像里 torch 是 cu130 ⇒ 驱动 API 必须 ≥ 13.0 |
| Docker | 29.8.0(storage overlayfs,cgroup v2) | cgroup v1 未验证 |
| containerd | 2.3.5 | |
| NVIDIA Container Toolkit | 1.20.0(libnvidia-container 1.20.0-1) | –runtime nvidia 依赖它 |
| GPUStack | quay.io/gpustack/gpustack:v2.2.3 | 所有 API/字段按 2.2.3 核对 |
1 克隆仓库
git clone https://github.com/lichangfeng-1/vllm-sm75-gpustack-backend.git
cd vllm-sm75-gpustack-backend
本文命令一律在包根目录执行。
2 检查依赖并构建后端镜像
bash gpustack/preflight-sources-v1.sh # 只读 HEAD 检查;检查失败时停止后续步骤
bash gpustack/build-backend-v1.sh --two-stage # 默认两段(已验证):先建 SM75 基座,再建自定义后端
-
vllm-sm75:v0.1.7-beta2仅作为内部构建缓存,不属于最终交付物。最终镜像为vllm-sm75-gpustack:v0.1.7-beta2-v7;该版本在运行时固定使用 transformers 5.15.1 和 tokenizers 0.22.2。 -
--rebuild-base用于强制重建基座;--drop-base会在后端构建成功后删除基座 tag。后者可以节省磁盘空间,但下次构建时需要重新生成基座。 -
Docker 构建无法消除镜像中间层;
--drop-base仅删除中间产物的 tag。
需要分步排查时,可执行以下等价命令:
bash gpustack/build-gpustack-v1.sh --build
docker build --file gpustack/Dockerfile.v1 --target runtime-pin-layer \
--build-arg BASE_TAG=vllm-sm75:v0.1.7-beta2 \
--build-arg TF_VERSION=5.15.1 \
--build-arg TOKENIZERS_VERSION=0.22.2 \
-t vllm-sm75-gpustack:v0.1.7-beta2-v7 .
末端必须使用 runtime-pin-layer 目标层。该目标层包含前四层、面板负载、BenchLocal 运行时、随仓测试资产、DSH 工作台和运行期固定版本。最终镜像同时承担四项功能:运行模型、启动面板、启动三个校验器,以及提供 Ultra 工作台。该镜像也可单独用于启动面板,此时需将入口改为 runtime-entrypoint.py,详见 §9 末尾。
3 启动 GPUStack Server
docker run -d --name gpustack-server --restart unless-stopped \
--network bridge --env TZ=Asia/Shanghai \
-p ${HOST_IP}:8180:80 \
-v ${GS_DATA_DIR}:/var/lib/gpustack \
quay.io/gpustack/gpustack:v2.2.3
| 配置项 | 本文设置 | 说明 |
|---|---|---|
| 网关端口 | 8180 | 不是 8080;config.py:922-927 对非 Worker 角色返回 self.port |
| 重启策略 | unless-stopped | 进程异常退出或宿主机重启后自动恢复;显式执行 docker stop 后保持停止 |
| 特权与挂载 | 不启用特权模式,不挂载 docker.sock | 这两项仅为 Worker 所需;实测 Server 的 Privileged=false,且只挂载数据目录 |
| 时区 | TZ=Asia/Shanghai | 省略后,日志和定时任务将使用 UTC |
| 初始管理员密码 | ${GS_DATA_DIR}/initial_admin_password | 首次启动后生成 12 字符密码;修改密码后,该文件会被删除 |
4 登录并创建 API Key

GPUStack 概览:Clusters / Workers / GPUs / Deployments
-
管理员登录接口为
POST /auth/login,路径不包含/v2前缀。 -
网关 API key 只在创建时显示一次。平台只保存散列,之后无法找回;创建后应立即保存,后文记作 GS_KEY。
5 启动 GPUStack Worker

Workers 页:8 卡 worker 就绪
同机部署不需要单独传入 token。Worker 会从自身的 data_dir 读取注册令牌,因此必须将 ${GS_DATA_DIR} 挂载到容器内的 /var/lib/gpustack,并与 Server 使用相同的目标路径。
docker create --name gpustack-worker --hostname gpustack-worker \
--restart unless-stopped --env TZ=Asia/Shanghai \
--privileged --network host --runtime nvidia \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--mount type=bind,source=${GS_DATA_DIR},target=/var/lib/gpustack \
quay.io/gpustack/gpustack:v2.2.3 \
--server-url http://${HOST_IP}:8180 \
--advertise-address ${HOST_IP} \
--worker-name gpustack-worker
docker start gpustack-worker
跨机部署需要 token 时应直接向 server 获取:
curl -s -H "X-API-Key: ${GS_KEY}" http://${HOST_IP}:8180/v2/clusters/1/registration-token
响应包含 token、server_url、image、env 和 args 五个字段。其中,server_url 应为 http://${HOST_IP}:8180,env 包含 GPUSTACK_TOKEN,args 为空。可通过 -e GPUSTACK_TOKEN=… 或 --token … 传入令牌。该令牌具有写入权限,可能出现在进程列表和 shell 历史中;完成注册后应立即轮换。
GET /v2/clusters/{id}/manifests 仅适用于 Kubernetes 集群。Docker provider 调用该接口会返回 422,不能用它获取 Worker 启动命令。
网络配置基线:Server 使用 bridge 网络,并且只映射 8180 端口。Worker 必须保留 host 网络,因为它通过 docker.sock 管理模型容器,而模型实例端口直接监听宿主机网络命名空间。若将 Worker 改为 bridge 网络,还需映射 10150 端口和所有模型端口,并重新验证注册与调度流程;本文不采用该方案。模型实例使用 host 网络,三个校验器使用不映射宿主机端口的 internal bridge,面板发布 1615 端口,无头测速容器按需使用 host 网络。
6 注册自定义后端版本

推理后端页:vLLM 自定义版本入口
在界面中选择 vLLM 后端,并填写以下配置:版本 0.1.7-sm75.1-fast-custom、自定义框架 CUDA、镜像 vllm-sm75-gpustack:v0.1.7-beta2-v7。入口覆盖填写:
python3 /opt/vllm-sm75/panel-sidecar.py vllm serve
也可以通过 API 完成配置。version_configs 是以版本名为键的字典,entrypoint 必须使用字符串类型。
curl -s -X PUT -H "X-API-Key: ${GS_KEY}" -H 'Content-Type: application/json' \
-d '{"backend_name":"vLLM","version_configs":{"0.1.7-sm75.1-fast-custom":{
"image_name":"vllm-sm75-gpustack:v0.1.7-beta2-v7",
"custom_framework":"cuda",
"entrypoint":"python3 /opt/vllm-sm75/panel-sidecar.py vllm serve"}}}' \
http://${HOST_IP}:8180/v2/inference-backends/1
-
版本名和镜像必须保持默认值,不要改成其他版本或镜像。
-
提交时必须满足四项约束:版本名必须以
-custom结尾;内置后端不能设置default_version;backend_name不可修改;PUT 请求按整条记录覆盖。遗漏字段会删除对应配置;存在多个版本时,应先合并完整记录再提交。
7 部署模型

模型广场:从 ModelScope 选择模型入口
来源 ModelScope|模型 ID Intel/Qwen3.8-Flash-Next-W4A16-AutoRound|后端版本 0.1.7-sm75.1-fast-custom|副本 1。
7.1 后端参数(24 行,A 路线,整体粘贴)
--dtype=float16
--hf-overrides={"dtype":"float16"}
--tensor-parallel-size=8
--enable-expert-parallel
--enable-ep-weight-filter
--limit-mm-per-prompt={"image":4,"video":0}
--max-model-len=262144
--max-num-seqs=4
--max-num-batched-tokens=4096
--gpu-memory-utilization=0.92
--kv-cache-dtype=fp8_e4m3
--kv-cache-memory-bytes=2415919104
--enable-prefix-caching
--engram-config={"cpu_offload":true}
--gdn-prefill-backend=flashqla_sm75
--generation-config=vllm
--enable-prompt-tokens-details
--compilation-config={"mode":0,"cudagraph_mode":"PIECEWISE","cudagraph_capture_sizes":[1,2,4,8,16]}
--block-size=16
--scheduler-cls=vllm.v1.core.sched.scheduler_sm75.SM75Scheduler
--enable-auto-tool-choice
--tool-call-parser=qwen3_xml
--reasoning-parser=qwen3
--chat-template=/opt/vllm-sm75/templates/qwen38-next-high-compat.jinja
7.2 环境变量(25 行,整体粘贴)
NCCL_P2P_LEVEL=SYS
VLLM_USE_MODELSCOPE=false
VLLM_FIREFLY=auto
HF_HUB_OFFLINE=1
TRANSFORMERS_OFFLINE=1
NCCL_DEBUG=WARN
NCCL_IB_DISABLE=1
NCCL_P2P_DISABLE=0
OMP_NUM_THREADS=1
VLLM_SM75_QWEN38_HC_GEMV=1
VLLM_FLASHINFER_WORKSPACE_BUFFER_SIZE=134217728
VLLM_USE_BREAKABLE_CUDAGRAPH=1
VLLM_WORKER_MULTIPROC_METHOD=spawn
VLLM_SPARSE_INDEXER_MAX_LOGITS_MB=16
VLLM_SM75_QSA_FLASHINFER_PREFILL=1
VLLM_SM75_QSA_SHARED_TARGET_SCRATCH=1
VLLM_SM75_QSA_FP8_MAIN_KV=1
VLLM_SM75_QSA_CUBLAS_INDEXER=1
VLLM_SM75_QSA_SELECTED_PAGES_PREFILL=1
VLLM_ENFORCE_STRICT_TOOL_CALLING=1
VLLM_SM75_QSA_MIXED_PREFILL=1
VLLM_ALLREDUCE_USE_FLASHINFER_PCIE_IPC=1
TZ=Asia/Shanghai
GPUSTACK_MODEL_RUNTIME_SHM_SIZE_GIB=64
GPUSTACK_MODEL_VRAM_CLAIM=120779177984
粘贴后执行 bash gpustack/lint-paste-v1.sh。最后一行必须显示 LINT_PASTE_OK env=25 args=24。随后追加 §7.2.1 的 6 行缓存变量和 §7.3 的 8 行面板及校验器变量,合计 39 行。
两条硬性提醒:
-
第 24 行:漏掉 GPUSTACK_MODEL_RUNTIME_SHM_SIZE_GIB=64 时,平台会使用默认的 10 G。可在容器内执行 df -h /dev/shm 验证。
-
第 25 行:
GPUSTACK_MODEL_VRAM_CLAIM是调度准入值,不等于真实显存需求。未设置时,平台会按启发式估算为 204.5 GiB;本机可调度显存仅为 117.76 GiB,因此模型会持续处于 Pending。默认值 120779177984 折合每卡 14,398 MiB,低于多模态实测的每卡 15,372 MiB,属于放宽准入的申报值。该配置只适用于没有其他 GPU 工作负载的专用八卡 Worker。严格按实测占用申报时,8 卡总值至少应为 128949682176 字节;但该值高于本机可调度容量,模型仍可能处于 Pending。更换机器后,应按“实测逐卡驻留 MiB × 卡数 × 1048576”重新计算。
7.2.1 编译缓存(6 行,默认启用)
将以下 6 行与前述 25 行环境变量粘贴到同一区域。首次启动时,初始化引擎并生成缓存耗时 213.48 秒;第二次启动命中缓存后,该阶段耗时 30.95 秒,降低 85.5%。权重加载仍需约 210 秒,因此缓存不能消除全部启动时间。本机第二次启动从创建副本到 /health 返回 200,耗时约 6 分 54 秒。
FLASHINFER_WORKSPACE_BASE=/var/lib/gpustack/cache
HUMMING_CACHE_DIR=/var/lib/gpustack/cache/humming
CUDA_CACHE_PATH=/var/lib/gpustack/cache/cuda
TRITON_CACHE_DIR=/var/lib/gpustack/cache/triton
TORCHINDUCTOR_CACHE_DIR=/var/lib/gpustack/cache/inductor
TORCH_EXTENSIONS_DIR=/var/lib/gpustack/cache/torch_extensions
| 场景 | 操作要求 | 说明 |
|---|---|---|
| 缓存位置 | 宿主机使用 ${GS_DATA_DIR}/cache,容器内使用 /var/lib/gpustack/cache | 缓存随 Worker 数据目录持久化;不要写入 /tmp 或容器可写层 |
| 正常运行 | 无需定期清空缓存 | 当前缓存约 44 MiB,无需部署常驻清理服务 |
| 更换镜像或升级依赖 | 停止模型后,先将缓存目录改名为 *.bak-日期;新版本首次启动成功后再删除备份 | 适用于升级 torch、CUDA 或 transformers 等场景 |
| 容量检查 | 每月执行 du -sh ${GS_DATA_DIR}/cache/* ${GS_DATA_DIR}/cache/.cache/* | 总量超过 2 GiB 时,再检查并处理 30 天前的文件 |
| 过期文件检查 | 执行 find ${GS_DATA_DIR}/cache -type f -mtime +30 -print,确认后再使用 -delete | 删除前必须核对输出,避免误删仍在使用的缓存 |
| 实测边界 | 6 个变量按整组验证,不单独承诺每个变量的性能收益 | 实测未生成 HUMMING_CACHE_DIR 对应目录;清空缓存后,首次初始化时间将恢复到约 213 秒 |
7.3 面板与扩展变量(本交付默认;不使用面板或校验器时可省略)
将以下 8 行追加到 GPUStack 模型部署表单的“环境变量”区域,与前述 25 行环境变量一起提交。不要在宿主机 shell 中执行这些变量。
SM75_PANEL_AUTOSTART=1
SM75_CONSOLE_HOST=0.0.0.0
SM75_CONSOLE_ROOT=/var/lib/gpustack/panel
SM75_CONSOLE_PORT=1615
SM75_EXTENSIONS=panel,harness,benchlocal,speedtest,sql
SM75_BENCH_VERIFIERS_MODE=external
SM75_BENCH_VERIFIER_CONFIG_FILE=/var/lib/gpustack/benchlocal/benchlocal.env
SM75_BENCH_VERIFIER_STATE_DIR=/var/lib/gpustack/benchlocal
| 配置项 | 作用 | 配置要求 |
|---|---|---|
SM75_CONSOLE_HOST、SM75_CONSOLE_PORT | 设置面板监听地址和端口 | 端口统一设为 1615;SM75_CONSOLE_HOST 决定是否允许远程访问 |
SM75_CONSOLE_ROOT | 保存面板状态和登录令牌 | 必须指向 Worker 数据目录;登录令牌位于 $SM75_CONSOLE_ROOT/key |
SM75_EXTENSIONS | 选择控制面板、Ultra 工作台、校验器和测试资产 | panel 表示控制面板,harness 表示 Ultra 工作台,benchlocal 表示三个校验器,speedtest 和 sql 表示相应测试资产;仅需要面板时设为 panel |
SM75_BENCH_VERIFIERS_MODE | 设置校验器运行模式 | 本文使用 external,由宿主机运行三个独立容器 |
SM75_BENCH_VERIFIER_CONFIG_FILE | 向面板提供校验器地址 | 宿主机 launcher 将地址写入 benchlocal.env,面板从该文件读取 |
SM75_BENCH_VERIFIER_STATE_DIR | 保存校验器启停状态 | 宿主机看护进程根据 benchlocal.enabled 启动或停止容器;安装步骤见 §9 |
-
未设置
SM75_PANEL_AUTOSTART时,入口脚本只转发原始启动命令,不启动面板。省略全部 8 行变量后,模型仅运行推理引擎;当 1615 端口不可访问时,宿主机看护进程会停止三个校验器容器。 -
在 GPUStack 托管模式下,面板会自动进入外部引擎模式,并隐藏“模型库”“运行配置”和“设置”。模型启停及连接由 GPUStack 管理;速度测试、SQL、BenchLocal、监控和工作台仍可正常使用。只有直接启动带面板的 SM75 实例时,才保留完整的运行配置功能。
-
GPUStack 还会自动补充
SAFETENSORS_FAST_GPU、RUNAI_STREAMER_*、VLLM_CACHE_ROOT等默认变量,因此表单回显数量可能多于手动提交的数量。应按变量名检查必需项,不应仅按总数判断配置是否正确。 -
启动顺序:先在宿主执行 §9 的 benchlocal-containers-v1.sh start,写好 benchlocal.env,再启动模型。面板只在启动时读取一次配置;如果先启动模型,面板会读不到配置,BenchLocal 将一直显示未配置,此时需要重启面板或模型。
7.4 多模态开关(图/视频)

部署页:模型副本运行中
| 目标配置 | 参数调整 |
|---|---|
| 仅启用文本 | 删除 --limit-mm-per-prompt={"image":4,"video":0},添加 --language-model-only |
| 启用图像并禁用视频(本交付默认) | 保留 --limit-mm-per-prompt={"image":4,"video":0} |
| 启用图像且不设置显式上限 | 删除 --limit-mm-per-prompt,且不要添加 --language-model-only;引擎默认上限为 999,风险较高 |
| 启用图像,单请求最多 8 张 | 将参数替换为 --limit-mm-per-prompt={"image":8,"video":0} |
| 同时启用图像和视频 | 将参数替换为 --limit-mm-per-prompt={"image":4,"video":1} |
多模态 JSON 必须紧贴等号且内部不能有空格。GPUStack 会按空格切分参数。未指定模态时,vLLM 默认返回 999,而不是 1;对应代码位于 vllm/config/multimodal.py:478-489,注释为 “Unspecified modality is set to 999 by default”。因此建议始终显式设置上限。每增加一种模态,都应重新计算 claim。启用多模态后,实测显存占用为每卡 15,372 MiB,8 卡合计 128949682176 字节,高于默认 claim 对应的每卡 14,398 MiB。默认 claim 只用于专用 Worker 的放宽准入,不能作为真实显存占用或资源共享依据。将图像上限设置为 8 仅表示接口允许该数量,不代表当前硬件一定能够稳定运行。
A 路线在默认交付配置和 SMT Off 条件下的实测结果为:8192 对应 57.05,16384 对应 56.67,32768 对应 56.78,平均值为 56.83;对照实验结果为 57.04,差异处于测试噪声范围内。与同一镜像的 text-only 配置相比,差值为 0.1–0.6,未观察到明显性能下降。单图基础功能测试返回 multimodal_tokens.image=64,且回答正确。video:0 表示禁用视频输入;携带视频的请求会被拒绝,而不是转换为文本。
图像上限按请求计算,当前配置允许每个请求最多包含 4 张图片。引擎不会自动移除历史图片。如果需要仅保留最近的图片,客户端必须维护消息滑动窗口,并从 messages 中删除较早的消息及其图片。
8 执行验收
docker ps --format '{{.Names}} {{.Status}}' | grep run- # 1 实例容器在跑
curl -s -H "Authorization: Bearer ${GS_KEY}" -H 'Content-Type: application/json' \
-d '{"model":"qwen3.8-flash-next-w4a16-autoround","messages":[{"role":"user","content":"你好"}],"max_tokens":256}' \
http://${HOST_IP}:8180/v1/chat/completions # 2 正文非空
nvidia-smi --query-gpu=memory.used --format=csv,noheader # 3 逐卡 ≤ 15500 MiB
INST="$(docker ps --format '{{.Names}}' | grep run- | head -1)"
docker logs "$INST" 2>&1 | grep -ciE "out of memory|CUDA error|Traceback" # 4 须为 0
第 2 项验收有两个前提。首先,max_tokens 必须留出足够预算;当前配置启用了 --reasoning-parser=qwen3,预算过小时,推理 token 可能耗尽额度,导致接口返回 200 但正文为空。其次,GS_KEY 必须在创建时妥善保存,否则无法从平台重新读取完整密钥。
9 面板、校验器与 Ultra 工作台

模型测试:BenchLocal 六项与历史结果

工作台(DSH)入口

使用统计:Token / 缓存命中 / 每日活跃

插件页
完成 §7.3 的变量配置后,面板会随模型启动。可执行以下命令检查状态并读取登录令牌:
curl -s -o /dev/null -w '%{http_code}\n' http://${HOST_IP}:1615/ # 期望 200
docker exec "$INST" cat /var/lib/gpustack/panel/key # 登录令牌
端口统一为 1615:模型行应显式设置 SM75_CONSOLE_PORT=1615。端口状态以容器 /proc/net/tcp 中的监听记录为准(1615=064F、1616=0650),不要只看 panel.log 尾部,因为其中可能混有早先容器的日志。
默认部署包含三个独立容器:bugfind-15、cli-40 和 hermesagent-20。这些校验器不在模型容器中运行。模型配置只读取 §7.3 中 external 模式的三项共享配置;宿主机上的 benchlocal-containers-v1.sh 负责启动容器、发现网络 IP 并写入配置。由于单个模型配置只会创建一个模型容器,且平台没有通用 sidecar 机制,这三个校验器必须由宿主机 launcher 管理,不能加入模型启动参数。
export GPUSTACK_DATA_ROOT="${GS_DATA_DIR}"
bash gpustack/benchlocal-containers-v1.sh start
bash gpustack/benchlocal-containers-v1.sh status
# 期望三行:sm75-bench-* running ip=... health=ok;PANEL 200、FLAG 1
看护进程必须常驻。面板关闭或模型停止时,该进程负责停止三个校验器容器并释放 CPU 和内存;面板恢复后再自动启动。可任选以下一种运行方式:
# 有 root:30 秒周期的 systemd timer
sudo install -m755 gpustack/benchlocal-containers-v1.sh \
/usr/local/sbin/benchlocal-containers-v1.sh
sudo install -m644 gpustack/systemd/sm75-bench-verifiers.{service,timer} /etc/systemd/system/
sudo install -m600 gpustack/systemd/sm75-bench-verifiers.env.example /etc/sm75-bench-verifiers.env
# 编辑 /etc/sm75-bench-verifiers.env:GPUSTACK_DATA_ROOT、IMAGE
sudo systemctl daemon-reload
sudo systemctl enable --now sm75-bench-verifiers.timer
# 无 root:用户 cron,每分钟一次;先写一个短包装脚本
cat > "$HOME/benchlocal-sync.sh" <<EOF
#!/usr/bin/env bash
export GPUSTACK_DATA_ROOT="${GS_DATA_DIR}"
export IMAGE=vllm-sm75-gpustack:v0.1.7-beta2-v7
exec flock -n /tmp/sm75-bench-sync.lock \
$(pwd)/gpustack/benchlocal-containers-v1.sh sync
EOF
chmod +x "$HOME/benchlocal-sync.sh"
( crontab -l 2>/dev/null; echo "* * * * * $HOME/benchlocal-sync.sh >> $HOME/benchlocal-sync.log 2>&1" ) | crontab -
面板将 BenchLocal 开关写入 ${GPUSTACK_DATA_ROOT}/benchlocal/benchlocal.enabled。看护进程读取到 0 时停止校验器,读取到 1 时启动校验器;模型停止或面板 1615 端口不可访问时也会停止校验器。stop 只停止容器,不删除容器,因此容器 IP 会保留,恢复后无需修改配置。
镜像 tag 指向新 digest 后,应先执行一次 sync --replace;看护进程不会自动重建容器。默认模式为 external,不要切换为 local。若不再使用校验器,应从 SM75_EXTENSIONS 中移除 benchlocal,或将整行设置为 panel;随后停用 systemd timer 或 cron 看护任务,并执行 bash gpustack/benchlocal-containers-v1.sh stop。仅删除 external 模式的三项变量并不能停用校验器,仍在运行的看护任务会再次启动容器。
Ultra 工作台中的“使用统计”“工作台”和“插件”页面由镜像内的 DSH 提供。首次打开这些页面时,控制台会按需启动 DSH。
# 登录后查状态(把 COOKIE 换成你的会话)
curl -s -b "$COOKIE" http://${HOST_IP}:1615/console-api/harness # running:true
curl -s -o /dev/null -w '%{http_code}\n' -b "$COOKIE" http://${HOST_IP}:1615/harness-ui/ # 200
-
DSH 使用 uid/gid 1000 运行。
/dsh/home和/dsh/workspace实际保存在/var/lib/gpustack/dsh/,并随 Worker 数据目录持久化。 -
GPUStack 每次重启引擎时都可能重新分配 400xx 端口。工作台中
sm75-plugins.patch.json和profiles/web/cordis.patch.yml的 baseURL 必须指向当前端口。连接失败时,先执行docker exec "$INST" sh -lc "tr '\0' ' ' < /proc/1/cmdline | grep -o -- '--port [0-9]*'"获取端口,再更新两处配置并重新打开工作台。 -
工作台日志位于
$SM75_CONSOLE_ROOT/harness-process.log。DSH 启动失败时,应首先检查该文件。 -
当前 DSH 版本 0.2.0-rc.2。
9.1 配置模型与思考强度
快速会话页面在输入框上方提供“模型”和“思考强度”两个选项。模型应选择当前引擎;各思考强度对应关系如下。
| 思考强度 | 思考预算 | 使用说明 |
|---|---|---|
| 模型默认 | 由模型配置决定 | 保留当前模型的默认行为 |
| 关闭 | 0 tokens | 不启用额外思考预算 |
| 低 | 1,024 tokens | 适用于较简单的任务 |
| 中 | 4,096 tokens | 适用于需要一定推理过程的任务 |
| 高 | 16,384 tokens | 适用于复杂任务;应同步保证 max_tokens 足够 |
参考截图:16-快速会话-模型与思考强度-20261019.png。
-
在工作台中,点击输入框右下角的模型名称。弹窗上方用于选择模型,下方用于选择推理等级;DSH 0.2 的推理等级仅在该弹窗中设置。参考截图:
17-工作台-模型与推理等级-20261019.png。 -
GPUStack 将引擎参数写为
--reasoning-parser=qwen3。控制台同时兼容等号和空格两种参数形式,并已为等号形式提供单元测试,因此可以正确识别思考能力。 -
验证时,
GET /console-api/profiles/gpustack-external/chat-config应返回"thinking":true,DSH 的sm75-plugins.patch.json应包含reasoningEfforts。启用思考后,单次对话响应中的usage.completion_tokens_details.reasoning_tokens应大于 0。
如需仅启动面板而不运行模型,可使用同一镜像执行以下命令。该模式会保留完整的运行配置功能。
docker run -d --name sm75-panel --restart unless-stopped --runtime nvidia \
--shm-size 64g -p 1615:1615 \
-e SM75_EDITION=ultra -e SM75_CONSOLE_ROOT=/data -e SM75_CONSOLE_HOST=0.0.0.0 -e SM75_CONSOLE_PORT=1615 \
-v "$PANEL_DATA:/data" \
--entrypoint python3 vllm-sm75-gpustack:v0.1.7-beta2-v7 \
/opt/vllm-sm75/runtime-entrypoint.py
独立运行 AutoRound A 路线时,必须在 profile 的 env 中补充 VLLM_ALLREDUCE_USE_FLASHINFER_PCIE_IPC=1、NCCL_P2P_LEVEL=SYS 和 VLLM_FIREFLY=auto。缺少这些变量时,8192 档位仅约 41 tok/s,并进入 Firefly 路径。补齐变量后,同一测试方法下的三次结果为 56.32、57.28、56.77 tok/s,中位数为 56.77,与 GPUStack 托管模式处于同一水平。引擎鉴权应使用 $SM75_CONSOLE_ROOT/engine-key.current,不能使用面板登录令牌。
text-only 配置使用 --language-model-only,且不设置图像限额。同一测试方法下,8192 档位三次结果为 57.52、57.25、58.51 tok/s,中位数为 57.52。A 路线保留图像时约为 56.8 tok/s;两组结果的配置不同,不应直接合并比较。
若独立面板需要默认启用测速功能,请在容器 env 中加入 SM75_EXTENSIONS=panel,harness,speedtest,sql 和 SM75_EXTENSIONS_FORCE=1。SM75_EXTENSIONS_FORCE=1 会重新启用此前手动关闭的测速和 SQL 扩展。默认不设置该变量,以保留“仅首次启动时启用”的行为。
DSH 0.2.0-rc.2 内置 dsh-compaction-image-offload。当请求中的图片超过预算时,它会将最早的图片替换为占位文本并重试,而不是固定保留最近 N 张;被卸载的图片不会自动恢复。为配合引擎的 image:4 限制,建议适当降低工作台的图片预算,并在长会话中主动执行 /compact。如果必须严格保留最近 4 张图片,客户端仍需自行维护消息窗口。
10 测速与雷达图
推荐使用面板内测速:登录 http://${HOST_IP}:1615/ → 模型测试 → 吞吐测试。测试资产已随镜像分发,不需要另行安装;页面由面板 1615 提供。测速请求从浏览器直连引擎 400xx,不经过面板代理。引擎端口没有鉴权,因此面板只供管理员使用。
如需在无界面环境中复测并保存结果,可执行以下命令:
# ① 从镜像里取已装好的测速资产(manifest 已在镜像内)
docker run --rm -v "$PWD/bench-seed:/speedtest" --entrypoint sh \
vllm-sm75-gpustack:v0.1.7-beta2-v7 -c 'cp -a /opt/sm75-workbench/extensions/speedtest/. /speedtest/'
# ② 无头复跑(cfg 里填 base_url、model、key_file 与九档参数)
docker run --rm --network host \
-v "$PWD/bench-seed:/speedtest:ro" -v "$PWD/cfg.json:/work/cfg.json:ro" \
-v "$KEY_FILE:/run/secrets/gs_apikey:ro" -v "$PWD/out:/work/out" \
--entrypoint python3 vllm-sm75-gpustack:v0.1.7-beta2-v7 \
/opt/sm75-workbench/console/benchmark-runner.py /speedtest /work/cfg.json
测试参数为:并发数 1、超时 30000 ms、输出长度 1024、最小长度 512、最大长度 131072、步长 128、倍数 2、Temperature 1、Top P 0.95、Presence 0、Frequency 0。
面板中的“平均总输出”按 (各档结果之和 + 当前批次结果) ÷ (已完成档数 + 1) 计算,即分母包含当前批次。
10.1 本机实测数据(2026-10-20,SMT Off,AutoRound;引用时必须包含完整测试条件)
| 后端/形态 | 路径 | 8192 | 16384 | 32768 | 均值 |
|---|---|---|---|---|---|
| 默认交付(仓库一条命令构建,钉 5.15.1/0.22.2)+A 路线 | 页面 1615;请求直连 400xx | 57.05 | 56.67 | 56.78 | 56.83 |
| 独立面板对照(AutoRound A 路线,补 ALLREDUCE) | 容器内 8000,8192 三次 | 56.32 / 57.28 / 56.77 | — | — | 中位 56.77 |
| 独立面板对照(AutoRound text-only,补 ALLREDUCE) | 容器内 8000,8192 三次 | 57.52 / 57.25 / 58.51 | — | — | 中位 57.52 |
-
不同请求路径的结果不能直接比较。在同一引擎上,经网关请求比面板直连低约 1–2 tok/s;SMT On 与 SMT Off 的差异约为 8%。
-
关键变量:transformers/tokenizers 必须成对固定为 5.15.1/0.22.2,不要单独升级或降级其中一个。
引用测速结果必须保留完整条件:output 1024、top_p 0.95。面板全新默认值是 512/0.1,测速前必须手动修改,否则数据不可比较。8192、16384、32768 为单次扫读;同一配置多次结果落在 56.83–57.04,引用时应使用中位数或范围,单次噪声约为 ±2.5。
BenchLocal 和雷达图的操作步骤如下:
-
打开面板 → 模型测试 → 能力评测(BenchLocal);
-
面板启动后,看护进程会启动三个校验器,其状态应显示为
ready; -
每次选择 1–9 个题包并运行。默认六项测试不需要校验器;只有勾选 BugFind、CLI 或 Agent 时才会使用校验器;
-
测试完成后查看雷达图。通过面板导出按钮调用
/console-api/benchlocal/export,记录保存在$SM75_CONSOLE_ROOT/benchlocal/。
10.2 自定义 API
需要测试其他 OpenAI 兼容接口时,在“能力评测 · BenchLocal”页面展开“自定义 API”:
-
开关与说明同一行;API 地址整行;API 密钥与模型名两列;「测试并拉取模型」单独成行。
-
地址填到 /v1 或 /v1/chat/completions 均可,服务端会归一化;测试成功后会拉取模型列表供选择。
-
密钥仅在服务端请求上下文中使用,不会写入报告或日志。
-
截图:20-BenchLocal-自定义API-20261019.png。
截图按 NN-主题-YYYYMMDD.png 命名。
10.3 其他用户接入 GPUStack 的模型

API 密钥页:按用户建 key,列表只显示掩码
其他用户应通过 GPUStack 网关调用模型 API。面板和工作台仅供本机管理员使用,不作为多用户入口。
10.3.1 管理员先建用户(GPUStack UI)
-
管理员通过
http://${HOST_IP}:8180登录 GPUStack。 -
进入 Users 页面并选择 Add User,填写 Name、Full Name 和 Password,将角色设置为 User。系统仅提供 Admin 和 User 两种角色;默认管理员账号不能在 UI 中停用或删除。
-
密码必须包含至少 1 个大写字母、1 个小写字母、1 个数字和 1 个特殊字符(
! @ # $ % ^ & * _ + .),长度限制为 6–64 个字符。 -
普通用户只能管理自己的 API key 并访问模型 API,不能修改集群、模型或系统设置。
10.3.2 每个用户建自己的 API key
-
使用该用户账号登录,依次进入 Access Control → API Keys → New API Key。
-
填写名称并保存。完整 key 只在创建时显示一次,应立即存入用户自己的密码管理器或权限为 0600 的文件,不要粘贴到群聊、截图或对话中。
-
同页的 API Access Info 里有 Access URL,即该用户的 base URL,格式为
http://<HOST_IP>:8180/v1。 -
人员离开或需要常规轮换时,先在 API Keys 页面创建新 key,更新客户端配置并验证成功,再删除旧 key。若旧 key 已确认泄露,应立即删除,不应等待轮换完成。
10.3.3 用户调用(OpenAI 兼容)
export GPUSTACK_API_KEY='<该用户自己的 key>'
export BASE_URL="http://${HOST_IP}:8180/v1"
# 1) 看模型清单
curl -s "$BASE_URL/models" -H "Authorization: Bearer $GPUSTACK_API_KEY"
# 2) 对话
curl -s "$BASE_URL/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GPUSTACK_API_KEY" \
-d '{
"model": "qwen3.8-flash-next-w4a16-autoround",
"messages": [{"role":"user","content":"用三句话介绍你自己"}],
"max_tokens": 512,
"stream": false
}'
Python(OpenAI SDK):
from openai import OpenAI
client = OpenAI(base_url="http://<HOST_IP>:8180/v1", api_key="<该用户自己的 key>")
r = client.chat.completions.create(
model="qwen3.8-flash-next-w4a16-autoround",
messages=[{"role": "user", "content": "你好"}],
max_tokens=512,
)
print(r.choices[0].message.content)
-
如需快速验证,可进入 GPUStack UI 的 Playground → Chat,并在右上角选择模型。
-
GPUStack 还提供 Anthropic 兼容的
/v1/messages接口,可在客户端要求 Anthropic 协议时使用。 -
只向用户开放 8180 网关。不要直接暴露引擎端口,因为 400xx 端口没有鉴权。
10.3.4 面板/工作台只给管理员(不对外)
-
面板 Console 采用单账号模式。不要向他人提供管理员 key,也不要让多人共用同一个面板 root。
-
不提供多用户面板或工作台。其他用户按 §10.3.3 使用自己的 OpenAI 兼容客户端连接 8180,并使用各自的 API key。
-
工作台的自定义模型只服务本机单用户,见 §10.3.6。
10.3.5 验收
| 验收项 | 预期结果 |
|---|---|
| 模型列表接口 | 普通用户使用自己的 key 调用 /v1/models,返回 HTTP 200 |
| 对话接口 | 调用 /v1/chat/completions,响应正文非空 |
| 权限隔离 | 普通用户登录后只能看到普通用户菜单,不能访问集群、模型或用户管理页面 |
| 用量记录 | 用量或监控页面能够显示该用户及该 key 的请求 |
| 密钥撤销 | 删除该 key 后,再次发送相同请求应返回 HTTP 401 |
截图:Users 页与 Access Control → API Keys 页。
10.3.6 DSH 工作台的自定义模型(单用户)
当前 GPUStack 形态的工作台已经预置本机模型:provider 为 sm75-local,model 为 qwen3.8-flash-next-w4a16-autoround,baseURL 为 http://<HOST>:<引擎端口>/v1。实机访问 GET /harness-ui/sm75/configured-models 可看到该配置,随后可直接在工作台模型选择器中选择。
如需在同一工作台中添加第二个模型,请按以下步骤操作:
-
打开工作台 → 设置 → 模型,然后选择“添加 provider/模型”。
-
外部模型或网关的 baseURL 填
http://<HOST>:8180/v1。必须走 8180 网关,不要直连 400xx 端口。api 选openai-completions,model id 与 GPUStack 模型行一致,contextWindow 填 262144。 -
在设置页的凭据或 API key 区域填写对应的 GPUStack API key。工作台通过内置的
dsh-credentials-local保存凭据;不要将 key 写入 YAML、模型环境变量或命令行。 -
保存后,在模型选择器中选择新的 provider 和 model,并发送一条消息验证连接。
-
工作台子进程只注入内部引擎使用的
SM75_ENGINE_KEY。如果在cordis.patch.yml中为新 provider 指定未注入的apiKeyEnv,配置不会生效。新 provider 应使用设置页的凭据存储;只有内部引擎可以直接使用已注入的SM75_ENGINE_KEY。 -
GPUStack 重启引擎后,内部
sm75-local的端口可能变化。此时应将/var/lib/gpustack/dsh/home/sm75-plugins.patch.json和profiles/web/cordis.patch.yml中的 baseURL 更新为当前端口,然后重新打开工作台。通过 8180 网关访问的外部 provider 不受该变化影响。 -
批量预置时,在
cordis.patch.yml的llm-pi-ai.providers中添加 provider,并使用agent-default-model指定默认模型。修改后需要重启工作台。 -
其他用户通过客户端连接 8180:每个用户使用自己的 OpenAI 兼容客户端和 API key,见 §10.3.1–10.3.5。DSH 只服务本机单用户,不要共用面板 admin key。
11 参数速查(逐条讲解见文末附录 A)
| 参数 | 作用 | 调整要求 |
|---|---|---|
| –dtype / --hf-overrides | 数值类型 | Turing 无 bf16,只能 float16;两行必须同步 |
| –tensor-parallel-size=8 | 八卡切分 | 改小需先算显存;卡间通信参与数随之变 |
| –enable-expert-parallel / --enable-ep-weight-filter | 专家并行与仅加载当前 GPU 所需专家权重 | 受本机显存容量限制,必须启用 |
| –limit-mm-per-prompt={“image”:4,“video”:0} | 每请求图像上限;视频 0=禁用 | A 路线默认;删掉换成 --language-model-only 即纯文本 |
| –max-model-len | 最大上下文 | 调大要同步涨 KV |
| –max-num-seqs | 并发上限 | 当前测速使用并发 1,不受该值影响 |
| –gpu-memory-utilization | 显存占比 | 给了 --kv-cache-memory-bytes 后它不再主导分配 |
| –kv-cache-dtype / --kv-cache-memory-bytes | KV 精度与大小 | 换机按实测驻留重算 |
| –enable-prefix-caching | 前缀缓存 | 本机实测命中为 0;关闭前应确认业务不存在重复前缀 |
| –engram-config | 将 embedding 表卸载到 CPU | 关闭前必须确认显存余量充足 |
| –gdn-prefill-backend=flashqla_sm75 | SM75 专用预编译核 | 该核的挂载点;改成 triton 会明显变慢 |
| –compilation-config | 编译与 cudagraph | mode 0=不 compile;改捕获尺寸要重测 |
| –scheduler-cls | 自建调度器 | 换回默认会丢定制调度 |
| –reasoning-parser=qwen3 | 思链分离 | 决定 max_tokens 要给够 |
| GPUSTACK_MODEL_RUNTIME_SHM_SIZE_GIB | 实例 /dev/shm | 未设置时使用 10 G 默认值 |
| GPUSTACK_MODEL_VRAM_CLAIM | 准入申报 | 低报会看似通过、实际超卖;按实测重算 |
| SM75_PANEL_* | 面板自启/监听/数据目录 | 见第 7.3 节 |
| SM75_EXTENSIONS | 面板/工作台/校验器/测试资产开关 | panel,harness,benchlocal,speedtest,sql;只要面板写 panel |
| SM75_BENCH_VERIFIERS_MODE | 校验器形态 | external=宿主三容器(默认);local=旧容器内三网关 |
| SM75_BENCH_VERIFIER_CONFIG_FILE / SM75_BENCH_VERIFIER_STATE_DIR | 三容器地址与开关标志 | 容器内指向 /var/lib/gpustack/benchlocal,宿主对应 ${GS_DATA_DIR}/benchlocal;由宿主 launcher 写入和读取 |
| 编译缓存 6 条 | 启动 JIT 缓存 | 默认启用;见 §7.2.1,首次生成缓存约 213 秒、再次启动约 31 秒 |
12 排错速查
| 现象 | 可能原因与处理方法 |
|---|---|
| 模型永久排队、界面不报错 | 漏 GPUSTACK_MODEL_VRAM_CLAIM,或申报值高于当前可调度显存 |
| 模型已启动但出现显存超卖或影响其他任务 | GPUSTACK_MODEL_VRAM_CLAIM 低于真实占用;停止其他 GPU 任务,或按实测值重新申报 |
| HTTP 200 但正文为空 | max_tokens 被推理 token 耗尽;提高该值后重试 |
| 容器里 /dev/shm 只有 10G | 漏 GPUSTACK_MODEL_RUNTIME_SHM_SIZE_GIB |
| Worker 为 Ready,但模型无法启动 | 缺少 --advertise-address;补充宿主机可访问地址后重建 Worker |
| 面板 1615 无法访问 | 模型环境变量中未显式设置 SM75_CONSOLE_PORT=1615;以 /proc/net/tcp 的监听状态为准,不要依据旧的 panel.log 记录判断 |
| A 路线首次启动较慢,且 cc1plus 占用较高 | 权重加载仍需约 210 秒;JIT 缓存首次生成耗时 213.48 秒,第二次启动降至 30.95 秒,但不会缩短权重加载时间。应等待 /health 返回 200,期间不要重启 |
| 速度页 API 地址还是旧 400xx(手工改过/旧页面缓存) | 新构建会在 iframe URL 带当前引擎端口并清旧 40xx;旧页面可按 F12 执行 localStorage.removeItem(‘llmPerfTestApiUrl’); localStorage.removeItem(‘sm75-speed-proxy-v2’); location.reload(),然后关闭整个面板标签重开(只刷新父页不会重载 iframe),或直接打开 /bench-app/speedtest/。面板进程的 SM75_ENGINE_URL 是当前端口(本机实读 40019) |
出现 nms does not exist 或 import 异常 | 镜像版本与 torch 不匹配;本交付使用相互匹配的 cu129 版本 |
| 面板 401 | 用 $SM75_CONSOLE_ROOT/key 的令牌,不要用平台 API key |
| 模型测试页顶部 The ‘path’ argument must be of type string | 镜像的 /preview 对 GPUStack 托管配置取 cacheRoot;当前镜像已返回 external 预览 |
| 速度页 iframe 里 401 请先登录 | 镜像 iframe 的 fetch 未带会话 cookie;当前镜像已注入 credentials=include |
| 面板 503 Harness 正在启动 | DSH 首次启动需 3–5 秒;看 $SM75_CONSOLE_ROOT/harness-process.log,等 /console-api/harness 的 running:true |
| 工作台或使用统计页面显示大量方框 | 镜像缺少中文字体;当前交付镜像已安装 fonts-noto-cjk |
| 配置修改未生效 | 检查修改位置:入口和镜像属于后端版本,参数和环境变量属于模型配置 |
附录 A 参数说明(24 条后端参数 + 39 条环境变量 + 1 条后端入口)
本附录说明各项参数的作用、调整条件和潜在影响。QSA 相关变量仅按变量名称和实测行为说明,不推断未公开的内部实现。
A.1 后端参数(24 条)
--dtype=float16:指定权重和激活的数据类型。T10(Turing)不支持 bfloat16,因此必须使用 float16。若需调整精度,应更换量化方案,不能直接改为 bf16。--hf-overrides={"dtype":"float16"}:覆盖模型config.json中声明的 dtype。AutoRound 权重配置可能标记为 bfloat16;如果不覆盖,引擎可能按 bf16 加载并报错。本参数必须与--dtype保持一致。--tensor-parallel-size=8:将模型拆分到 8 张 GPU。本机配置以 8 卡为运行前提。减小并行规模前,必须重新评估单卡显存需求;all-reduce 的参与 GPU 数也会随之变化。--enable-expert-parallel:启用 MoE 专家并行,使专家权重分片存放在不同 GPU 上。本机单卡显存无法容纳全部专家权重,因此不能关闭。--enable-ep-weight-filter:使每张 GPU 仅加载自身需要的专家权重,是控制显存占用的关键设置。关闭后会加载全部专家权重,本机显存不足以支持该模式。--limit-mm-per-prompt={"image":4,"video":0}:限制单个请求中的多模态输入数量。A 路线允许最多 4 张图片,并禁用视频。未显式设置时,引擎会对未指定模态返回 999;对应代码位于vllm/config/multimodal.py:478-489。JSON 必须紧贴等号且不能包含空格,否则 GPUStack 会按空格拆分参数。此限制按请求生效;单个请求超过 4 张图片时会被拒绝。提高上限前,必须重新评估分波编码、首包时延、显存占用和 claim。纯文本模式应将该参数替换为--language-model-only。--max-model-len=262144:将最大上下文长度设置为 262144 tokens(256K)。增大该值时,必须同步增加--kv-cache-memory-bytes或提供更多显存,否则模型可能无法启动。--max-num-seqs=4:设置最大并发序列数。本文性能测试使用并发 1,因此不受该值影响。提高该值可能增加总吞吐,但也会增加 KV cache 和显存占用。--max-num-batched-tokens=4096:设置单批次可处理的最大 token 数。增大该值可以减少分块次数并提高吞吐,但会增加激活显存;减小该值则会降低处理速度。--gpu-memory-utilization=0.92:设置显存使用比例。同时指定--kv-cache-memory-bytes后,引擎会跳过基于比例的 profiling,本参数不再主导 KV cache 分配。--kv-cache-dtype=fp8_e4m3:使用 FP8 e4m3 格式存储 KV cache。在 QSA FP8 路径可用的前提下,可将其显存占用约减半。改为auto可能使占用翻倍,并导致模型无法启动。--kv-cache-memory-bytes=2415919104:将每张 GPU 的 KV cache 固定为 2.25 GiB。更换硬件或配置档位时,必须根据实测的单卡驻留显存重新计算。--enable-prefix-caching:启用前缀缓存。本机测试期间prefix cache hits始终为 0,未观察到性能收益。若业务不存在重复前缀,可以关闭并重新测试实际负载。--engram-config={"cpu_offload":true}:将 embedding 表卸载到 CPU,并在推理时按需查询,以减少显存占用。关闭 CPU offload 可能提高速度,但必须重新测试性能和稳定性。--gdn-prefill-backend=flashqla_sm75:使 GDN 预填充使用 SM75 专用的flash_qla_sm75_gdn.so。改为 triton 会显著降低本机性能。--generation-config=vllm:使用 vLLM 的 generation config,避免模型自带的 temperature 等默认值覆盖请求参数。--enable-prompt-tokens-details:在响应的 usage 字段中返回 prompt token 明细,用于验收和计量。业务不需要时可以关闭。--compilation-config={"mode":0,"cudagraph_mode":"PIECEWISE","cudagraph_capture_sizes":[1,2,4,8,16]}:mode:0表示不启用torch.compile。cudagraph 使用 PIECEWISE 模式,仅捕获批大小 1、2、4、8、16。修改 mode 或捕获尺寸后,必须重新测试启动时间和稳定性。--block-size=16:设置 KV cache 的分页大小。改为 32 会改变 KV 粒度与命中行为,需要重新测试。--scheduler-cls=vllm.v1.core.sched.scheduler_sm75.SM75Scheduler:使用上游 VLLM-SM75 提供的定制调度器。改回默认调度器会失去 SM75 专用调度行为。--enable-auto-tool-choice:允许模型自动选择工具调用。关闭后,客户端必须显式指定工具调用策略。--tool-call-parser=qwen3_xml:指定工具调用解析器,必须与模型输出格式匹配。更换模型时应同步核对并调整解析器。--reasoning-parser=qwen3:将推理内容与最终正文分开解析,并决定 reasoning tokens 的统计方式。如果max_tokens过小,推理 token 可能耗尽预算,导致正文为空。--chat-template=/opt/vllm-sm75/templates/qwen38-next-high-compat.jinja:指定聊天模板文件。更换模型时,应同步核对并更新模板。
A.2 环境变量(39 条 = 契约 25 + 面板 5 + 外部校验器 3 + 编译缓存 6;另 1 条可选 SM75_DSH_ROOT)
NCCL_P2P_LEVEL=SYS:设置 NCCL 的 P2P 路径层级。本机没有 NVLink,使用 PCIe 交换(SYS 级);改为其他层级可能使 NCCL 绕开 P2P。VLLM_USE_MODELSCOPE=false:禁用 ModelScope 的网络加载路径。本文使用本地缓存中的模型权重,无需通过 ModelScope 下载。VLLM_FIREFLY=auto:上游 VLLM-SM75 的运行时开关。保持auto,具体分支由上游代码决定。HF_HUB_OFFLINE=1、TRANSFORMERS_OFFLINE=1:禁止 Hugging Face Hub 和 Transformers 在运行时联网。模型文件已完整保存在本地,启用离线模式可避免启动过程因网络请求而阻塞。NCCL_DEBUG=WARN:将 NCCL 日志级别设为WARN。排查通信问题时可临时改为INFO,以输出拓扑结构和通道选择信息。NCCL_IB_DISABLE=1:禁用 InfiniBand,本机没有 IB 设备。NCCL_P2P_DISABLE=0:允许 GPU 间 P2P 直连。设为1后会退化为经主机中转;实测 P2P 为 13.16 GB/s,host-staged 为 6.50 GB/s。OMP_NUM_THREADS=1:将每个进程的 OpenMP 线程数限制为 1,避免八个进程造成 CPU 线程过度订阅。VLLM_SM75_QWEN38_HC_GEMV=1:控制上游 HC 投影 GEMV 内核。2026-10-19 在 GPUStack 部署形态下完成单变量 A/B 测试:相同的 1024-token 条件下,生成速度由 49.66 tok/s 提升至 51.63 tok/s,增幅为 3.97%。八张 GPU 的日志均出现NEXT_HC_GEMV_ACTIVE,并覆盖 336×10240、320×10240 和 10240×320(M=1)三种形状,表明该内核已实际生效。温度为 0 的输出指纹未发现语义偏差。因此,本交付设为1;如果后续大样本精度对照测试发现退化,应改回0并重建实例。VLLM_FLASHINFER_WORKSPACE_BUFFER_SIZE=134217728:将 FlashInfer workspace 设为 128 MiB。减小该值可以节省显存,但可能触发性能降级;增大该值可提供更多工作空间,但会占用更多显存。VLLM_USE_BREAKABLE_CUDAGRAPH=1:允许中断 CUDA Graph,避免长时间运行的图阻塞中断或休眠流程。VLLM_WORKER_MULTIPROC_METHOD=spawn:将多进程启动方式设为spawn。在 CUDA 场景下,该方式通常比fork更稳定。VLLM_SPARSE_INDEXER_MAX_LOGITS_MB=16:将稀疏 indexer 的 logits 缓冲上限设为 16 MB。增大该值可降低缓冲区不足的概率,但会增加显存占用。VLLM_SM75_QSA_FLASHINFER_PREFILL=1:使 QSA 预填充使用 FlashInfer 路径。VLLM_SM75_QSA_SHARED_TARGET_SCRATCH=1:允许 QSA 各层共享 target scratch,以降低显存占用。VLLM_SM75_QSA_FP8_MAIN_KV=1:主 KV 使用 FP8,与--kv-cache-dtype=fp8_e4m3配套。VLLM_SM75_QSA_CUBLAS_INDEXER=1:使 QSA indexer 使用 cuBLAS。VLLM_SM75_QSA_SELECTED_PAGES_PREFILL=1:启用基于选中页面的预填充。启用成功后,启动日志中会出现SM75 QSA direct FP8 selected-page Prefill startup warmup complete。VLLM_SM75_QSA_MIXED_PREFILL=1:启用混合预填充路径。VLLM_ENFORCE_STRICT_TOOL_CALLING=1:启用严格工具调用校验。模型输出不合规时返回错误,而不是静默降级。VLLM_ALLREDUCE_USE_FLASHINFER_PCIE_IPC=1:使用 FlashInfer 的 PCIe-IPC all-reduce,对应本文第 1 层回填路径;设为0时回退至 NCCL。TZ=Asia/Shanghai:设置容器时区,主要影响日志与时间戳。GPUSTACK_MODEL_RUNTIME_SHM_SIZE_GIB=64:设置实例容器的/dev/shm容量。未设置时,平台默认分配 10 GiB;可在容器内执行df -h /dev/shm核对。GPUSTACK_MODEL_VRAM_CLAIM=120779177984:向调度器申报约 112.5 GiB 显存,即每卡 14,398 MiB。该值低于 A 路线实测的每卡 15,372 MiB,是专用八卡 Worker 的放宽准入值,不代表真实需求,并会造成调度层面的超卖。因此,不要在同一 Worker 上并行安排其他 GPU 工作负载。严格按实测占用申报时,8 卡总值至少为 128949682176 字节;如果平台可调度容量仍为 117.76 GiB,模型会处于 Pending。更换机器后,应按“实测逐卡驻留 MiB × 卡数 × 1048576”重新计算。- 编译缓存变量(6 条):
FLASHINFER_WORKSPACE_BASE=/var/lib/gpustack/cache将 FlashInfer 缓存写入<base>/.cache/flashinfer;其余变量为HUMMING_CACHE_DIR=.../humming、CUDA_CACHE_PATH=.../cuda、TRITON_CACHE_DIR=.../triton、TORCHINDUCTOR_CACHE_DIR=.../inductor和TORCH_EXTENSIONS_DIR=.../torch_extensions。整组实测显示,首次生成缓存时init engine耗时 213.48 秒,第二次命中缓存时降至 30.95 秒,缩短 85.5%;权重加载仍约为 210 秒。缓存管理方法见 §7.2.1。 SM75_PANEL_AUTOSTART=1:控制面板是否自动启动。设为1时,sidecar 会在引擎启动前启动面板;未设置时,入口仅转发原始启动命令。SM75_CONSOLE_HOST=0.0.0.0:设置面板监听地址。默认值为127.0.0.1,只能本机访问;跨机访问必须设为0.0.0.0。SM75_CONSOLE_ROOT=/var/lib/gpustack/panel:设置面板状态目录,用于保存登录令牌 key、panel.log和会话数据。该目录应位于 Worker 数据目录下,以便在容器重启后保留状态。SM75_EXTENSIONS=panel,harness,benchlocal,speedtest,sql:选择启用的扩展模块。panel表示控制面板,harness表示 Ultra 工作台 DSH,benchlocal表示三个校验器,speedtest和sql表示相应测试资产。仅需要面板时可设为panel;未设置时,入口仅转发原始启动命令。测试资产和 DSH 运行时已内置于镜像,校验器容器由宿主机 launcher 管理,详见 §9。SM75_CONSOLE_PORT=1615:设置面板监听端口。该变量与SM75_CONSOLE_HOST一起决定访问地址;GPUStack 部署形态统一使用 1615。SM75_BENCH_VERIFIERS_MODE=external:指定校验器运行模式。external表示由宿主机运行三个独立容器,也是本文验证过的默认模式;请勿改为local。SM75_BENCH_VERIFIER_CONFIG_FILE=/var/lib/gpustack/benchlocal/benchlocal.env:指定面板读取的校验器配置文件,其中包含访问密钥、三个校验器地址和代理基址。该文件由宿主机 launcher 写入,权限为0600;请勿手动修改或对外分发。SM75_BENCH_VERIFIER_STATE_DIR=/var/lib/gpustack/benchlocal:指定面板写入benchlocal.enabled状态标志的目录。宿主机看护进程根据该标志启动或停止三个校验器容器。SM75_DSH_ROOT=/var/lib/gpustack/dsh(可选):指定 DSH 的 home/workspace 根目录。默认情况下,sidecar 会将其指向 Worker 数据目录,以便在重启后保留数据。独立面板(standalone)未设置该变量时使用/dsh。
A.3 后端版本入口(一个字段,不属于模型参数)
入口命令:python3 /opt/vllm-sm75/panel-sidecar.py vllm serve
GPUStack 使用该字段完整覆盖镜像的 ENTRYPOINT。字段值经 shlex.split 解析后作为容器入口。panel-sidecar.py 首先根据 SM75_PANEL_AUTOSTART 判断是否启动面板,随后通过 exec 原样执行 vllm serve <模型参数>。未启用面板时,其行为与直接使用原始入口一致。
本文详细记录在8×Tesla T10 GPU服务器上完整部署GPUStack v2.2.3并运行vLLM SM75定制后端的全过程,涵盖环境构建、Worker注册、多卡推理配置、多模态支持(图像上限4张)、显存精准申报(每卡15372 MiB)、编译缓存优化(启动提速85.5%)、面板与DSH工作台集成、OpenAI兼容API接入及多用户权限管理。重点适配Turing架构限制(禁用bf16,强制float16),并验证SMT Off与AutoRound量化下的稳定吞吐(~56.8 tok/s)。
400

被折叠的 条评论
为什么被折叠?



