Qwen3.8-27B 本地推理 + DeepSeek Harness 配置

本文档记录本机硬件环境、Qwen3.8-27B 模型的安装与推理服务部署,以及在 DeepSeek Harness(dsh)中的接入配置。支持文本 + 图片(多模态)

1. 本机硬件环境

组件 配置
CPU Intel Xeon W-2150B @ 3.00GHz(10 核 20 线程)
内存 251 GiB
GPU 2 × NVIDIA GeForce RTX 2080 Ti(每卡 22 GiB,共 44 GiB)
驱动 / CUDA NVIDIA Driver 595.84 / CUDA 13.2
操作系统 Ubuntu 24.04.4 LTS(x86_64)

注意:RTX 2080 Ti 是 Turing 架构(SM 75),llama.cpp 编译时需确认 CUDA backend 已启用(见下文编译说明)。

2. 模型文件

Qwen3.8-27B 是支持多模态(图文)的 27B 参数模型,本机使用 GGUF 量化格式,Q8_0 量化。

文件 大小 用途
Qwen3.8-27B-Q8_0.gguf 27G 主模型权重(Q8_0)
mmproj-Qwen3.8-27B-BF16.gguf 889M 视觉投影器(vision encoder,BF16 未量化)
mtp-Qwen3.8-27B-Q8_0.gguf 3.0G 多 token 预测(MTP)权重
Qwen3.8-27B-DFlash2-Q4_K_M.gguf 1.1G DFlash2 投机解码 drafter(draft 小模型,来源 incoai/Qwen3.8-27B-DFlash2-GGUF

3. 编译 llama.cpp

推理服务基于 llama.cpp

bash 复制代码
cd ~/llama.cpp-upstream
cmake -B build -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=75
cmake --build build -j --config Release
# 产物:build/bin/llama-server

关键点:

  • GGML_CUDA=ON 必须开启,否则模型掉回 CPU(日志会出现 failed to initialize CUDA: no CUDA-capable device is detected)。
  • 2080 Ti 的 CUDA 架构码是 75CMAKE_CUDA_ARCHITECTURES=75 能让编译针对本卡优化。不指定也能编译,但会用默认架构列表。

当前实际使用的二进制不是这个 :因为 DFlash2 投机解码需要未合并的 PR #27342,服务现在指向 ~/llama.cpp-dflash2/build/bin/llama-server(见第 8 章)。上面只是基础编译方法;如需 DFlash2 请按第 8.2 节构建。

4. 部署推理服务(systemd 用户服务)

用 systemd 用户服务托管 llama-server,开机/登录自启、崩溃自动拉起。

4.1 服务文件

~/.config/systemd/user/qwen38-27b-q8.service

ini 复制代码
[Unit]
Description=llama.cpp server - Qwen3.8-27B Q8_0 (dual-GPU hybrid attention)
After=network.target

[Service]
Type=simple
ExecStart=/home/XXXXX/llama.cpp-dflash2/build/bin/llama-server \
    --model /home/XXXXX/models/Qwen3.8-27B-GGUF/Qwen3.8-27B-Q8_0.gguf \
    --mmproj /home/XXXXX/models/Qwen3.8-27B-GGUF/mmproj-Qwen3.8-27B-BF16.gguf \
    --alias qwen3.8-27b-q8 \
    --host 127.0.0.1 \
    --port 8097 \
    --ctx-size 131072 \
    --n-gpu-layers 99 \
    --split-mode layer \
    --jinja \
    --flash-attn on \
    --cache-type-k q8_0 \
    --cache-type-v q8_0 \
    --spec-type draft-dflash \
    --spec-draft-model /home/XXXXX/models/Qwen3.8-27B-GGUF/Qwen3.8-27B-DFlash2-Q4_K_M.gguf \
    --spec-draft-ngl 99 \
    --spec-draft-n-max 5 \
    --no-webui
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target

4.2 参数说明

参数 含义
--model 主模型权重路径
--mmproj 视觉投影器路径,加载它才支持图片输入
--alias 模型别名,/v1/models 里返回的名字
--ctx-size 131072 上下文窗口 128K
--n-gpu-layers 99 把 99 层全部卸载到 GPU
--split-mode layer 按层拆分到双卡(layer 模式)
--flash-attn on 开启 Flash Attention
--cache-type-k/v q8_0 KV cache 量化,节省显存以容纳 128K 上下文
--spec-type draft-dflash 开启 DFlash2 投机解码(draft 小模型先猜,大模型后验)
--spec-draft-model DFlash2 drafter 权重路径
--spec-draft-ngl 99 drafter 全部卸载到 GPU
--spec-draft-n-max 5 drafter 每次猜测的 token 上限(编程场景最优值,见第 9 章)
--no-webui 关闭内置 Web UI,仅开 API

4.3 启用并启动

bash 复制代码
systemctl --user daemon-reload
systemctl --user enable --now qwen38-27b-q8.service
systemctl --user status qwen38-27b-q8.service

4.4 验证

bash 复制代码
# 模型列表
curl -s http://127.0.0.1:8097/v1/models

# 文本推理
curl -s http://127.0.0.1:8097/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen3.8-27b-q8","messages":[{"role":"user","content":"用一句话解释递归"}]}'

# 图片推理(base64 图片)
curl -s http://127.0.0.1:8097/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model":"qwen3.8-27b-q8",
    "messages":[{"role":"user","content":[
      {"type":"text","text":"图里有哪些颜色?"},
      {"type":"image_url","image_url":{"url":"data:image/png;base64,<BASE64>"}}
    ]}]
  }'

