模型部署方案
2026-02-13
模型
00
请注意,本文编写于 50 天前,最后修改于 5 天前,其中某些信息可能已经过时。

目录

一、环境准备
1.1 系统更新与基础工具
1.2 NVIDIA 驱动与 CUDA(略)
二、Python 环境:Miniconda 隔离管理
2.1 为什么选择 Miniconda?
2.2 安装与配置
2.3 创建专用环境
三、核心依赖安装:PyTorch 与 Transformers
3.1 安装命令
3.2 关键包功能说明
3.3 安装验证
四、模型下载:魔搭社区(ModelScope)加速
4.1 为什么选择 ModelScope?
4.2 安装与配置
4.3 下载模型(以 70B 为例)
4.4 模型文件结构验证
五、最小推理验证:Transformers 原生加载
5.1 编写推理脚本
5.2 运行推理
六、生产级部署:vLLM 高性能服务
6.1 为什么选择 vLLM?
6.2 安装 vLLM
6.3 启动服务(单卡/多卡)
6.4 API 调用测试
续写接口(Completions)
聊天接口(Chat Completions,推荐)
6.5 性能压测
七、生产环境加固
7.1 Systemd 服务化
7.2 Nginx 反向代理(SSL + 限流)
7.3 监控与告警(Prometheus + Grafana)
八、故障排查速查表

一、环境准备

1.1 系统更新与基础工具

展开代码
# 更新系统包(避免旧版本兼容性问题) sudo apt update && sudo apt upgrade -y # 安装编译工具链(后续安装 Python 包需要) sudo apt install -y build-essential python3-pip curl git wget \ libssl-dev zlib1g-dev libbz2-dev libreadline-dev \ libsqlite3-dev llvm libncurses5-dev libncursesw5-dev \ xz-utils tk-dev libffi-dev liblzma-dev

关键说明

  • build-essential:提供 GCC/G++,编译 PyTorch 等库必需
  • 开发库(zlib/bzip2/readline 等):Python 解释器编译依赖

1.2 NVIDIA 驱动与 CUDA(略)

假设已完成:

  • 驱动版本 ≥ 525.60.13(CUDA 12.x 兼容)
  • nvidia-smi 正常输出
  • nvcc --version 显示 CUDA 12.x

验证命令

展开代码
nvidia-smi # 应显示 GPU 型号、温度、显存占用 nvcc -V # 应显示 release 12.x

二、Python 环境:Miniconda 隔离管理

2.1 为什么选择 Miniconda?

方案优点缺点
系统 Python简单包冲突、无法多版本并存
virtualenv轻量编译依赖复杂
Miniconda预编译包、环境隔离、CUDA 自动匹配体积稍大
Docker完全隔离调试麻烦、GPU 穿透配置繁琐

2.2 安装与配置

展开代码
# 下载官方安装脚本(约 100MB) wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh # 静默安装到用户目录(-b 跳过交互,-p 指定路径) bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda3 # 加入环境变量(当前 shell 生效) echo 'export PATH=$HOME/miniconda3/bin:$PATH' >> ~/.bashrc source ~/.bashrc # 验证 conda --version # 应显示 conda 23.x 或更高

2.3 创建专用环境

展开代码
# 创建 Python 3.10 环境(LLM 生态最稳定版本) conda create -n llm python=3.10 -y # 激活环境(后续所有操作都在此环境) conda activate llm # 升级基础工具 pip install --upgrade pip setuptools wheel

环境管理速查

展开代码
conda env list # 查看所有环境 conda deactivate # 退出当前环境 conda remove -n llm --all # 删除环境(危险)

三、核心依赖安装:PyTorch 与 Transformers

3.1 安装命令

展开代码
# 核心推理栈 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # HuggingFace 生态(模型加载、量化、加速) pip install transformers accelerate bitsandbytes # 可选:FlashAttention 加速(需 CUDA 11.6+,A100/H100 推荐) pip install flash-attn --no-build-isolation

3.2 关键包功能说明

包名作用关键特性
torchPyTorch 深度学习框架CUDA 加速、自动求导
transformersHuggingFace 模型库AutoModel、AutoTokenizer
accelerate多卡/混合精度训练推理device_map="auto"
bitsandbytes8-bit/4-bit 量化load_in_4bit=True 省显存
flash-attn内存高效 Attention2-4× 速度提升,支持长序列

3.3 安装验证

展开代码
python -c " import torch print(f'PyTorch: {torch.__version__}') print(f'CUDA available: {torch.cuda.is_available()}') print(f'CUDA version: {torch.version.cuda}') print(f'GPU: {torch.cuda.get_device_name(0)}') print(f'GPU memory: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB') "

