原文:https://mp.weixin.qq.com/s/QaJNbqA3zND2JT4H0Vn5qQ
在企业内网物理断网、禁止外网访问的安全管控下,无法在线拉取镜像、模型权重及依赖,常规云端部署方案不适用。
为了满足智能问答、知识库RAG、本地推理等业务对稳定性、低延迟、高并发和数据私密性的要求,本次基于企业GPU服务器集群,采用vLLM推理框架完成多模型统一部署优化,涵盖DeepSeek-V4-Flash、Qwen3-Embedding-8B等,适配不同业务场景。
全程采用Docker容器化离线部署,规避内网依赖缺失与环境兼容问题,并结合FP8 KV缓存、多卡张量并行+专家并行、CUDA Graph编译加速、MTP推测解码等vLLM高阶优化策略,提升GPU利用率与推理吞吐。
部署完成后,通过vLLM官方压测工具进行多并发压力测试,采集TPS、首token延迟、单token生成延迟、QPS、错误率等指标,完成性能校验与参数调优,最终搭建出一套可复用、高稳定、高性能的企业内网离线大模型服务架构。
本文作为个人实战的完整记录,覆盖了从环境准备、容器部署、参数调优到压力测试的全流程实战细节,为同类企业私有化大模型落地提供标准化参考。
离线环境前置准备
离线Docker镜像准备
内网无外网权限,无法在线pull镜像,需提前在外网机器拉取vLLM官方镜像并打包迁移:
-
外网拉取镜像:docker pull vllm/vllm-openai:latest
-
镜像打包导出:docker save vllm/vllm-openai:latest -o vllm-openai-latest.tar
-
将tar包迁移至内网服务器,执行导入:docker load -i vllm-openai-latest.tar
模型权重与分词器文件准备
提前下载完整模型权重、分词器配置文件,保证文件完整无缺失,统一存放至内网服务器固定目录,挂载至容器使用,全程离线加载:
-
必备模型包:DeepSeek-V4-Flash-0731、Qwen3-Embedding-8B、Qwen3.5-9B
-
包含文件:模型权重文件、vocab词典、tokenizer配置、模型配置、推理脚本等全套文件
-
内网存放路径:统一防至/path/xxx目录,保证目录权限可读,后续容器只读挂载
端口与目录规划准备
提前规划端口与存储目录,避免端口冲突、目录权限不足问题:
-
端口规划:8000端口(DeepSeek主模型)、8001端口(向量模型)、8003端口(Qwen3.5-9B模型),提前确认端口未被占用
-
目录规划:提前创建模型挂载目录、压测结果保存目录/path/model,配置读写权限
-
服务配置:服务器开放网卡访问权限,支持内网其他机器调用模型API接口
部署Deepseek-v4-flash
Bash
sudo docker rm -f vllm-deepseek 2>/dev/null && sudo docker run -d \
--name vllm-deepseek \
--gpus '"device=0,1,2,3"' \
--ipc=host \
-v /path/deepseek-ai/DeepSeek-V4-Flash-0731:/model/DeepSeek-V4-Flash-0731:ro \
-e CUDA_VISIBLE_DEVICES=0,1,2,3 \
-e TRANSFORMERS_OFFLINE=1 \
-p 8000:8000 \
vllm/vllm-openai:latest \
/model/DeepSeek-V4-Flash-0731 \
--served-model-name deepseek-v4-flash \
--host 0.0.0.0 \
--port 8000 \
--kv-cache-dtype fp8 \
--tensor-parallel-size 4 \
--max-model-len 250000 \
--max-num-seqs 50 \
--enable-expert-parallel \
--gpu-memory-utilization 0.95 \
--enable-auto-tool-choice \
--tool-call-parser deepseek_v4 \
--tokenizer-mode deepseek_v4 \
--reasoning-parser deepseek_v4 \
--trust-remote-code
自动清理旧容器,在 4 卡 GPU 上用 vLLM 部署 DeepSeek-V4-Flash MoE 大模型,开启 FP8 KV 缓存、张量并行 + 专家并行,支持 25 万长上下文与工具调用,对外暴露 OpenAI 兼容 API 在 8000 端口,离线不联网。
容器管理参数
| 参数 | 作用 |
| sudo docker rm -f vllm-deepseek | 强制删除旧容器(无论运行或停止) |
| 2>/dev/null | 屏蔽容器不存在的报错信息 |
| && | 前面删除成功后才继续执行 docker run |
| docker run -d | 后台守护进程方式运行 |
Docker 容器配置参数
| 参数 | 含义 |
| --name vllm-deepseek | 容器命名为 vllm-deepseek |
| --gpus '"device=0,1,2,3"' | 分配 GPU 0/1/2/3 共 4 张卡 |
| --ipc=host | 共享宿主机 IPC 命名空间,多卡通信必需 |
| -v ...:/model/...:ro | 挂载模型文件进容器,ro= 只读 |
| -e CUDA_VISIBLE_DEVICES=0,1,2,3 | 容器内仅可见这 4 张 GPU |
| -e TRANSFORMERS_OFFLINE=1 | transformers 离线模式,不联网拉配置 |
| -p 8000:8000 | 宿主机 8000 端口映射到容器 8000 |
| vllm/vllm-openai:latest | 使用的镜像:vLLM OpenAI 兼容服务 |
vLLM 推理参数
| 参数 | 含义 |
/model/DeepSeek-V4-Flash-0731 |
指定模型路径 |
--served-model-name deepseek-v4-flash |
API 调用时的模型名称 |
--host 0.0.0.0 --port 8000 |
监听所有网卡、端口 8000 |
--kv-cache-dtype fp8 |
KV 缓存用 FP8 精度,省显存提吞吐 |
--tensor-parallel-size 4 |
张量并行度 = 4,权重拆分到 4 卡 |
--max-model-len 250000 |
最大上下文窗口 25 万 token |
--max-num-seqs 50 |
最多并发 50 个请求序列 |
--enable-expert-parallel |
专家并行,优化 MoE 模型显存与负载 |
--gpu-memory-utilization 0.95 |
显存利用率上限 95% |
--enable-auto-tool-choice |
开启自动工具调用 |
--tool-call-parser deepseek_v4 |
使用 DeepSeek V4 工具调用解析器 |
--tokenizer-mode deepseek_v4 |
使用 DeepSeek V4 分词器模式 |
--reasoning-parser deepseek_v4 |
使用 DeepSeek V4 推理解析器 |
--trust-remote-code |
允许执行模型仓库自定义代码(慎用) |
参数分类汇总
| 类别 | 涉及参数 | 核心作用 |
| 容器生命周期 | rm -f / -d / --name | 清理旧容器、后台运行、命名 |
| 硬件与资源 | --gpus / -e CUDA_VISIBLE_DEVICES / --ipc | 分配 4 卡 GPU 并保证通信 |
| 模型与数据 | -v / TRANSFORMERS_OFFLINE / 模型路径 | 挂载模型、离线加载 |
| 网络端口 | -p 8000:8000 / --host / --port | 对外暴露 OpenAI API |
| 并行策略 | --tensor-parallel-size 4 / --enable-expert-parallel | 张量并行 + 专家并行 |
| 显存与性能 | --kv-cache-dtype fp8 / --gpu-memory-utilization | 省显存、高吞吐 |
| 能力开关 | --enable-auto-tool-choice / 各 parser | 工具调用与思考链解析 |
效果测试
Shell
curl http://1x.x.x.x:8000/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"deepseek-v4-flash", "messages":[{"role":"user", "content": "你好,介绍一下你自己"}]}'
部署Deepseek-v4-flash:性能优化
SQL
sudo docker rm -f vllm-deepseek 2>/dev/null && sudo docker run -d \
--name vllm-deepseek \
--gpus '"device=0,1,2,3"' \
--ipc=host \
-v /path/DeepSeek-V4-Flash:/model/DeepSeek-V4-Flash:ro \
-e CUDA_VISIBLE_DEVICES=0,1,2,3 \
-e TRANSFORMERS_OFFLINE=1 \
-p 8000:8000 \
vllm/vllm-openai:latest \
/model/DeepSeek-V4-Flash \
--served-model-name deepseek-v4-flash \
--host 0.0.0.0 \
--port 8000 \
--kv-cache-dtype fp8 \
--tensor-parallel-size 4 \
--max-model-len 250000 \
--max-num-seqs 50 \
--enable-expert-parallel \
--gpu-memory-utilization 0.95 \
--compilation-config '{"cudagraph_mode":"FULL_AND_PIECEWISE","custom_ops":["all"]}' \
--enable-auto-tool-choice \
--tool-call-parser deepseek_v4 \
--tokenizer-mode deepseek_v4 \
--reasoning-parser deepseek_v4 \
--trust-remote-code \
--speculative_config '{"method":"mtp","num_speculative_tokens":1}'
参数解释
| 参数分类 | 参数 | 说明 |
| 前置清理 | docker rm -f vllm-deepseek 2>/dev/null | 强制删除旧容器,2>/dev/null屏蔽 "容器不存在" 的报错;&&前面成功才继续执行后面 |
| Docker 容器基础 | docker run -d | -d 后台守护模式运行容器 |
| --name vllm-deepseek | 容器名称 | |
| --gpus '"device=0,1,2,3"' | 分配 GPU 0,1,2,3 共 4 张卡给容器 | |
| --ipc=host | 共享宿主机 IPC 命名空间,多卡张量并行必需,GPU 之间高速通信 | |
| -v /path/DeepSeek-V4-Flash:/model/DeepSeek-V4-Flash:ro | 挂载宿主机 NVMe 盘模型目录;ro= 只读,保护模型文件不被意外修改 | |
| -e CUDA_VISIBLE_DEVICES=0,1,2,3 | 环境变量,容器内仅能看到 0~3 号 GPU | |
| -e TRANSFORMERS_OFFLINE=1 | HuggingFace 离线模式,不会联网拉取模型配置 / 分词器 | |
| -p 8000:8000 | 端口映射:宿主机 8000 端口转发容器 8000,外部访问 API | |
| vllm/vllm-openai:latest | 使用 vLLM 官方 OpenAI 兼容镜像 | |
| vLLM 模型基础 | /model/DeepSeek-V4-Flash | 容器内模型文件路径 |
| --served-model-name deepseek-v4-flash | API 调用时,model参数填写的模型名称 | |
| --host 0.0.0.0 | 监听所有网卡 IP,允许外部服务器访问 | |
| --port 8000 | 服务监听端口 | |
| 显存 & 并行策略 | --kv-cache-dtype fp8 | KV 缓存使用 FP8 精度,节省大量显存 |
| --tensor-parallel-size 4 | 张量并行度 = 4,模型权重拆分到 4 张 GPU | |
| --max-model-len 250000 | 最大上下文窗口:250000 token | |
| --max-num-seqs 50 | 最多同时并发处理 50 条请求序列 | |
| --enable-expert-parallel | MoE 模型专家并行,把不同专家层分散到多张 GPU,均衡负载 | |
| --gpu-memory-utilization 0.95 | GPU 显存利用率上限 95%,尽可能利用显存,预留少量余量 | |
| 性能加速(新增) | --compilation-config '{"cudagraph_mode":"FULL_AND_PIECEWISE","custom_ops":"all"}' | CUDA Graph 编译加速,减少 CPU 调度开销;FULL_AND_PIECEWISE 自动切换完整 / 分段 graph;启用全部自定义算子提升吞吐 |
| --speculative_config '{"method":"mtp","num_speculative_tokens":1}' | MTP 推测解码(DeepSeek V4 Flash 专属),每步预预测 1 个 token,提升生成速度 | |
| 工具调用 & 安全 | --enable-auto-tool-choice | 开启自动工具调用能力 |
| --tool-call-parser deepseek_v4 | DeepSeek V4 专用工具调用解析器 | |
| --tokenizer-mode deepseek_v4 | DeepSeek V4 专用分词器模式 | |
| --reasoning-parser deepseek_v4 | DeepSeek V4 推理解析器,解析思考链输出 | |
| --trust-remote-code | 允许加载模型仓库自定义代码;离线部署常用,公网环境存在安全风险 |
压力测试
SQL
docker exec -it vllm-deepseek vllm bench serve \
--backend openai \
--base-url http://1x.x.x.x:8000 \
--model /model/Deepseek-V4-Flash-0731 \
--tokenizer /model/Deepseek-V4-Flash-0731 \
--endpoint /v1/chat/completions \
--dataset-name random \
--random-input-len 1024 \
--random-output-len 512 \
--num-prompts 40 \
--max-concurrency 8 \
--request-rate inf \
--save-result \
--result-dir /path/AI**
在 vLLM 的容器里,对在线 Deepseek-V4-Flash 模型服务做并发压测。构造 40 条请求,每条输入 1024 token、输出 512 token,最大并发 8,尽可能持续发请求,最后把吞吐、延迟等性能指标保存到磁盘。
vllm bench serve 是 vLLM 自带的服务压测工具,用来对一个已经启动好的 OpenAI 兼容接口做并发性能测试,统计:
-
TPS(每秒 token 吞吐)
-
首 token 延迟、后续 token 延迟
-
并发下的 QPS、错误率等指标
参数解释
| 参数 | 含义 |
| --backend openai | 被测服务是 OpenAI 协议兼容接口(vLLM 启动的服务默认就是这个协议) |
| --base-url http://1x.x.x.x:8000 | 被测大模型服务地址,8000 是 vLLM 默认端口 |
| --model /model/Deepseek-V4-Flash-0731 | 指定模型名称 / 路径 |
| --tokenizer /model/Deepseek-V4-Flash-0731 | 指定分词器路径 |
| --endpoint /v1/chat/completions | 使用 chat 对话接口做压测(不是普通 completions) |
| --dataset-name random | 不使用真实数据集,自动生成随机 token 作为输入 prompt,方便纯压力测试 |
| --random-input-len 1024 | 每个请求输入上下文固定 1024 tokens |
| --random-output-len 512 | 要求模型每个请求输出 512 tokens |
| --num-prompts 40 | 总共发送 40 个请求 完成本次压测 |
| --max-concurrency 8 | 最大并发请求数:同时最多 8 个请求打进去 |
| --request-rate inf | 请求速率无限大,只要并发没满就立刻发下一个(尽可能打满 max-concurrency=8) |
| --save-result | 压测结束保存性能报告 |
| --result-dir /path/model | 性能报告保存到这个目录 |
示例控制台打印样例
Java
-------------- Serving Benchmark Result --------------
Successful requests: 40
Failed requests: 0
Request throughput (req/s): 2.1
Output token throughput (tok/s): 1080
Total token throughput (tok/s): 3250
------------ Time To First Token ------------
Mean TTFT (ms): 142
Median TTFT (ms): 136
P99 TTFT (ms): 215
------------ Time Per Output Token -----------
Mean TPOT (ms): 0.89
Median TPOT (ms): 0.87
P99 TPOT (ms): 1.12
向量化模型部署
Qwen3-Embedding-8B 部署
SQL
sudo docker rm -f vllm-qwenembedding 2>/dev/null && sudo docker run -d \
--name vllm-qwenembedding \
--gpus '"device=5"' \
--ipc=host \
-v /path/Qwen3-Embedding-8B:/model/Qwen3-Embedding-8B:ro \
-e VLLM_ENABLE_CUDA_COMPATIBILITY=1 \
-p 8001:8000 \
--restart unless-stopped \
vllm/vllm-openai:latest \
/model/Qwen3-Embedding-8B \
--served-model-name qwen3-embedding-8B \
--host 0.0.0.0 \
--port 8000 \
--runner pooling \
--trust-remote-code \
--max-model-len 8192 \
--max-num-seqs 100 \
--gpu-memory-utilization 0.5 \
--tensor-parallel-size 1 \
--enforce-eager
在 5 号单张 GPU 上,用 vLLM 部署通义千问 Qwen3-Embedding-8B 向量嵌入模型,对外提供 OpenAI 兼容的 Embedding 向量接口,端口宿主机 8001,用于 RAG 知识库的文本向量化。
| 参数 | 参数值 | 作用说明 |
| docker rm -f | vllm-qwenembedding 2>/dev/null | 强制删除旧同名容器,屏蔽容器不存在时的报错 |
| docker run -d | - | 后台守护模式运行容器 |
| --name | vllm-qwenembedding | 容器名称 |
| --gpus | "device=5" | 仅使用 GPU 编号 5,单卡部署,不和大模型抢占其他显卡 |
| --ipc=host | - | 共享宿主机 IPC 命名空间,满足 vLLM 进程通信需求 |
| -v | /path/Qwen3-Embedding-8B:/model/Qwen3-Embedding-8B:ro | 挂载 NVMe 盘中的模型,ro只读保护模型文件 |
| -e | VLLM_ENABLE_CUDA_COMPATIBILITY=1 | 开启 CUDA 兼容模式,规避算子编译、驱动版本兼容报错 |
| -p | 8001:8000 | 端口映射:宿主机 8001 → 容器内部 8000,与 8000 端口的 DeepSeek 服务隔离 |
| --restart | unless-stopped | 自动重启策略:除非手动停止,否则崩溃 / 服务器重启自动拉起服务 |
| 镜像 | vllm/vllm-openai:latest | vLLM 官方镜像,提供 OpenAI 兼容 API |
| 模型路径 | /model/Qwen3-Embedding-8B | 容器内模型存放路径 |
| --served-model-name | qwen3-embedding-8B | API 调用时请求体中model参数填写的模型名称 |
| --host | 0.0.0.0 | 监听所有网卡,允许外部机器访问 |
| --port | 8000 | 容器内部监听端口 |
| --runner | pooling | 核心参数,指定为 Embedding 向量模型,启用池化输出向量,不是文本生成 |
| --trust-remote-code | - | 允许加载模型仓库自定义代码,Embedding 模型必需 |
| --max-model-len | 8192 | 输入文本最大 token 长度上限 |
| --max-num-seqs | 100 | 最多同时并发处理 100 条向量化请求 |
| --gpu-memory-utilization | 0.5 | GPU 显存最大占用上限 50%,预留显存给其他任务 |
| --tensor-parallel-size | 1 | 张量并行度 = 1,单卡运行,不拆分模型权重 |
| --enforce-eager | - | 强制 PyTorch eager 执行模式,关闭 CUDA Graph,提升向量服务稳定性 |
Qwen3.5-9B 部署
Plain
sudo docker rm -f vllm-qwen3_5 2>/dev/null && sudo docker run -d \
--name vllm-qwen3_5 \
--gpus '"device=6"' \
--ipc=host \
-v /path/Qwen3.5-9B:/model/Qwen3.5-9B:ro \
-e VLLM_ENABLE_CUDA_COMPATIBILITY=1 \
-p 8003:8000 \
--restart unless-stopped \
vllm/vllm-openai:latest \
/model/Qwen3.5-9B \
--served-model-name qwen3.5-9B \
--host 0.0.0.0 \
--port 8000 \
--tensor-parallel-size 1 \
--data-parallel-size 1 \
--max-model-len 200000 \
--max-num-seqs 50 \
--gpu-memory-utilization 0.6 \
--enable-prefix-caching \
--trust-remote-code
在 6 号单卡 GPU 上,使用 vLLM 部署 Qwen3.5-9B 大语言模型,对外提供 OpenAI 兼容对话 API,宿主机访问端口 8003,开启前缀缓存加速长上下文场景,作为独立对话模型服务。
| 参数分类 | 参数 | 说明 |
| Docker 容器基础 | --name vllm-qwen3_5 | 容器名称:vllm-qwen3_5 |
| --gpus '"device=6"' | 绑定 GPU 编号 6,单卡独立部署,和其他服务资源隔离 | |
| --ipc=host | 共享宿主机 IPC 命名空间,保障 vLLM 进程通信 | |
| -v /path/Qwen3.5-9B:/model/Qwen3.5-9B:ro | 挂载 NVMe 盘模型目录到容器;ro只读,保护模型文件 |
|
| -e VLLM_ENABLE_CUDA_COMPATIBILITY=1 | 开启 CUDA 兼容模式,规避算子编译报错 | |
| -p 8003:8000 | 端口映射:宿主机 8003 → 容器内 8000,独立端口避免冲突 | |
| --restart unless-stopped | 容器自动重启策略:除非手动停止,否则自动恢复 | |
| vllm/vllm-openai:latest | 基础镜像:vLLM 官方 OpenAI 兼容接口镜像 | |
| vLLM 模型与 API | /model/Qwen3.5-9B | 容器内模型加载路径 |
| --served-model-name qwen3.5-9B | API 调用时使用的模型名称,请求 body 的 model 字段填此值 | |
| --host 0.0.0.0 | 监听所有网卡,允许外部机器访问服务 | |
| --port 8000 | 容器内部服务监听端口 | |
| 并行策略 | --tensor-parallel-size 1 | 张量并行度 = 1,单卡运行,不拆分模型权重 |
| --data-parallel-size 1 | 数据并行度 = 1,不启动多副本负载分发 | |
| 上下文 & 并发 | --max-model-len 200000 | 最大上下文窗口:200000 token |
| --max-num-seqs 50 | 最多同时并发处理 50 条对话请求 | |
| 显存 & 加速 | --gpu-memory-utilization 0.6 | GPU 显存使用率上限 60%,预留显存余量,防止 OOM |
| --enable-prefix-caching | 前缀缓存,相同上下文前缀复用 KV 缓存,RAG / 多轮对话加速 | |
| 安全选项 | --trust-remote-code | 允许加载模型仓库内自定义分词器代码,离线部署使用 |