5. 在 DeepSeek Harness 中配置

DeepSeek Harness(dsh)通过 llm-pi-ai 插件接入任意 OpenAI 兼容端点。配置写在 ~/.dsh/settings.yaml

5.1 settings.yaml 配置片段

yaml 复制代码
agent-default-model:
  provider: qwen38-local
  model: qwen3.8-27b-q8

llm-pi-ai:
  providers:
    qwen38-local:
      displayName: Qwen3.8-27B Local (llama.cpp Q8 dual-GPU)
      api: openai-completions
      baseURL: http://127.0.0.1:8097/v1
      headers:
        Authorization: Bearer local-noauth   # llama-server 无鉴权,占位值即可
      models:
        - id: qwen3.8-27b-q8
          name: Qwen3.8-27B Q8_K (128K ctx)
          contextWindow: 131072
          maxTokens: 8192
          input: [ text, image ]            # 关键:声明支持图片
      defaultInput:
        - text
        - image

5.2 关键点:图片支持怎么开启

Harness 的 llm-pi-ai 适配器在发请求前会检查 model.input 是否包含 image,不含就直接抛 UNSUPPORTED_CONTENT 拒绝图片。因此:

  • 模型条目必须写 input: [ text, image ]------这是让一个手写声明的视觉模型可用的唯一方式。
  • defaultInput: [ text, image ] 是 provider 级兜底,供未在 catalog 里的模型继承。
  • 两者都写上最稳妥(模型级 input 优先于 defaultInput)。

对比纯文本模型(如 Qwen2.5-Coder-32B)只需 input: [ text ] 或不写(默认 [text])。

5.3 重启生效

settings.yaml 修改后需重启 dsh:

bash 复制代码
# 停掉当前 dsh web
pkill -f "dsh web"
# 重新启动
cd ~ && nohup dsh web > /tmp/dsh-web.log 2>&1 &
# 或前台运行
dsh web

Web UI 地址:http://127.0.0.1:3080

6. 显存规划与多模型共存

两块 2080 Ti 合计 44 GiB。Qwen3.8-27B Q8_0 本体约 26 GiB,128K 上下文的 KV cache(q8_0 量化后)仍需额外数 GiB,合计约 34 GiB。

因此同时常驻多个大模型会显存不足,导致 offload 失败、掉回 CPU(表现为 CPU 占用高、推理超时)。本机最终方案:

  • 常驻 :仅 Qwen3.8-27B(qwen38-27b-q8.service,enabled)。
  • 停用 :GLM-4.6V-Flash(llama-server.service,8099)与 Qwen2.5-Coder-32B(qwen32b.service,8098),已 disable,需要时再手动 systemctl --user start

排查口诀:nvidia-smi --query-compute-apps=pid,used_memory --format=csv 看进程是否真的上了 GPU;若不在列表,查服务日志里是否出现 no usable GPU found

7. 已知问题与备注

  • 图片识别偏慢 :视觉投影器是 BF16 未量化,且 128K 上下文 KV cache 占用较多显存,图片请求整体比纯文本慢(实测约 9~10 秒返回)。若高频做视觉任务,可考虑降低 --ctx-size 释放显存,或接受现状。
  • 并发幽灵请求 :曾观测到外部客户端向 8097 发送超长 prompt(77K+ token)拖垮响应。若推理突然变慢,用 ss -tpn 定位连接来源。
  • Harness 侧另有 dsh-vision-tools 插件 (日志中注册了 vision_understand 工具、/api/vision-paste 路由)。这与「模型原生支持图片」是两套机制:本方案让 qwen3.8 模型自身吃图片;dsh-vision-tools 是另一条视觉增强旁路,二者可独立存在。

8. DFlash2 投机解码加速

本机已为 Qwen3.8-27B 启用 DFlash2 投机解码(speculative decoding),编程场景实测约 2.8× 加速。

