RTX 4090 24GB + Ubuntu 26.04 LTS:本地大模型部署与测试教程
古董级程序员,大厂出来后一直在创业公司,现在还在一线写 AI 相关的后端。更完整的技术记录写在微信公众号「字与码」:踩过的坑、换技术栈时的权衡、和这些年绕过的弯路,会不定期发在那里。若这篇对你有用,欢迎顺手关注。
这篇是一个持续更新的本地大模型部署教程。目标机器已经定下来:Ubuntu 26.04 LTS,单张 RTX 4090 24GB。目标也很具体:不是跑一次 demo,而是在本地或者内网里长期提供一个能用的模型服务,支持命令行测试、OpenAI-compatible API,以及后续接入 Open WebUI、Continue、Cline 这类客户端。
先说明当前状态:本文已经把完整步骤写成可执行教程,后面实机跑完后,会继续补充真实显存占用、tokens/s、不同上下文长度下的稳定性,以及几个模型的效果对比。
这台机器适合跑什么模型
RTX 4090 的 24GB 显存是一个很微妙、也很实用的区间。它不适合把 70B 级模型用高精度完整塞进显存,但很适合跑 30B 到 35B 级别的 4bit 量化模型。个人开发、中文技术写作、代码辅助、文档总结、轻量知识库问答,基本都落在这个区间。
我准备先按下面的顺序测试:
| 用途 | 候选模型 | 说明 |
|---|---|---|
| 默认通用模型 | Qwen3.6-35B-A3B 的 GGUF 4bit 量化版 | 作为首选候选,兼顾中文、代码和日常问答 |
| 代码模型 | Qwen3-Coder-30B-A3B-Instruct 的 GGUF 4bit 量化版 | 偏代码生成、仓库理解和 Agentic Coding |
| 推理对照 | DeepSeek-R1-Distill-Qwen-32B 的 GGUF 4bit 量化版 | 用于复杂推理、数学和分析任务对比 |
本文先以 Qwen3.6-35B-A3B GGUF 为主线写部署步骤。模型文件建议优先试 Q4_K_M 或同级 4bit 量化。如果实际显存吃紧,就降到 IQ4_NL、Q3_K_M 一类更小的量化;如果显存还有余量,再考虑更高量化质量。
参考入口:
- Qwen3.6-35B-A3B
- Qwen3.6-35B-A3B-GGUF
- Qwen3-Coder-30B-A3B-Instruct
- llama.cpp CUDA 构建文档
- Ubuntu Server NVIDIA 驱动安装文档
- NVIDIA Container Toolkit 安装文档
0. 系统前提
下文假设你已经能 SSH 登录这台机器,并且用户有 sudo 权限。
lsb_release -a
uname -a
期望看到 Ubuntu 26.04 LTS。如果机器是刚装好的系统,先更新软件源和基础包:
sudo apt update
sudo apt upgrade -y
sudo apt install -y \
build-essential \
cmake \
git \
curl \
wget \
unzip \
pkg-config \
python3 \
python3-venv \
python3-pip \
htop \
nvtop
nvtop 不是必须,但调模型时很好用。它能直观看到 GPU 使用率、显存占用和进程。
1. 安装并验证 NVIDIA 驱动
Ubuntu 官方推荐用 ubuntu-drivers 选择驱动。先安装工具并查看推荐项:
sudo apt install -y ubuntu-drivers-common
ubuntu-drivers devices
输出里通常会有一项 recommended。不要硬背某个驱动版本号,直接用系统推荐版本更稳:
sudo ubuntu-drivers install
sudo reboot
重启后检查:
nvidia-smi
至少要确认三件事:
- 能看到
NVIDIA GeForce RTX 4090。 - 能看到驱动版本和 CUDA Version。
- 空闲状态下显存占用不异常。
如果 nvidia-smi 报错,先别继续下载模型。优先排查:
dkms status
lsmod | grep nvidia
journalctl -k | grep -i nvidia | tail -n 80
如果机器启用了 Secure Boot,NVIDIA 内核模块可能加载失败。最省事的做法通常是进 BIOS 关闭 Secure Boot,或者按 Ubuntu 提示给内核模块签名。
2. 准备 Docker GPU 环境
不是所有部署都必须用 Docker,但我建议先配好。以后测试 vLLM、SGLang、Open WebUI 时都会用得上。
先安装 Docker:
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
把当前用户加入 docker 组:
sudo usermod -aG docker "$USER"
newgrp docker
然后安装 NVIDIA Container Toolkit:
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
| sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
| sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
验证 Docker 能看到 GPU:
docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubuntu24.04 nvidia-smi
这里容器镜像用 Ubuntu 24.04 base 没关系,关键是能通过宿主机驱动访问 GPU。只要容器里也能看到 RTX 4090,后面跑容器化推理服务就有基础了。
3. 准备模型目录
建议把模型放在单独的数据盘或固定目录,不要散落在项目目录里。
sudo mkdir -p /data/models/gguf
sudo chown -R "$USER:$USER" /data/models
安装 Hugging Face 下载工具:
python3 -m venv ~/.venvs/hf
source ~/.venvs/hf/bin/activate
pip install -U pip huggingface_hub
如果访问 Hugging Face 较慢,可以临时设置镜像端点:
export HF_ENDPOINT=https://hf-mirror.com
下载 Qwen3.6 的 GGUF 文件时,先到模型仓库确认实际文件名。下面命令写法保留变量,方便替换:
cd /data/models/gguf
MODEL_REPO="unsloth/Qwen3.6-35B-A3B-GGUF"
MODEL_FILE="Qwen3.6-35B-A3B-Q4_K_M.gguf"
huggingface-cli download "$MODEL_REPO" \
"$MODEL_FILE" \
--local-dir /data/models/gguf \
--local-dir-use-symlinks False
如果仓库里的推荐文件名不是 Q4_K_M,就把 MODEL_FILE 改成实际文件名。下载后确认大小:
ls -lh /data/models/gguf
sha256sum /data/models/gguf/*.gguf | tee /data/models/gguf/SHA256SUMS.txt
24GB 显存下,Q4_K_M 级别文件通常会比较贴近上限。后面启动时上下文不要一开始拉满,先用 8K 验证。
4. 编译 llama.cpp CUDA 版本
llama.cpp 是跑 GGUF 最直接的一条路。先安装 CUDA 编译工具。Ubuntu 仓库里的包如果能满足当前版本,直接用:
sudo apt install -y nvidia-cuda-toolkit
nvcc --version
如果系统仓库的 CUDA 包太旧,或者 nvcc 不存在,再换 NVIDIA 官方 CUDA repository。本文先按 Ubuntu 26.04 LTS 的基础路径写。
拉代码并编译:
mkdir -p ~/src
cd ~/src
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
cmake -B build -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j"$(nproc)"
编译完成后检查二进制:
./build/bin/llama-server --help | head
./build/bin/llama-cli --help | head
如果编译阶段找不到 CUDA,通常是 nvcc 或 CUDA 头文件路径问题。先确认:
which nvcc
nvcc --version
echo "$CUDA_HOME"
有些环境需要显式指定 CUDA 编译器,例如:
cmake -B build \
-DGGML_CUDA=ON \
-DCMAKE_CUDA_COMPILER=/usr/bin/nvcc \
-DCMAKE_BUILD_TYPE=Release
5. 先用命令行跑通一次
不要一上来就起服务。先用 llama-cli 跑一个短 prompt,确认模型、CUDA、显存三件事都正常。
cd ~/src/llama.cpp
MODEL=/data/models/gguf/Qwen3.6-35B-A3B-Q4_K_M.gguf
./build/bin/llama-cli \
-m "$MODEL" \
-ngl 99 \
-c 8192 \
-p "请用三句话解释一下,为什么 24GB 显存适合跑 30B 级 4bit 量化模型。"
同时另开一个终端观察:
watch -n 1 nvidia-smi
这里的几个参数含义:
| 参数 | 作用 |
|---|---|
-m | 指定 GGUF 模型文件 |
-ngl 99 | 尽量把模型层 offload 到 GPU |
-c 8192 | 上下文长度先设为 8K,避免一开始就被 KV cache 打爆 |
-p | 测试 prompt |
如果报显存不足,先不要怀疑驱动。优先把上下文降下来:
./build/bin/llama-cli \
-m "$MODEL" \
-ngl 99 \
-c 4096 \
-p "你好,请做一个简单自我介绍。"
如果还是 OOM,再换更小的量化文件。
6. 启动 OpenAI-compatible API
命令行跑通后,再启动 llama-server:
cd ~/src/llama.cpp
MODEL=/data/models/gguf/Qwen3.6-35B-A3B-Q4_K_M.gguf
./build/bin/llama-server \
-m "$MODEL" \
-ngl 99 \
-c 8192 \
--host 0.0.0.0 \
--port 8000
本机测试:
curl http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local-qwen",
"messages": [
{
"role": "user",
"content": "用三点说明本地部署大模型相比云端 API 的优缺点。"
}
],
"temperature": 0.7,
"stream": false
}'
流式输出也要测:
curl http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local-qwen",
"messages": [
{
"role": "user",
"content": "写一段 200 字左右的中文技术博客开头,主题是本地大模型部署。"
}
],
"temperature": 0.7,
"stream": true
}'
如果要给局域网其他机器访问,确认防火墙:
sudo ufw status
sudo ufw allow 8000/tcp
如果只是本机用,就不要开放端口,把 --host 改成 127.0.0.1 更安全。
7. 用 systemd 托管服务
长期使用不要手工开终端挂着。新建一个专用目录放启动脚本:
mkdir -p ~/bin
vim ~/bin/start-local-llm.sh
写入:
#!/usr/bin/env bash
set -euo pipefail
cd "$HOME/src/llama.cpp"
MODEL="/data/models/gguf/Qwen3.6-35B-A3B-Q4_K_M.gguf"
exec "$HOME/src/llama.cpp/build/bin/llama-server" \
-m "$MODEL" \
-ngl 99 \
-c 8192 \
--host 0.0.0.0 \
--port 8000
加执行权限:
chmod +x ~/bin/start-local-llm.sh
创建 systemd user service:
mkdir -p ~/.config/systemd/user
vim ~/.config/systemd/user/local-llm.service
写入:
[Unit]
Description=Local LLM server via llama.cpp
After=network-online.target
[Service]
Type=simple
ExecStart=%h/bin/start-local-llm.sh
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
启用并启动:
systemctl --user daemon-reload
systemctl --user enable --now local-llm.service
systemctl --user status local-llm.service
如果希望用户退出 SSH 后服务仍然运行:
sudo loginctl enable-linger "$USER"
查看日志:
journalctl --user -u local-llm.service -f
8. 可选:用 Ollama 快速体验
如果只是想先聊天,不想编译 llama.cpp,Ollama 更省事:
curl -fsSL https://ollama.com/install.sh | sh
确认服务:
systemctl status ollama
ollama --version
如果 Ollama 官方库里已有目标模型,可以直接:
ollama pull qwen3.6:35b
ollama run qwen3.6:35b
如果官方库还没有,或者你想用自己下载的 GGUF,可以写一个 Modelfile:
mkdir -p ~/ollama-models/qwen36
cd ~/ollama-models/qwen36
cp /data/models/gguf/Qwen3.6-35B-A3B-Q4_K_M.gguf .
cat > Modelfile <<'EOF'
FROM ./Qwen3.6-35B-A3B-Q4_K_M.gguf
PARAMETER num_ctx 8192
PARAMETER temperature 0.7
EOF
ollama create qwen36-35b-q4 -f Modelfile
ollama run qwen36-35b-q4
Ollama 的 API 默认在 11434:
curl http://127.0.0.1:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
"model": "qwen36-35b-q4",
"messages": [
{"role": "user", "content": "写一个 Python 脚本,读取目录下所有 Markdown 文件并统计字数。"}
],
"stream": false
}'
我个人会把 Ollama 当作快速体验路径,把 llama.cpp server 当作更可控的服务路径。
9. 固定测试问题集
只问“你好”没有意义。每次换模型、换量化、换上下文长度,都应该用同一组问题做对比。
中文写作
请把下面这段说明改写成适合技术博客读者阅读的中文,不要改变技术含义:
我们在 Ubuntu 26.04 LTS 上使用 RTX 4090 部署本地大模型。模型采用 4bit GGUF 量化,推理服务通过 llama.cpp 暴露 OpenAI-compatible API。
观察它是否自然、是否废话多、是否偷换含义。
代码理解
请阅读下面这段 Python 代码,指出潜在问题,并给出最小修改建议:
import requests
def fetch_all(urls):
result = []
for url in urls:
r = requests.get(url)
result.append(r.json())
return result
好的回答应该能提到超时、异常处理、状态码、串行请求性能等问题。
运维排障
有一个本地 LLM API 服务,平均响应很快,但偶发 60 秒超时。机器是单张 RTX 4090,Ubuntu 26.04 LTS。请列出排查步骤。
我会看它是否能想到显存碎片、上下文长度、并发排队、CPU 采样瓶颈、磁盘换页、反向代理超时、客户端重试等问题。
代码生成
写一个 Bash 脚本,每 5 秒记录一次 nvidia-smi 的显存占用和 GPU 利用率,输出到 CSV 文件。
这个问题能快速看出模型写脚本的可靠性。
10. 记录性能数据
建议建一个简单表格,每次测试都填进去:
| 日期 | 模型 | 量化 | 上下文 | 框架 | 显存峰值 | 输出速度 | 结论 |
|---|---|---|---|---|---|---|---|
| 待补 | Qwen3.6-35B-A3B | Q4_K_M | 8K | llama.cpp | 待补 | 待补 | 待补 |
| 待补 | Qwen3.6-35B-A3B | Q4_K_M | 16K | llama.cpp | 待补 | 待补 | 待补 |
| 待补 | Qwen3-Coder-30B-A3B | Q4_K_M | 8K | llama.cpp | 待补 | 待补 | 待补 |
显存可以用:
nvidia-smi --query-gpu=timestamp,name,memory.used,memory.total,utilization.gpu,power.draw,temperature.gpu \
--format=csv \
-l 5 \
| tee gpu-llm-test.csv
如果要记录接口耗时,可以先用简单脚本:
cat > test_chat_latency.py <<'PY'
import json
import time
import urllib.request
url = "http://127.0.0.1:8000/v1/chat/completions"
payload = {
"model": "local-qwen",
"messages": [
{"role": "user", "content": "请用 300 字说明本地大模型部署的关键注意事项。"}
],
"temperature": 0.7,
"stream": False,
}
data = json.dumps(payload).encode("utf-8")
req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"})
start = time.perf_counter()
with urllib.request.urlopen(req, timeout=300) as resp:
body = resp.read().decode("utf-8")
elapsed = time.perf_counter() - start
print(f"elapsed={elapsed:.2f}s")
print(body[:1000])
PY
python3 test_chat_latency.py
后续我会把这部分改成更完整的批量测试脚本。
11. 常见问题
nvidia-smi 正常,但 llama.cpp 没用 GPU
先看启动日志里有没有 CUDA backend。再确认编译时确实带了:
cmake -B build -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j"$(nproc)"
如果用的是系统里另一个旧版本 llama-server,也可能出现“你以为自己跑了 CUDA 版,实际跑的是 CPU 版”的情况。用绝对路径启动最稳。
模型能启动,但一问就 OOM
优先降上下文:
-c 4096
再考虑换更小量化。模型权重只是显存的一部分,KV cache 会随着上下文长度和并发继续吃显存。24GB 显存不要一上来追 64K、128K。
下载模型很慢
先用 huggingface-cli download,不要浏览器手工下。国内网络可以临时使用:
export HF_ENDPOINT=https://hf-mirror.com
如果公司或内网有代理,也可以设置:
export HTTPS_PROXY=http://127.0.0.1:7890
export HTTP_PROXY=http://127.0.0.1:7890
服务给别人访问时不安全
llama-server 直接暴露在公网并不合适。至少要放在内网,或者前面加 Nginx、鉴权和 HTTPS。最简单的内网反代示例:
server {
listen 80;
server_name local-llm.internal;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_read_timeout 300s;
}
}
如果只是自己用,SSH 端口转发更干净:
ssh -L 8000:127.0.0.1:8000 user@your-server
然后本机访问 http://127.0.0.1:8000。
12. 后续要补的实测结果
接下来我会按下面顺序补数据:
- Ubuntu 26.04 LTS 实机上的驱动版本、CUDA 版本。
-
Qwen3.6-35B-A3B Q4_K_M在 8K / 16K 上下文下的显存占用。 -
llama.cpp server的 tokens/s、首 token 延迟。 - Ollama 同模型体验对比。
-
Qwen3-Coder-30B-A3B-Instruct代码任务测试结果。 - 是否需要切到 SGLang 或 vLLM 做服务化。
先把教程写到这里。下一步真正上机时,我会把命令输出、错误处理和最终推荐参数继续补进来。