预期输出

展开代码
PyTorch: 2.3.0+cu121 CUDA available: True CUDA version: 12.1 GPU: NVIDIA A100-SXM4-80GB GPU memory: 80.0 GB

四、模型下载:魔搭社区(ModelScope)加速

4.1 为什么选择 ModelScope?

渠道优点缺点
HuggingFace最全国内访问慢,易中断
ModelScope国内 CDN、速度快、免登录部分新模型滞后
官方 GitHub源码完整无 LFS 加速,大文件慢
百度网盘/迅雷民间镜像版本混乱、安全风险

4.2 安装与配置

展开代码
# 安装魔搭客户端 pip install modelscope # 设置国内镜像(可选,自动识别) export MODELSCOPE_CACHE=/home/roots/models # 自定义缓存目录

4.3 下载模型(以 70B 为例)

展开代码
# 创建模型目录 mkdir -p /home/roots/models/DeepSeek-R1-Distill-Llama-70B # 最好使用终端复用工具(如tmux)进行下载,防止断开下载连接 # 开始下载(约 140GB,根据网速 30-120 分钟) # 支持断点续传,中断后重新执行会自动跳过已下载 modelscope download \ --local_dir /home/roots/models/DeepSeek-R1-Distill-Llama-70B \ --model deepseek-ai/DeepSeek-R1-Distill-Llama-70B

下载进度监控

展开代码
# 另开终端查看 watch -n 5 'du -sh /home/roots/models/DeepSeek-R1-Distill-Llama-70B'

4.4 模型文件结构验证

展开代码
ls -lh /home/roots/models/DeepSeek-R1-Distill-Llama-70B

预期输出

展开代码
total 140G -rw-r--r-- 1 roots roots 1.5K config.json -rw-r--r-- 1 roots roots 4.8K generation_config.json -rw-r--r-- 1 roots roots 9.0G model-00001-of-00015.safetensors -rw-r--r-- 1 roots roots 9.0G model-00002-of-00015.safetensors ... -rw-r--r-- 1 roots roots 9.0G model-00015-of-00015.safetensors -rw-r--r-- 1 roots roots 16K model.safetensors.index.json -rw-r--r-- 1 roots roots 4.9M tokenizer.json -rw-r--r-- 1 roots roots 1.1M tokenizer.model -rw-r--r-- 1 roots roots 51K tokenizer_config.json

关键文件

  • config.json:模型架构配置(层数、隐藏维度、注意力头数)
  • *.safetensors:模型权重(HuggingFace 安全格式,替代 pickle)
  • tokenizer.*:分词器(BPE 算法,将文本转为 token ID)

五、最小推理验证:Transformers 原生加载

5.1 编写推理脚本

展开代码
cat > /home/roots/run.py <<'EOF' #!/usr/bin/env python3 """ 最小化 DeepSeek-R1-Distill-Llama 推理脚本 支持 4-bit 量化,单卡/多卡自动分配 """ import torch from transformers import AutoModelForCausalLM, AutoTokenizer import warnings warnings.filterwarnings("ignore") # ==================== 配置 ==================== MODEL_PATH = "/home/roots/models/DeepSeek-R1-Distill-Llama-70B" # 若显存不足,换 8B 版本: # MODEL_PATH = "/home/roots/models/DeepSeek-R1-Distill-Llama-8B" QUERY = "你是谁?你能做些什么?请用中文回答。" # ==================== 加载分词器 ==================== print(f"[1/3] 正在加载分词器: {MODEL_PATH}") tokenizer = AutoTokenizer.from_pretrained( MODEL_PATH, trust_remote_code=True, # DeepSeek 有自定义代码 padding_side="left" # 生成模型通常左填充 ) # 设置 pad_token(Llama 系列默认无 pad) if tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token # ==================== 加载模型 ==================== print("[2/3] 正在加载模型(4-bit 量化,自动分配设备)...") model = AutoModelForCausalLM.from_pretrained( MODEL_PATH, torch_dtype=torch.float16, # 权重 FP16,计算 FP16 device_map="auto", # 自动分配到所有 GPU load_in_4bit=True, # 4-bit 量化,显存省 4× bnb_4bit_compute_dtype=torch.float16, # 计算时还原 FP16 bnb_4bit_use_double_quant=True, # 嵌套量化,再省 0.4 bit trust_remote_code=True ) print(f" 模型设备分布:") for name, device in model.hf_device_map.items(): print(f" - {name}: {device}") # ==================== 推理 ==================== print("[3/3] 开始推理...") inputs = tokenizer(QUERY, return_tensors="pt").to("cuda") # 生成参数 generate_kwargs = { "max_new_tokens": 512, # 最多生成 512 个新 token "temperature": 0.7, # 采样温度(0=确定,1=随机) "top_p": 0.9, # 核采样,保留累积概率 90% "repetition_penalty": 1.1, # 惩罚重复,1.0=无惩罚 "do_sample": True, # 启用采样(False=贪心解码) "pad_token_id": tokenizer.pad_token_id } with torch.no_grad(): outputs = model.generate(**inputs, **generate_kwargs) response = tokenizer.decode(outputs[0], skip_special_tokens=True) print(f"\n{'='*50}") print(f"用户: {QUERY}") print(f"AI: {response[len(QUERY):].strip()}") # 去掉输入部分 print(f"{'='*50}") # 显存统计 if torch.cuda.is_available(): print(f"\n显存占用:") for i in range(torch.cuda.device_count()): mem = torch.cuda.memory_allocated(i) / 1e9 max_mem = torch.cuda.max_memory_allocated(i) / 1e9 print(f" GPU {i}: {mem:.2f} GB / {max_mem:.2f} GB (峰值)") EOF

