3080+WSL2 + llama.cpp 部署 Qwen3.8-27B-Coder

27B 的 Coder 模型塞进 20GB 显存是什么体验?Q3 量化 + KV cache 8bit + Flash Attention 三件套下来,64K 上下文只吃 15.7GB,netsh 端口转发一配,局域网里另一台主机的 WorkBuddy 直接把它当 OpenAI API 用。

WSL2 + llama.cpp 部署 Qwen3.8-27B-Coder:RTX 3080 20GB 实战 OpenAI 兼容 API

环境:Windows + WSL2 (Ubuntu 26.04) · NVIDIA RTX 3080 20GB · llama.cpp(CUDA 构建)· Qwen3.8-27B-Coder390 Q3LynnStyle16G(13.28GB GGUF)
生成日期:2026-10-26


一、环境概览与关键路径

整套方案的目标很明确:WSL2 里跑推理,对外提供 OpenAI 兼容 API,给局域网内另一台主机上的 WorkBuddy 当模型后端。先看总的环境:

环境概览

涉及的几个关键路径,后面所有命令都围绕它们展开:

关键路径

二、模型下载:绕过 XetHub 认证坑

模型从 HuggingFace 镜像站(hf-mirror.com)直接下载——注意这里的坑:huggingface_hub 默认走的 XetHub CAS 后端,镜像站不支持 Xet 认证,所以直接用 wget 打镜像的 resolve 链接最稳。下载脚本如下:

#!/usr/bin/env bash
# 从 hf-mirror.com 直接下载 Qwen3.8-27B-Coder390 的 Q3LynnStyle GGUF 文件
# 绕过 huggingface_hub 的 XetHub CAS 后端(镜像不支持 Xet 认证)
set -uo pipefail

REPO="nerkyor/Qwen3.8-27B-Coder390-EfficientThink-Opus5.5-GPT6Astra-Grok4.7-DSV4Pro-K3-SFT-RLOO-MTP-DFlash2"
BASE="https://hf-mirror.com/${REPO}/resolve/main/GGUF"
DIR=/home/antares/models/qwen38-27b/GGUF
mkdir -p "$DIR"

files=(
  "Qwen3.8-27B-Coder390-EfficientThink-Q3LynnStyle-MTP.gguf"
  "Qwen3.8-27B-Coder390-EfficientThink-Q3LynnStyle-Q8MTP.gguf"
  "Qwen3.8-27B-Coder390-Q3LynnStyle16G-MTP.gguf"
)

for f in "${files[@]}"; do
    echo "[$(date +%H:%M:%S)] === 下载 $f ==="
    if wget -c --progress=dot:giga -O "$DIR/$f" "$BASE/$f"; then
        echo "[$(date +%H:%M:%S)] OK  $f"
    else
        echo "[$(date +%H:%M:%S)] FAIL $f (exit $?)"
    fi
done
echo "[$(date +%H:%M:%S)] 全部任务结束,结果:"

执行就是一行:

bash ~/models/downloadQwen38Coder.sh

注:脚本里用的是 wget -c,断点续传自动生效——13GB 级别的文件下载中断了直接重跑即可,已下载的部分不会浪费。


三、启动服务

3.1 一键启动命令

nohup ~/llama.cpp/build/bin/llama-server \
  -m ~/models/qwen38-27b/GGUF/Qwen3.8-27B-Coder390-Q3LynnStyle16G-MTP.gguf \
  -ngl 99 \
  -c 65536 \
  --parallel 1 \
  --flash-attn on \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --host 0.0.0.0 \
  --port 8000 \
  --alias qwen3.8-27b-coder \
  > ~/llamaServer.log 2>&1 &

3.2 参数逐条解读

这套参数组合是 20GB 显存跑 27B Q3 的核心,逐条说清楚:

启动参数说明

其中 --cache-type-k/v q8_0 和 --flash-attn on 是显存优化的关键二件套:KV cache 8bit 量化直接把 KV 显存砍半,Flash Attention 再省一层——两者叠加后 64K 上下文总占用控制在 15.7GB。而 --parallel 1 是个容易忽略的点:多 slot 会均分上下文窗口,单请求可用 token 直接腰斩,独占模式才能吃满 64K。

3.3 启动后验证四连

# 检查进程
pgrep -af llama-server

# 检查 API
curl -s http://localhost:8000/v1/models | python3 -m json.tool

# 推理测试
curl -s http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen3.8-27b-coder","messages":[{"role":"user","content":"你好"}],"max_tokens":50}'

