简介:《DeepSeek 在 Linux 系统下的手动部署步骤与注意事项》是一份面向深度学习开发者及 Linux 运维人员的 PDF 操作指南,聚焦如何在 Ubuntu 等系统中从零完成 DeepSeek 的安装、配置与运行,适合准备用 GPU 加速训练或推理的读者参考。资源共 1 个 PDF 文件,大小 215KB,内容紧凑、步骤清晰,涵盖环境准备、创建 Python 虚拟环境、克隆代码库、安装依赖包、修改 config.yaml、准备数据,以及执行 train.py 和 infer.py 的完整流程。目前已有 794 人学习下载。文档不仅给出终端命令,还特别分析了依赖包冲突、GPU 未被检测到、内存不足、文件权限等部署中常见的坑,并给出对应检查方向,如确认 CUDA/cuDNN 版本兼容性、检查 PATH 与 LD_LIBRARY_PATH 环境变量等。对首次在 Linux 上部署 DeepSeek 的新手来说,这份资源能帮助少走弯路,快速完成模型运行环境的搭建。
1. DeepSeek 在 Linux 下的手动部署:先想清楚这三件事
如果你已经拿到一台 Linux 服务器,想在它上面把 DeepSeek 跑起来,最省事的做法当然是甩一个 Docker 命令或者一键脚本,但手动部署的意义恰恰在于:你能看清每个组件在做什么,也能在出问题时知道去哪一行日志里找答案。DeepSeek 这类大模型在 Linux 下的手动部署,本质上就是三件事——准备环境、选对推理引擎、把模型权重下载下来并以服务形式启动。它解决的核心诉求是对环境的完全掌控:定制量化格式、指定显存分配策略、接入你自己的鉴权和调度逻辑。这篇文章适合两类人:一是手上有多卡 GPU 机器、想跑满血版 DeepSeek-R1 的工程师,二是只有一张消费级显卡、想跑蒸馏版做原型验证的开发者。手动部署比看起来简单,但坑也集中在环境版本和显存估算上,下文会一步步拆开。
2. Linux 部署前的环境盘点:显卡、驱动与 Python 解释器
2.1 先确认你是哪一类部署者:单卡跑蒸馏版还是多卡跑大模型
DeepSeek 模型分两条线:一条是满血版,参数量达到 671B 的 MoE 架构,哪怕用 FP8 量化,权重也有 700GB 上下,单张 80GB 的卡根本装不下,必须走多卡张量并行或多机推理;另一条是蒸馏版(常见的有 7B、14B、32B、70B 等),是在小模型上把满血版的推理风格蒸馏出来的,单张 24GB 的卡就能跑量化后的 32B 版本。手动部署的第一步不是敲命令,而是先回答「我到底要跑哪个模型」,因为这一决定直接约束后面所有环节:模型文件从哪下载、用哪个推理引擎、需要几张卡、显存够不够。
我一般会这样判断:如果你的机器是单卡且显存在 24GB 以下,主战场是 7B 到 32B 的蒸馏版,部署重点是量化格式和 CPU/GPU 协同;如果你手上有 4 到 8 张 80GB 的卡,目标就是满血版,部署重点是并行策略和推理引擎版本。想清楚这些再动手,能省下大量试错时间。
2.2 用这几条命令把硬件底细摸清
进入实操前,先花两分钟把机器的家底摸清。下面三组命令我在每台新机器上都会跑一遍,它们能回答「显卡是否可用」「驱动和 CUDA 是否匹配」「内存够不够」三个问题。
# 查看 GPU 型号、显存总量和当前占用 nvidia-smi # 查看 GPU 拓扑,确认多卡之间是否支持 NVLink / PCIe 直连 nvidia-smi topo -m # 查看系统内存总量和当前可用内存(模型权重缓存、CPU offload 都需要) free -gnvidia-smi是最先要看的。注意右上角的 CUDA Version 表示驱动支持的最高 CUDA 版本,而不是已安装的 CUDA 工具包版本;推理引擎(如 vLLM)很多情况下自带 CUDA runtime,所以系统里装不装 CUDA 工具包反而没那么关键,驱动版本拖了后腿才更常见。nvidia-smi topo -m在多卡场景下要看 NV# 标记,NVLink 直连的卡之间通信延迟低,张量并行效率高;如果显示都是 PCIe 连接,就要考虑降低并行度、改用数据并行或干脆选小模型。free -g用来确认内存——大模型权重在加载时会先落到内存再搬运到显存,内存不足会直接加载失败。
2.3 依赖安装:CUDA、cuDNN 与 Python 虚拟环境的取舍
很多人在依赖这步翻车,根源是把「系统级依赖」和「应用级依赖」混在一起处理。对于 DeepSeek 手动部署,系统级依赖只有两个:NVIDIA 驱动和 Python 解释器,其余全部放进虚拟环境。CUDA 工具包和 cuDNN 不是必须手动装的——像 vLLM 这类推理框架会通过 pip 依赖拉取自己的 CUDA runtime 库,你系统里装了一套 CUDA 工具包反而可能与框架自带的版本冲突。我踩过的坑是:某次在系统里装了 CUDA 12.x 并改了LD_LIBRARY_PATH,vLLM 启动时加载了系统动态库,结果libcudart版本对不上直接崩。后面统一原则:不在全局环境动 CUDA 相关变量,依赖全部交给虚拟环境。
# 创建专用虚拟环境(Python 版本建议 3.10 或 3.11,多数推理引擎适配较好) python3 -m venv deepseek-venv # 激活虚拟环境 source deepseek-venv/bin/activate # 升级 pip 和基础工具链 pip install --upgrade pip setuptools wheel虚拟环境的优势不只是隔离包版本,更关键的是它把LD_LIBRARY_PATH这类全局变量也一并隔离了,你可以在环境内部自由指定 CUDA 相关路径而不影响系统其他服务。Python 版本我建议 3.10 或 3.11,太老的解释器装不上新版推理引擎,太新的解释器部分依赖库的预编译 wheel 还没跟上。到这里,环境准备就绪,下一步是选推理引擎和模型格式。
3. 推理引擎与模型格式选型:vLLM 主路线与备选方案
3.1 为什么首选 vLLM:连续批处理与 PagedAttention
大模型推理的吞吐瓶颈不在计算,而在「显存管理和批调度」。vLLM 之所以成为主流选择,是因为它解决了两件关键事:PagedAttention 让 KV Cache 不再需要一整块连续显存,而是像操作系统的内存分页一样按需分配,显存碎片率大幅下降;continuous batching 让推理引擎在每个 step 动态决定哪些请求进入批处理,多用户并发时吞吐量能比朴素实现高出一个量级。对 DeepSeek 这种超大规模 MoE 模型,这两点直接影响部署后的实际使用体验。
选型时我还会看重生态对齐:DeepSeek 的 MoE 结构里用到 MLA 注意力机制,主流推理框架对它的支持是逐步完善的,每次版本更新都可能带来兼容性变化。我的建议是:选 vLLM 时优先用当前稳定版本线的最新小版本,避开刚从 alpha 转正的激进版本。如果你已经在用某个版本且模型能正常返回结果,不要为了升级而升级。
3.2 备选路线 Ollama 与 llama.cpp:什么时候换
vLLM 不是唯一选择,也不是所有场景的最佳选择。Ollama 的亮点是开箱即用,一条命令就能把模型拉下来并以 OpenAI 兼容接口暴露,适合个人开发机快速体验;llama.cpp 则是纯 CPU/GPU 混合推理的典范,量化格式 GGUF 在显存不足时可以依靠 CPU offload 硬跑。但这两条路线在 DeepSeek 满血版面前都有限制:Ollama 对超大规模 MoE 的多卡并行支持不如 vLLM 细,llama.cpp 的 CPU 推理对于 671B 模型来说速度不现实。
我一般这样决策:只有一张卡、显存 24GB 以下、目标是跑蒸馏版做功能验证,选 Ollama 最省心;需要自定义调度、追求高并发吞吐、跑满血版多卡并行,选 vLLM。中间地带(比如显存 48GB 单卡)则看你对速度还是易用性的权重更大。手动部署说到底是为了掌控细节,vLLM 的启动参数和监控手段也更适合作为主路线。
3.3 量化格式怎么选:BF16、FP8 与 AWQ 的现实差异
模型量化是部署中最容易陷入「玄学」的环节。按工程惯例,量化方式的选择取决于显存瓶颈的类型:权重占用是主要瓶颈时考虑 FP8 或 AWQ,KV Cache 显存不足时考虑 KV Cache 量化。BF16 是基线格式,精度最高但体积也最大;FP8 是当前大模型部署的主流折中点,精度损失在多数场景下难以察觉,体积却直接减半;AWQ 这类权重量化则更适合显存紧张的单卡场景,代价是推理速度可能略降。
对 DeepSeek 系列模型的常见选择是:多卡显存充足时直接用 BF16 或 FP8 权重,蒸馏版在单卡上优先试 AWQ 或 GGUF 的 4-bit 版本。不要一味追求低比特——量化位数越低,幻觉和乱答的概率越高,这在大模型上比在 CV 任务上更敏感。如果量化后发现输出质量明显下降,先往高比特回退,而不是急着调温度参数。
4. 手动部署实操:从创建虚拟环境到启动服务
4.1 安装 vLLM 推理引擎与核心依赖
进入真实部署环节。激活虚拟环境后,先安装 vLLM 本身及配套依赖。这里要说明的是,不同模型在 vLLM 里的兼容性存在差异,建议以「当前模型在 vLLM 官方文档中的支持状态」为判断基准,而不是追新安装 nightly 构建。
# 激活前面创建的虚拟环境 source deepseek-venv/bin/activate # 安装 vLLM 及依赖(pip 会自动解析 CUDA 版本对应的 wheel;如果网络受限,可切换国内 PyPI 镜像) pip install vllm # 确认安装版本,方便后续对照日志排查 pip show vllmpip show vllm输出的 Version 字段很重要,后续如果推理异常,到 vLLM 的 GitHub issues 或项目文档里排查时,对方第一句就会问你版本号。网络受限时可以用-i https://pypi.tuna.tsinghua.edu.cn/simple这类镜像站,但要注意镜像站的同步延迟,可能需要错开一段时间再拉取。vLLM 安装时会把torch、transformers、tokenizers等一并装上,不需要手动单独安装,也不要提前装好这些库以免版本互踩。
4.2 下载模型权重:目录规划与校验
模型权重是纯黑匣子环节——看不到内部结构,只能通过哈希值和文件大小判断是否正确。下载前先规划目录,我习惯把所有模型权重放在一个独立磁盘分区下,避免和系统盘抢占空间。
# 创建模型目录,按「模型名-参数量-量化格式-日期」命名,方便后续多版本共存 mkdir -p /data/models/DeepSeek-R1-Distill-32B-AWQ-20250101 cd /data/models/DeepSeek-R1-Distill-32B-AWQ-20250101 # 使用 huggingface-cli 下载指定仓库(示例:下载 32B AWQ 量化版,按需替换仓库名) pip install -U huggingface_hub huggingface-cli download [模型仓库名] --local-dir .--local-dir .把权重下载到当前目录,而不是默认的缓存目录,这样模型路径可控。下载前通过模型仓库页面确认文件总大小和量化格式,如果仓库包含多个分支,用--revision指定分支。下载完成后做两件事:占用空间较大的权重文件用du -sh确认体积符合预期;若仓库提供了sha256校验文件,跑一遍校验,避免传输损坏导致推理时出现随机乱答。
4.3 写一个最小启动脚本并跑起来
手动部署与一键脚本最大的区别,在于你应该保留一份能看懂每行参数的启动命令。我习惯把启动参数写进一个 shell 脚本,而不是每次敲一长串命令,这样换模型、调参数时只改一处。
#!/bin/bash # 启动脚本 vllm_start.sh source /data/deepseek-venv/bin/activate # 关键参数说明: # --model 模型权重目录或仓库路径 # --tensor-parallel-size 张量并行卡数,建议不超过同一 NUMA 节点内 GPU 数 # --max-model-len 最大上下文长度,直接影响 KV Cache 显存占用 # --gpu-memory-utilization 允许使用的显存比例,留一定余量给模型权重外的开销 # --port API 服务端口 python -m vllm.entrypoints.openai.api_server \ --model /data/models/DeepSeek-R1-Distill-32B-AWQ-20250101 \ --tensor-parallel-size 1 \ --max-model-len 8192 \ --gpu-memory-utilization 0.9 \ --port 8000--tensor-parallel-size是单卡部署时最容易填错的地方:只有一张卡就填 1,填 2 会直接报错。--max-model-len要按实际业务需要来定,填得太大 KV Cache 显存就大,能支撑的并发就少;填得太小长文本被截断。--gpu-memory-utilization 0.9表示允许用到 90% 显存,剩余 10% 留给驱动和模型加载临时开销,如果模型刚好卡在显存边缘,可以尝试降到 0.95,但要承担 OOM 风险。启动后要等日志出现类似Application startup complete的字样才算就绪,这个阶段看似卡住是在做模型权重加载和预热。
4.4 验证服务可用性的三条命令
服务起来后,先用最简单的方式验证推理链路是否打通。我常犯的错误是一上来就写复杂测试脚本,结果分不清是网络问题还是模型问题;正确顺序是先确认进程、再确认接口、最后确认推理。
# 1. 确认服务进程和端口在监听 ps -ef | grep vllm ss -tlnp | grep 8000 # 2. 用 curl 直接打一个最小请求,确认接口返回 curl http://localhost:8000/v1/models # 3. 发送一条推理请求,确认模型能正常生成 curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model": "deepseek", "messages": [{"role": "user", "content": "你好"}], "max_tokens": 64}'第一步失败说明进程没起稳,回到终端看启动日志的具体报错;第二步失败说明服务还没就绪或端口被防火墙挡住;第三步失败才轮到排查模型本身问题。/v1/models返回的模型 ID 可能与你传入的目录名不同,它是从模型配置读取的,写请求体时model字段要填接口返回的 ID,而不是目录名,这是最常见的低级错误。
5. 部署避坑指南:五条真实踩坑记录
5.1 现象:启动时报 CUDA error: device-side assert triggered
模型加载完成、服务也起来了,但第一次请求就崩掉,终端刷出CUDA error。原因是在消费级显卡上跑需要较新计算能力的量化算子,或者驱动版本太旧。解决:先升级 NVIDIA 驱动到当前较新稳定版,重启机器;如果还不行,把量化格式从 AWQ 换成 GPTQ 或直接 BF16 验证——有些量化 Kernel 对特定 GPU 架构的支持不完善。这类问题最怕的不是报错本身,而是错误的模糊性,所以一定要先确认驱动版本和模型量化格式的匹配关系。
5.2 现象:模型加载到一半就 OOM 被杀
vllm启动日志显示权重加载到某个百分比就报显存不足。原因通常有两个:一是模型量化格式选得太高(如 BF16 权重占了过多显存);二是--max-model-len或--gpu-memory-utilization计算不合理。解决:先算一笔账——权重大小除以卡数,加上 KV Cache 预留,是否超过单卡显存;再尝试降低--max-model-len,比如从 16384 降到 8192;最后一招是换更低位宽的量化版本。注意看的是nvidia-smi里的Memory-Usage而不是进程内显存统计,两者可能对不上。
5.3 现象:服务能起,但端口一访问就卡死或超时
这不是网络问题,而是「请求进入推理队列后无法完成生成」。常见原因是--max-model-len设置得过大,导致 KV Cache 显存几乎占满,一旦有并发请求,逐 token 生成阶段显存不够就持续阻塞。解决:重启时把--max-model-len调低,同时设置--served-model-name显式指定模型名,避免请求体里的模型名与配置不一致导致请求被拒。排查时可以观察日志里是否反复出现GC或Timeout字样,这类信息远比「卡死」这个现象更有指向性。
5.4 现象:下载模型时中断,重新下载又从零开始
huggingface-cli download走的是断点续传,但如果网络长时中断,进程退出后缓存会被清理,下次重新执行确实可能从头开始。解决:不修改默认行为,而是改用以下方式——先下载到缓存目录,再硬链接到目标目录;或者用小工具hf_transfer加速下载,减少中断概率。更重要的一点是别在模型下载中途去做系统升级或重启,这类大文件下载本身就适合放在 tmux 或 systemd 服务里托管,避免 SSH 断连导致进程被杀。
5.5 现象:一次请求正常,并发一上来就大量报错
这是部署后最常遇到也最容易被误判为「模型不行」的问题。原因通常是并发请求全部挤在同一时刻进入批处理,KV Cache 瞬时分配失败,或max-num-seqs参数限得过死。解决:--max-num-seqs适当调大(默认值对于大模型往往偏保守),同时压测工具的并发数先从小到大分级探测;另外确认--gpu-memory-utilization不要卡在临界值——显存利用率越高,并发下的波动容忍度越低。遇事不要先怀疑模型,多数并发报错能从显存余量和批处理参数找到答案。
6. 部署后的验证、监控与调优技巧
6.1 压测是最快的验证方式
服务跑通只是起点,真正的验证是用模拟业务流量测试并发吞吐。我习惯用简易的 Python 并发脚本测三个指标:首 token 延迟、平均输出速度、并发上限。并发脚本可以控制请求数和 batch 数量,观察显存与日志的变化。
# 简易并发压测脚本 import requests, concurrent.futures URL = "http://localhost:8000/v1/chat/completions" data = { "model": "deepseek", "messages": [{"role": "user", "content": "写一段 200 字的技术说明"}], "max_tokens": 512, "temperature": 0.7, } def send_req(idx): resp = requests.post(URL, json=data, timeout=120) return idx, resp.status_code, resp.elapsed.total_seconds() with concurrent.futures.ThreadPoolExecutor(max_workers=8) as pool: results = list(pool.map(send_req, range(16))) for r in results: print(r)脚本里max_workers=8是并发请求数,可以先从 1 起步逐级加,观察不同并发档位下各请求的耗时变化,这比一次性压满更能暴露瓶颈区。如果并发 8 时部分请求超时,回到第 5.5 节的方法调整参数,而不是压完就下结论。压测结果要记录到本地,后续每次调整参数都跑同一套脚本对比,这是最朴素的调优闭环。
6.2 监控显存与日志的习惯
部署完成后,养成两个习惯:每跑完一轮压测随手nvidia-smi看显存余量变化;定期翻 vLLM 的请求日志,关注每轮生成的prefix cache hit rate指标——这个指标代表多少 token 命中了前缀缓存,命中率越高,重复前缀的请求响应越快。手动部署带来的控制力就体现在这些细颗粒度的观察上,容器化部署反而很难接触到这层指标。
6.3 进阶调优的几条实用技巧
到最后阶段,给你三个可持续优化的方向:第一,服务入口前加一层请求缓存,对重复性高的查询(如固定模板生成)直接命中缓存,可以显著降低推理负载;第二,如果模型支持分离部署,把预填充和解码阶段拆到不同节点,能改善长时间生成场景下的整体吞吐;第三,设置--enable-prefix-caching这类显式选项,让系统自动复用公共前缀的 KV Cache,与 6.2 节的命中率指标互相照应。
我自己的习惯是每次部署都会把启动参数、压测记录、问题日志三个文件放在同一目录下,出问题时先翻旧账而不是急着重启换参。这种「手动」记录方式在初期看起来比脚本慢,但一旦遇到复现性问题,它的价值就完全体现了。希望这些真实踩过的坑能帮你少折腾一晚,让 DeepSeek 在你的机器上真正跑起来、跑得稳。
本文还有配套的精品资源,点击获取