5.2 运行推理

展开代码
# 确保在 llm 环境 conda activate llm # 运行(首次加载需 2-5 分钟,从磁盘读 140GB) python /home/roots/run.py

预期输出

展开代码
[1/3] 正在加载分词器: /home/roots/models/DeepSeek-R1-Distill-Llama-70B [2/3] 正在加载模型(4-bit 量化,自动分配设备)... 模型设备分布: - model.embed_tokens: cuda:0 - model.layers.0-39: cuda:0 - model.layers.40-79: cuda:1 - model.norm: cuda:1 - lm_head: cuda:1 [3/3] 开始推理... ================================================== 用户: 你是谁?你能做些什么?请用中文回答。 AI: 我是 DeepSeek-R1 蒸馏后的 Llama 模型,由 DeepSeek 团队训练。我可以帮助你进行文本生成、代码编写、数学推理、知识问答等任务。我的回答基于训练数据中的模式,但请注意核实重要信息。 ================================================== 显存占用: GPU 0: 38.5 GB / 40.2 GB (峰值) GPU 1: 38.2 GB / 39.8 GB (峰值)

六、生产级部署:vLLM 高性能服务

6.1 为什么选择 vLLM?

特性TransformersvLLM
吞吐量低(逐序列生成)高(连续批处理 + PagedAttention)
并发支持优秀(动态批处理)
显存效率一般(KV-Cache 碎片)高(分页管理)
API 兼容性OpenAI 兼容
生产适用性实验/调试在线服务

6.2 安装 vLLM

展开代码
conda activate llm # 安装指定版本(与 CUDA 12.1 匹配) pip install vllm==0.5.1 # 或最新版(可能需编译) pip install -U vllm

6.3 启动服务(单卡/多卡)

展开代码
# 8B 模型,单卡启动 python -m vllm.entrypoints.openai.api_server \ --model /home/roots/models/DeepSeek-R1-Distill-Llama-8B \ --host 0.0.0.0 \ --port 36000 \ --dtype half \ --gpu-memory-utilization 0.9 \ --trust-remote-code # 70B 模型,双卡张量并行(需 2×A100-80GB 或 4×A100-40GB) python -m vllm.entrypoints.openai.api_server \ --model /home/roots/models/DeepSeek-R1-Distill-Llama-70B \ --host 0.0.0.0 \ --port 36000 \ --dtype half \ --tensor-parallel-size 2 \ --quantization bitsandbytes \ --load-format safetensors \ --gpu-memory-utilization 0.95 \ --trust-remote-code \ --max-model-len 8192 \ --max-num-seqs 16

参数详解

参数说明建议值
--model本地模型路径绝对路径
--host监听地址0.0.0.0(允许外部访问)
--port服务端口36000
--dtype权重精度half(FP16)或 bfloat16
--tensor-parallel-size张量并行卡数2/4/8,需整除注意力头数
--quantization量化方式bitsandbytes(8bit/4bit)
--gpu-memory-utilization显存利用率上限0.9-0.95,留余量给 KV-Cache
--max-model-len最大序列长度模型支持的最大上下文
--max-num-seqs最大并发序列数根据显存调整

首次启动:会自动编译 CUDA kernel,持续 2-3 分钟,看到 Uvicorn running on http://0.0.0.0:36000 即成功。

6.4 API 调用测试

续写接口(Completions)