# 检查显存
nvidia-smi --query-gpu=memory.used,memory.free --format=csv,noheader

正常运行时显存占用约 15.7GB / 20GB,留有余量。


四、网络配置:WSL2 端口转发

WSL2 默认不对外暴露端口,LAN 里其他机器是连不进来的,需要在 Windows 宿主机上做一层端口转发。

4.1 查询 WSL2 IP

# 在 WSL2 内执行
hostname -I | awk '{print $1}'
# 示例输出:172.27.7.50

4.2 配置端口转发与防火墙

# PowerShell 管理员运行
netsh interface portproxy add v4tov4 listenport=8000 listenaddress=0.0.0.0 connectport=8000 connectaddress=172.27.7.50
netsh advfirewall firewall add rule name="llama-server" dir=in action=allow protocol=TCP localport=8000

4.3 查询 Windows 宿主机局域网 IP

# PowerShell 运行
Get-NetIPAddress -AddressFamily IPv4 |
  Where-Object {$_.InterfaceAlias -notlike "*WSL*" -and $_.IPAddress -notlike "127.*" -and $_.IPAddress -notlike "169.254.*" -and $_.IPAddress -notlike "172.*"} |
  Select-Object IPAddress, InterfaceAlias
# 示例输出:10.10.10.216

注:WSL2 每次重启后 IP 可能变化,connectaddress 就会失效。图省事可以写个开机脚本自动查询并更新转发规则,一劳永逸。

4.4 更新端口转发(WSL2 IP 变化时)

# 先删除旧规则再添加
netsh interface portproxy delete v4tov4 listenport=8000 listenaddress=0.0.0.0
netsh interface portproxy add v4tov4 listenport=8000 listenaddress=0.0.0.0 connectport=8000 connectaddress=<新的WSL2_IP>

五、WorkBuddy 客户端接入

在局域网另一台主机的 WorkBuddy 里按下面的参数配置 OpenAI API 连接:

WorkBuddy 客户端配置

注:把 10.10.10.216 换成你自己的 Windows 宿主机实际局域网 IP;API Key 随便填,llama-server 默认不校验。


六、日常运维

6.1 停止 / 重启服务

# 停止
pkill -f "llama-server"

# 重启:杀掉后 sleep 3 再拉起
pkill -f "llama-server"; sleep 3
nohup ~/llama.cpp/build/bin/llama-server \
  -m ~/models/qwen38-27b/GGUF/Qwen3.8-27B-Coder390-Q3LynnStyle16G-MTP.gguf \
  -ngl 99 -c 65536 --parallel 1 --flash-attn on \
  --cache-type-k q8_0 --cache-type-v q8_0 \
  --host 0.0.0.0 --port 8000 --alias qwen3.8-27b-coder \
  > ~/llamaServer.log 2>&1 &

实际操作中把重启命令存成一键脚本最省心。

6.2 日志与状态

# 实时日志
tail -f ~/llamaServer.log

# 进程
pgrep -af llama-server

# 显存
nvidia-smi --query-gpu=memory.used,memory.free --format=csv,noheader

# API 可用性
curl -s http://localhost:8000/v1/models | head -5

七、故障排查手册

7.1 request exceeds the available context size

原因:请求 token 数超过上下文窗口。解决:增大 -c 并确保 --parallel 1。当前 64K 已够用,再往上加要盯着显存:

上下文与显存对照

7.2 端口被占用 / 重启失败

原因:旧进程未完全释放端口。解决:强杀后确认端口空闲再拉起:

pkill -9 -f "llama-server"
sleep 5
# 确认端口空闲后再启动
ss -tlnp | grep :8000

7.3 另一台主机无法连接

按下面五步逐层排查,从内到外:

  • ✓ WSL2 内服务正常:curl http://localhost:8000/v1/models
  • ✓ Windows 端口转发存在:netsh interface portproxy show v4tov4
  • ✓ WSL2 IP 未变化:hostname -I 与 connectaddress 比对
  • ✓ Windows 防火墙规则存在:netsh advfirewall firewall show rule name="llama-server"
  • ✓ Windows 局域网 IP 正确:从另一台主机 ping 10.10.10.216

7.4 显存 OOM

解决:降低上下文 -c,或换更小的量化。~/models/qwen38-27b/GGUF/ 下的三个量化文件按显存量力而行:

可选模型文件对比

注:20GB 显存无脑选 Q3LynnStyle16G(13.28GB),是实测最稳的一档;Q8 精度更高但 17.52GB 装不下 64K 上下文,除非你显存 24GB 往上。

Antares

>_