8.1 原理

投机解码 = 「小模型先猜,大模型后验」:

  1. drafter (DFlash2,仅 1.1GB 的轻量 draft 模型)跑得快,一次并行预测 N 个候选 token
  2. 大模型 (27B Q8)一次 forward 验证这 N 个 token,保留连续的、正确的,丢弃第一个猜错之后的所有;
  3. 猜对 k 个,就相当于大模型只跑 1 次却产出 k 个 token → 加速。

关键 :投机解码不改变输出内容 ------最终 token 都由大模型验证过,与无投机时逐字一致,只是更快。且加速发生在 llama.cpp 服务端,对任何 OpenAI 兼容客户端(dsh、curl 等)完全透明,客户端无需任何配置。

8.2 为什么用独立构建

DFlash2 是 llama.cpp PR #27342 引入的(含 local-convolution + candidate-selector 两个新模块),尚未合并进上游 master 。master 自带的 draft-dflash 是 DFlash v1,读不了 81-tensor 的 DFlash2 drafter(会报 wrong number of tensors; expected 81, got 58)。

因此本机在独立 worktree 里构建:

bash 复制代码
git worktree add ~/llama.cpp-dflash2 pr-27342   # 基于 PR #27342
cd ~/llama.cpp-dflash2
cmake -B build -DGGML_CUDA=ON -DGGML_CUDA_FA=ON -DGGML_NATIVE=ON -DGGML_OPENMP=ON
cmake --build build --target llama-server -j
  • 产物:~/llama.cpp-dflash2/build/bin/llama-server(服务已指向它)
  • ~/llama.cpp-upstream(master)保持不动,上游合并后可切回重编译。

8.3 n_max 调优(实测数据)

--spec-draft-n-max(drafter 每次猜测的 token 上限)是核心性能旋钮,并非越大越好 :太小加速有限,太大则接受率下降、且 drafter 的 CUDA graph 显存暴涨(本卡 n_max=15 直接 failed to allocate compute buffers 溢出)。

任务 可预测性 最优 n_max 实测解码速度 vs 无投机
编程 / 结构化 高(代码语法固定,接受率 66--79%) 5 43 tok/s ≈2.8×
创意写作 / 散文 低(发散,接受率 ~33%) 3 22.7 tok/s ≈1.5×

无投机基线约 15.3 tok/s。本机当前 n_max=5(用户主要用编程)。

若高频做创意写作,可把 --spec-draft-n-max 从 5 降到 3,systemctl --user restart qwen38-27b-q8.service 生效。

8.4 验证投机解码确实在跑

请求 /v1/chat/completions,响应 timings 字段里有投机指标:

json 复制代码
"timings": {
  "predicted_per_second": 43.0,
  "draft_n": 295,          // drafter 共猜了多少 token
  "draft_n_accepted": 196  // 大模型接受了多少
}

draft_n / draft_n_accepted 存在即说明投机解码已激活;两者之比为接受率。

9. 快速参考

推理服务 llama-server127.0.0.1:8097
服务二进制 ~/llama.cpp-dflash2/build/bin/llama-server(DFlash2 分支)
投机解码 DFlash2(draft-dflash),drafter Qwen3.8-27B-DFlash2-Q4_K_M.ggufn_max=5
OpenAI 兼容端点 http://127.0.0.1:8097/v1
模型别名 qwen3.8-27b-q8
systemd 服务 qwen38-27b-q8.service(user 级)
Harness 配置 ~/.dsh/settings.yamlllm-pi-ai.providers.qwen38-local
Harness Web UI http://127.0.0.1:3080
dsh 版本 0.1.0-rc.7(Node v24.16.0)
相关推荐
Code额2 小时前
Python 连接 DeepSeek API,OpenAI 对话方式总结
后端·python·ai·ai编程
电化学仪器白超2 小时前
MV-CS200-10UC相机参数配置
python·单片机·嵌入式硬件·数码相机·自动化·ltspice
荣码2 小时前
向量数据库选型:4种方案全测了,选错重来成本最高
java·python
eagle_Annie2 小时前
Python/torch/深度学习——Miniforge+uv环境安装
python·深度学习·uv
OPEN-F2 小时前
Python进阶教程:Web开发入门(Flask)
开发语言·python
for_ever_love__2 小时前
python基础语法学习: 类型注解
开发语言·python·学习
王志来137944730083 小时前
聚焦五大核心场景:工控服务器机箱平台的垂直深耕之路
运维·服务器·python
zmzb01033 小时前
Python课后习题训练记录Day193
开发语言·python
卷无止境3 小时前
LiteLLM 全面解析开源AI网关如何统一管理百余种大模型
后端·python