
1. 无头服务器上的“本地大模型”到底怎么用1.1 先看这套方案的适用场景最近我把一台淘汰下来的旧服务器重新翻出来装好 Ubuntu Server插上一块 24G 显存的卡然后全程没碰过它的图形桌面连显示器都没接只靠 SSH 登进去干活。折腾完之后这台无头服务器变成了我的“本地 AI 工作站”DeepSeek 模型在它上面跑起来我这边用终端工具连上去在命令行里直接让它写代码、解释报错、改脚本。这套玩法最吸引我的一点是所有请求都走内网数据不出门。对于手上有敏感代码或者不想把内容丢给云端 API 的人来说这是刚需。同时因为走的是 OpenAI 兼容接口客户端的选择非常自由——我这次用的是千问终端Qwen Code CLI它本质上是把 Qwen 的 Agent 能力封装成了一个终端工具但底层支持对接任意 OpenAI 兼容的服务地址就把它接到了本地 DeepSeek 上。如果你是下面这几类人这篇文章应该能帮你省不少时间想在一台无图形界面服务器上本地部署大模型的人希望用终端工具不一定是 Qwen CodeClaude Code 的兼容客户端、aider、codex 之类同理接入本地模型的开发者以及手里显卡不大但想搞懂“模型权重、显存、量化、API 服务”这一整套链路怎么串起来的人。1.2 部署前必须搞清的三个基础概念先别急着敲命令把这几个概念理顺后面踩坑会少一半。第一个是 headless server。无图形界面服务器没有 X11、没有 Wayland、没有桌面进程所有操作都是命令行。这不影响你跑大模型。相反少了图形环境显存和内存反而更干净。你远程操作时只需要一个 SSH 会话或者配合 tmux 保住后台任务。第二个是 OpenAI 兼容接口。DeepSeek 模型本身是一堆权重文件不能直接跟客户端对话。你需要用一个推理框架把它加载起来暴露成一个 HTTP 服务最常见的协议就是 OpenAI 的/v1/chat/completions。只要服务端把这个接口实现好了任何支持 OpenAI 协议的工具都能接上来。这就是“千问终端能连接本地 DeepSeek”的最核心前提千问终端负责交互和工具调用DeepSeek 服务负责生成内容。第三个是模型名与服务名。服务器上加载的模型有一个名字客户端请求里要指定这个名字。两者不一致客户端会报 model not found。这个坑我后面会详细讲很多人联调失败就是卡在名字上。2. DeepSeek 部署选型三条路线我最终留了哪个2.1 三条路线的核心差异本地部署 DeepSeek主流就三条路Ollama、vLLM、llama.cpp。我先把它们拉到一个表格里看差异再说我的选择。路线上手难度性能/并发OpenAI 兼容完整度适合场景Ollama极低中等默认串行多基础 chat 接口可用个人尝鲜、单用户聊天vLLM中等高连续批处理吞吐强很高工具调用/流式兼容好接终端 Agent、多人使用llama.cpp中高低显存场景更灵活基本 chat 接口可用CPU 推理、极小显存机器Ollama 真的是“一条命令跑起来”的典型代表。ollama run deepseek-r1:7b模型自动拉取端口 11434自带/v1兼容端点。如果你只是想在服务器上偶尔聊两句用 Ollama 就够了。但这里有个关键问题如果把 Ollama 接到千问终端这类 Agent 工具上Agent 会频繁发起多轮请求还可能带工具调用参数。Ollama 的 OpenAI 兼容实现属于“能用但不完整”遇到工具调用、流式输出、并发请求时表现不太稳响应排队逻辑也比较简单。我用 Ollama 试了两天放弃的原因不是跑不起来而是 Agent 场景下偶发超时和响应截断。llama.cpp 强在极低显存也能跑量化方式灵活纯 CPU 也能转。但它的服务化能力和高并发吞吐不如 vLLMOpenAI 接口需要额外编译开 server 模式工具调用支持也弱一些。它更适合“我要在一台 4G 显存的老机器上死磕一个小模型”的场景。2.2 显存、参数量、量化档位的实际对应关系你可能已经看到过“本地部署 DeepSeek”这个说法但要注意DeepSeek 官方发布的大型模型是几百 B 参数的 MoE 模型消费级卡根本装不下。我们在本地部署的通常是 DeepSeek 蒸馏版比如 DeepSeek-R1-Distill-Qwen 系列或者开源社区做的量化版。模型文件的体积由参数量和精度决定。一个 7B 模型BF16 精度需要约 14G 显存Q4 量化后只需要约 5G。一个 14B 模型BF16 约 28GQ4 约 9G。32B 的蒸馏版BF16 要 64GAWQ 4bit 量化大约 20G 上下。所以选模型前先看一眼nvidia-smi确认显存8G 显存建议 7B Q4 量化12G~16G 显存建议 14B Q4 或者 7B BF1624G 及以上可以上 32B 的 AWQ 量化版体验完全不一样。我最后选了 14B 量化版本。因为我要用千问终端做代码辅助不是做数学推理14B 的蒸馏版在中文表达和代码理解上已经够用而且 24G 显存跑 AWQ 还能留出足够的 KV cache 空间长对话不会轻易爆显存。2.3 为什么最终选择直接跑推理框架而不是全家桶式工具我当时的最优解是模型用 vLLM 加载服务挂 systemd客户端用千问终端。选择 vLLM 的直接原因是它的 OpenAI 兼容实现完成度高。它对chat.completions的流式输出、tool call、response_format 这些参数支持得很标准而且并发吞吐比 Ollama 高一个数量级。这不是说 Ollama 差而是“忠实实现 OpenAI 协议”这件事上vLLM 确实更可靠。另一个原因是 vLLM 有连续批处理continuous batching即多个请求可以动态混在同一批里推理而不是一个排一个。千问终端在 Agent 模式下一次可能发起多个工具调用vLLM 能更平滑地处理。如果你只是单用户单请求地聊天这个优势体现不明显但只要叠加了 Agent 场景体感会差很多。3. 命令行部署 DeepSeek 服务的完整记录3.1 环境准备SSH、Python 虚拟环境、CUDA我的服务器是一台没有显示器的 Ubuntu Server所有操作通过 SSH 完成。如果你还没装 CUDA 驱动先跑nvidia-smi看驱动版本和显存总量然后按驱动版本装匹配的 CUDA toolkit。注意vLLM 的 wheel 包对 CUDA 版本有要求装之前先到 PyPI 上确认一下对应关系省得后面报错。接着建一个独立 Python 环境避免污染系统 Pythonsudo apt update sudo apt install -y python3-venv python3-pip mkdir -p /home/ubuntu/deepseek cd /home/ubuntu/deepseek python3 -m venv .venv source .venv/bin/activate pip install --upgrade pip pip install vllm装完后用python -c import vllm; print(vllm.__version__)验证一下。如果服务器显存只有 8G 这种规模不建议硬上 vLLM直接用 llama.cpp 更合适因为 vLLM 自身也要占用一些显存做管理。3.2 模型权重下载用国内镜像省心很多下载模型权重时直接从 Hugging Face 拉经常不稳定。我用了 ModelScope 镜像速度快好几个量级而且命令极其相似。以我在用的 14B AWQ 量化版本为例pip install modelscope modelscope download --model Qwen/DeepSeek-R1-Distill-Qwen-14B-AWQ --local_dir /home/ubuntu/deepseek/DeepSeek-R1-Distill-Qwen-14B-AWQ下载完成后确认目录里包含 config.json、tokenizer.json 和分片权重文件。如果你找不到 AWQ 版本也可以换成 GPTQ 版本vLLM 都能识别。注意如果你跑的是 BF16 原始权重显存需求会翻倍。我建议先把显存算明白再下载否则浪费带宽和时间。3.3 启动 vLLM 服务并注册成 systemd 服务手动启动先验证一次cd /home/ubuntu/deepseek source .venv/bin/activate python -m vllm.entrypoints.openai.api_server \ --model /home/ubuntu/deepseek/DeepSeek-R1-Distill-Qwen-14B-AWQ \ --served-model-name deepseek-r1-14b \ --host 127.0.0.1 \ --port 8000 \ --max-model-len 32768 \ --gpu-memory-utilization 0.9每个参数都有讲究。--served-model-name是给客户端看的模型名我简写成deepseek-r1-14b避免默认名里带斜杠造成配模型名时出错。--host 127.0.0.1表示只监听本机回环地址不允许外网直接访问安全上更稳妥。--max-model-len 32768是上下文窗口上限默认值可能更大但 32K 在这张卡上已经够用限制它可以让显存分配更合理。--gpu-memory-utilization 0.9给 KV cache 留了余量避免 100% 显存打满后偶发 OOM。确认能跑起来之后把它注册成 systemd 服务。这样做的好处是SSH 断开不影响服务服务器重启后服务自动拉起日志统一走 journalctl。[Unit] DescriptionDeepSeek vLLM API Server Afternetwork-online.target [Service] Userubuntu Groupubuntu WorkingDirectory/home/ubuntu/deepseek EnvironmentPATH/home/ubuntu/deepseek/.venv/bin:/usr/local/bin ExecStart/home/ubuntu/deepseek/.venv/bin/python -m vllm.entrypoints.openai.api_server --model /home/ubuntu/deepseek/DeepSeek-R1-Distill-Qwen-14B-AWQ --served-model-name deepseek-r1-14b --host 127.0.0.1 --port 8000 --max-model-len 32768 --gpu-memory-utilization 0.9 Restarton-failure RestartSec10 [Install] WantedBymulti-user.target把以上内容存到/etc/systemd/system/deepseek-vllm.service然后sudo systemctl daemon-reload sudo systemctl enable deepseek-vllm sudo systemctl start deepseek-vllm systemctl status deepseek-vllm跑起来之后看看传输控制协议端口和显存占用ss -lntp | grep 8000和nvidia-smi。3.4 用 curl 先自测一遍服务启动后不要急着配客户端先用 curl 直接打一下 API确认服务真的没问题curl http://127.0.0.1:8000/v1/models curl http://127.0.0.1:8000/v1/chat/completions \ -H Content-Type: application/json \ -d {model:deepseek-r1-14b,messages:[{role:user,content:你好}],stream:false}第一个命令用于确认服务在跑、模型名是否正确第二个命令用于确认对话链路是否通。如果这里通了说明问题只可能在客户端侧排查范围一下子缩小了。4. 千问终端接入改三个配置让它跑在本地模型上4.1 千问终端的安装千问终端的命令行工具通过 npm 安装前提是服务器或者你本地的开发机上有 Node.js 环境。因为我习惯在本地 Mac 上写代码所以我是在本地装的客户端远程服务器只跑模型服务。npm install -g qwen-code/qwen-code装完先执行qwen --version和qwen --help确认安装成功。有一点要注意不同版本的千问终端支持的配置方式和字段名可能有细微差别所以拿到工具后第一件事是看帮助信息而不是盲目复制网上的配置。4.2 配置文件中真正管用的三个字段千问终端默认会请求官方 Qwen API要切换到本地 DeepSeek核心是改三样东西API 地址、API Key、模型名。在配置文件里常见路径是~/.qwen_code/config.json这样写{ base_url: http://127.0.0.1:8000/v1, api_key: local-deepseek-key, model: deepseek-r1-14b }这三个字段分别解决什么问题base_url必须带/v1。vLLM 的 OpenAI 兼容接口挂载在/v1路径下如果你只写到http://127.0.0.1:8000客户端会拿着这个地址去拼/chat/completions最后请求打到不存在的路径上返回 404api_key随便填一个非空字符串即可。本地服务没有真正鉴权但很多客户端在 API Key 为空时会拒绝发起请求或报鉴权错误model要和 vLLM 启动时的--served-model-name完全一致我这里是deepseek-r1-14b。如果你不确定配置文件在哪执行一下qwen --help里面会直接打印配置文件读取路径和优先级。这种方式最稳妥。4.3 从远程照常用SSH 端口转发与安全设置我的模型服务监听的是127.0.0.1:8000所以外部机器访问不了。按上文方式配置时必须先在本地和服务器之间建立一条 SSH 隧道ssh -N -L 8000:127.0.0.1:8000 ubuntuserver-ip这个命令的含义是把本地 8000 端口的流量全部转发到远端服务器的 8000 端口。建立之后你的本地机器上http://127.0.0.1:8000就能访问到远程的 DeepSeek 服务了。客户端那边不需要改任何东西因为它以为自己就在访问本机。为什么不直接把 vLLM 监听在0.0.0.0上、省掉隧道因为没必要。如果监听公网就得自己处理访问控制、防火墙规则一旦配置疏漏端口裸奔在公网上被人扫到谁都能调用你的模型显卡会被跑满还会产生不必要的费用。SSH 隧道方案不需要改任何服务配置还能顺带加密传输内容是最省心的安全方案。5. 联调时最容易踩的四个坑附排查链路5.1 服务通了但客户端连不上的排查顺序我遇到过最典型的场景是curl 明明能正常拿到回复千问终端却一直报连接错误。这时不要急着怀疑客户端坏了按顺序排查服务端监听地址。看 vLLM 是否只绑定了127.0.0.1如果你试图通过服务器公网 IP 直连 8000 端口就会失败SSH 隧道是否建立成功。确认隧道端口是否对应本地 8000 对远端 8000不要搞反客户端配置的 base_url 结尾是否包含/v1终端环境变量里是否有 HTTP_PROXY 覆盖了请求目标。这个坑最隐蔽我单独在 5.4 展开。排查的时候多用curl加-v参数看完整请求路径比在客户端里瞎试高效得多。5.2 模型名不匹配的报错现场如果你启动 vLLM 时没用--served-model-name默认模型名会是完整的权重名字比如Qwen/DeepSeek-R1-Distill-Qwen-14B-AWQ里面带斜杠。有些客户端在拼接请求字段时对这个斜杠处理得不好甚至直接在配置里忽略了你填的 model导致请求用的名字和服务端注册的名字对不上返回类似“model not found”的错误。我的建议是不管模型权重目录叫什么启动 vLLM 时务必设置一个干净的--served-model-name比如deepseek-r1-14b没有斜杠、没有空格、全是小写字母和数字。然后 curlhttp://127.0.0.1:8000/v1/models验证返回的模型 id 是什么再把这个 id 原样填到客户端配置里。5.3 上下文和显存的“隐形天花板”Agent 工具和普通聊天有个很大的区别它发送的请求里自带了一套很长的 system prompt包括任务说明、工具定义、输出格式要求动不动就两三千 token。如果你服务的--max-model-len设得太小比如默认 4096客户端一次完整的工具调用请求就可能超出上限服务端直接拒绝表现像是“客户端发不出请求”。我后来把--max-model-len设成 32768情况立刻改善。但你也要明白上下文窗口越大KV cache 占的显存越多qwen code 这类工具又倾向于把大量历史代码塞进对话里所以不要盲目开 128K小卡上把它调小一点反而是保护自己。如果你发现体验一段时间后对话开始变慢多半是长上下文把显存吃完了此时最有效的办法是开一个新会话重置上下文。5.4 很隐蔽的本地网络环境变量问题这个坑我排了很久。服务器上之前配过 HTTP_PROXY 环境变量结果 vLLM 本身不影响但千问终端运行时会读取这些变量把对127.0.0.1的请求也一股脑送进代理服务代理服务又连不回去于是客户端表现是“请求发出后一直没响应”或“连接 reset”。解决办法很简单在启动客户端的环境变量里加上 NO_PROXY或者直接清掉代理相关变量export NO_PROXY127.0.0.1,localhost export no_proxy127.0.0.1,localhost我的经验是凡是做本地服务对接先把 HTTP_PROXY、HTTPS_PROXY、ALL_PROXY 这些变量清一遍。这不是说代理本身有问题而是很多程序在实现时不会区分“内网地址”和“外网地址”一律走代理结果本地回环请求反而被绕没了。6. 日常使用体验与针对性的调参建议6.1 推荐给终端编程场景的模型与量化档位用千问终端接本地 DeepSeek目的大多数是写代码、查资料、改脚本。这个场景下响应速度和稳定性比极致的推理深度更重要。我在 24G 显存上最终选了 14B AWQ 量化版响应速度快中文表达能力也不错。如果你的显存只有 16G7B Q4 会比较稳如果有 40G 以上直接上 32B AWQ体验会再上一个台阶。R1 蒸馏版有个特点会输出很长的思维链。终端编程场景下这可能表现为模型在“思考”了一大段之后才给答案如果你希望交互更轻快可以在 system prompt 里加一句“直接回答不要输出思考过程”体感会好很多。6.2 会话管理tmux 结合 systemd模型服务已经用 systemd 管理了SSH 断开也不影响。但你本地跑ssh -L隧道时隧道进程是挂在当前终端的断开 SSH 隧道就断了。建议把隧道放进 tmux 会话里或者写成一个后台脚本避免每次重连。常用做法tmux new -s tunnel ssh -N -L 8000:127.0.0.1:8000 ubuntuserver-ip按下CtrlB再按D把会话放到后台需要时用tmux attach -t tunnel回来看状态。日志方面用journalctl -u deepseek-vllm -f盯服务输出排查问题时很管用。6.3 一点个人体会整套流程跑通之后我最大的感受是本地模型 终端工具的组合解决的不只是“数据不出门”这个需求更重要的是它把大模型能力变成了一个可编程的本地基础设施。千问终端这类工具负责交互和工具编排DeepSeek 服务负责生成两者通过标准接口解耦换模型、换客户端都非常容易。我后来试过把另一个开源模型接到同一个服务端口上客户端配置一行没改只是重新跑了一次 vLLM加载新的权重客户端继续指向同一个地址直接就通了。以后如果再有人问我“无图形界面服务器能不能跑大模型”我会说不仅能跑还跑得很舒服前提是你把服务端和客户端拆开看服务端只做推理客户端只做交互接口统一用 OpenAI 兼容协议。这样一来DeepSeek、Qwen、其他开源模型都只是服务端的一个可替换组件而不是被某个工具绑死的固定搭配。