展开代码
curl http://localhost:36000/v1/completions \ -H "Content-Type: application/json" \ -d '{ "model": "/home/roots/models/DeepSeek-R1-Distill-Llama-8B", "prompt": "如何查看GPU温度?", "max_tokens": 80, "temperature": 0.7 }'

响应

展开代码
{ "id": "cmpl-abc123", "object": "text_completion", "created": 1699999999, "model": "/home/roots/models/DeepSeek-R1-Distill-Llama-8B", "choices": [{ "text": "你可以使用 nvidia-smi 命令查看 GPU 温度、功耗和显存占用。", "index": 0, "logprobs": null, "finish_reason": "stop" }], "usage": { "prompt_tokens": 12, "completion_tokens": 25, "total_tokens": 37 } }

聊天接口(Chat Completions,推荐)

展开代码
curl http://localhost:36000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer token-abc123" \ -d '{ "model": "/home/roots/models/DeepSeek-R1-Distill-Llama-8B", "messages": [ {"role": "system", "content": "你是一个 helpful 的 AI 助手。"}, {"role": "user", "content": "你好,你能干什么呢?用中文回答我"} ], "max_tokens": 200, "temperature": 0.7, "top_p": 0.9 }'

字段详解

字段类型说明
modelstring本地模型绝对路径(vLLM 直接当模型名用)
messagesarrayOpenAI 标准格式,system/user/assistant
max_tokensint最多生成多少新 token(约 0.75 汉字/token)
temperaturefloat0-2,越高越随机,0.7 平衡创意与稳定
top_pfloat核采样,0.9 表示从累积概率前 90% 采样

6.5 性能压测

展开代码
# 安装压测工具 pip install aiohttp # 并发压测脚本(100 并发,1000 请求) python -c " import asyncio, aiohttp, time, json async def request(session): async with session.post( 'http://localhost:36000/v1/chat/completions', json={ 'model': '/home/roots/models/DeepSeek-R1-Distill-Llama-8B', 'messages': [{'role': 'user', 'content': '你好'}], 'max_tokens': 50 } ) as resp: return await resp.json() async def main(): async with aiohttp.ClientSession() as session: start = time.time() tasks = [request(session) for _ in range(1000)] await asyncio.gather(*tasks) print(f'1000 请求完成,耗时: {time.time()-start:.2f}s') print(f'平均 QPS: {1000/(time.time()-start):.2f}') asyncio.run(main())

七、生产环境加固

7.1 Systemd 服务化

展开代码
sudo tee /etc/systemd/system/vllm-deepseek.service <<'EOF' [Unit] Description=vLLM DeepSeek-R1 Service After=network.target [Service] Type=simple User=roots Group=roots WorkingDirectory=/home/roots Environment="PATH=/home/roots/miniconda3/envs/llm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" Environment="CUDA_VISIBLE_DEVICES=0,1" Environment="VLLM_LOGGING_LEVEL=INFO" ExecStart=/home/roots/miniconda3/envs/llm/bin/python -m vllm.entrypoints.openai.api_server \ --model /home/roots/models/DeepSeek-R1-Distill-Llama-70B \ --host 0.0.0.0 \ --port 36000 \ --dtype half \ --tensor-parallel-size 2 \ --quantization bitsandbytes \ --gpu-memory-utilization 0.95 \ --trust-remote-code \ --max-model-len 8192 Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now vllm-deepseek sudo systemctl status vllm-deepseek

7.2 Nginx 反向代理(SSL + 限流)

展开代码
# /etc/nginx/sites-available/vllm server { listen 443 ssl http2; server_name llm.yourdomain.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://localhost:36000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 限流:每分钟 100 请求 limit_req zone=api_limit burst=20 nodelay; } } # 限流配置(http 块) limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m;

7.3 监控与告警(Prometheus + Grafana)

展开代码
# vLLM 自带 metrics 端点 curl http://localhost:36000/metrics # 关键指标 vllm:gpu_cache_usage_perc # KV-Cache 使用率 vllm:num_requests_running # 正在处理的请求数 vllm:time_to_first_token_seconds # 首 token 延迟 vllm:time_per_output_token_seconds # 生成速度

八、故障排查速查表

现象可能原因解决
CUDA out of memory模型太大,显存不足--quantization bitsandbytes 或换小模型
RuntimeError: CUDA error驱动/CUDA 版本不匹配重装对应版本 PyTorch
生成速度慢未使用 FP16/BF16--dtype half
首 token 延迟高模型未预热,KV-Cache 空发送 warm-up 请求
并发一高就 OOMmax-num-seqs 太大降低 --max-num-seqs
中文乱码分词器配置错误检查 tokenizer_config.json

本文作者:zzz

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!