RTX 4090 24GB + Ubuntu 26.04 LTS:本地大模型部署与测试教程
原创 · 约 38 分钟阅读 · 阅读 --
Last updated on

RTX 4090 24GB + Ubuntu 26.04 LTS:本地大模型部署与测试教程

作者: Alex Xiang


古董级程序员,大厂出来后一直在创业公司,现在还在一线写 AI 相关的后端。更完整的技术记录写在微信公众号「字与码」:踩过的坑、换技术栈时的权衡、和这些年绕过的弯路,会不定期发在那里。若这篇对你有用,欢迎顺手关注。

这篇是一个持续更新的本地大模型部署教程。目标机器已经定下来:Ubuntu 26.04 LTS,单张 RTX 4090 24GB。目标也很具体:不是跑一次 demo,而是在本地或者内网里长期提供一个能用的模型服务,支持命令行测试、OpenAI-compatible API,以及后续接入 Open WebUI、Continue、Cline 这类客户端。

先说明当前状态:本文已经把完整步骤写成可执行教程,后面实机跑完后,会继续补充真实显存占用、tokens/s、不同上下文长度下的稳定性,以及几个模型的效果对比。

一张正在台式机中运行的 RTX 4090 显卡实拍图
RTX 4090 实拍图。图片来源:Benlisquare / Wikimedia Commons,CC BY-SA 4.0;本文裁剪并压缩为站点配图。

这台机器适合跑什么模型

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_NLQ3_K_M 一类更小的量化;如果显存还有余量,再考虑更高量化质量。

参考入口:

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-A3BQ4_K_M8Kllama.cpp待补待补待补
待补Qwen3.6-35B-A3BQ4_K_M16Kllama.cpp待补待补待补
待补Qwen3-Coder-30B-A3BQ4_K_M8Kllama.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 做服务化。

先把教程写到这里。下一步真正上机时,我会把命令输出、错误处理和最终推荐参数继续补进来。