V100 32GB · llama.cpp · Qwen3.6

Qwen3.6 27B
推理优化报告

从虚拟机内的 Ollama 迁移到原生 llama.cpp server,在只保留一档 GPU 大模型的约束下,完成 MTP、批处理、上下文、模型常驻和工作负载预热的系统调优。

31%
长提示词预填充提升
47.0 t/s
预热后首个真实任务
69%
首请求等待时间下降
11.0 GiB
V100 剩余显存余量

Executive summary

不是换一个容器,而是重做推理路径

优化目标不是追求单次跑分峰值,而是在 V100 32GB 上建立一个资源可预期、 模型不反复换入换出、真实请求首轮不承担编译成本的 27B 长期服务。

01

框架换代

Ollama 迁移为固定版本 llama.cpp server,显式控制 GPU 层、KV、MTP 和批处理。

02

单实例常驻

V100 只加载一份 27B。Terra 与 Sol 是同一物理模型的两种推理策略。

03

延迟分层治理

生成用 MTP,长输入用 ubatch,首请求用健康门控预热,各自解决不同瓶颈。

04

链路统一

New API 统一暴露三档模型,OpenWebUI、Agent 与 Lab 使用同一组模型身份。

Performance trajectory

从基线到生产,三条速度曲线同步向上

不同阶段解决不同瓶颈,因此采用相对性能指数展示趋势:每项优化前均设为 100,生产值保留真实单位。折线斜率表示提升幅度,不混淆不同工作负载。

Relative performance index

基线 = 100

higher is better
27B 推理三项速度指标从基线到生产配置的提升趋势 稳态生成从指数 100 提升到 114,长提示词预填充提升到 131,首任务吞吐提升到 136。 114 131 136

稳态生成 · MTP

34.0 38.7 t/s 同一固定提示词,开启 n=2 MTP
+13.6%

长提示词 · ubatch

465 608 t/s 22,022-token、无缓存预填充
+31%

首任务吞吐 · 预热

34.5 47.0 t/s 同一解释任务的首次生产请求
+36%

Architecture

从动态 runner,收敛为可预测的两层服务

原方案把虚拟机、Ollama 调度和模型生命周期叠在一起。新方案把物理推理后端与 对外模型身份拆开,避免上下文差异触发额外 runner。

Before

VM + Ollama

业务请求
Ubuntu 24 VM
Ollama 动态 runner
V100 32GB
  • 不同 num_ctx 可能创建新的 runner
  • 模型换入换出会清空原有常驻状态
  • 虚拟机额外占用内存、磁盘与维护面
After

llama.cpp + New API

OpenWebUI
Agent
Lab
New API
模型身份与策略
V100 · 27B Terra / Sol
AMD 780M · 0.6B Luna / auto
  • GPU 只常驻一份 27B 权重
  • 32K 上下文与推理参数在服务端固定
  • 三档模型卡保持稳定,对业务透明

Optimization stack

五层优化,各自对应一个瓶颈

生成、预填充、冷启动和服务治理不是同一个问题。把它们拆开,才能知道每个参数究竟改善了什么。

  1. 1

    运行框架

    llama.cpp CUDA server 固定为 b9445,直接提供 OpenAI 兼容接口。

    可控
  2. 2

    模型驻留

    Q4_K_M 主模型与 Q8 MTP draft 同卡常驻,不允许请求改变上下文形状。

    稳定
  3. 3

    逐 token 生成

    MTP 先预测、主模型批量验证;最终选择 n-max=2,而不是盲目扩大草稿。

    +13.6%
  4. 4

    长提示词预填充

    ubatch 从 256 调到 512,让 V100 在 prompt processing 阶段吃到更大的物理批次。

    +31%
  5. 5

    首请求

    健康检查执行真实 128/384-token 推理,CUDA 与 MTP 图热好后才开放流量。

    -69%

Benchmark lab

参数不是越大越快

固定 seed、固定提示词、每类任务重复三次,同时记录服务端 timings、MTP 接受率和输出哈希。以下数据均来自实际 V100 运行。

Median generation throughput

MTP draft n-max 对比

tokens/s
n = 2
45.1
n = 3
41.8
n = 4
42.4
n = 6
33.5

Technical deep dive

三个最容易被误解的技术点

MTP

它减少的是主模型串行前向次数

MTP draft 先给出未来 token 候选,27B 主模型在一个批次内验证多个候选。 只有接受率足够高时,少做的串行前向才大于草稿生成和验证成本。

T0 T1? T2? verify T1 T2
ubatch

它主要加速 prompt processing

ubatch 是一次物理计算可处理的 token 数。更大的 ubatch 能提高长提示词并行度, 但也改变显存和 kernel 行为;它并不天然提升逐 token 解码。

Warmup

预热应覆盖真实计算图形状

只检查 `/health` 会把 CUDA graph 编译成本留给第一个用户。预热提示词还要制造 真实的 MTP 接受和拒绝,否则只热到“容易预测”的分支。

load128384healthy

Production profile

最终生产参数

参数围绕单用户、固定 32K 上下文和资源可预测性设计。Terra 关闭思考,Sol 开启思考,但二者共享同一个物理 runner。

--ctx-size 32768
--parallel 1
--gpu-layers all
--device CUDA0
--cache-type-k q8_0
--cache-type-v q8_0
--batch-size 1024
--ubatch-size 512
--flash-attn auto
--spec-type draft-mtp
--spec-draft-n-max 2
--spec-draft-type-k q4_0
--spec-draft-type-v q4_0
主模型
Qwen3.6 27B · Q4_K_M
MTP draft
Qwen3.6 27B · Q8_0 · 3.16GB
生产显存
约 20.7 GiB,剩余约 11.0 GiB
上下文
32,768 tokens · 单并发槽
服务身份
Terra 无思考 / Sol 有思考
就绪条件
模型加载 + 两阶段真实推理预热

End-to-end validation

优化最终落在完整业务链路上

公网请求经过 Cloudflare、New API 和 llama.cpp,而不是绕开网关直接测本机端口。

Luna0.77–0.87s
Terra1.03–1.28s
Sol7.17s · reasoning + answer
chat.k1412.top 200 agent.k1412.top 200 lab.k1412.top 200 api.k1412.top 200

Conclusion

甜点不是某个参数,而是一组相互约束的选择

最终方案没有采用单项跑分最高的 ubatch 1024,也没有采用更激进的 MTP 深度。 它选择的是 n=2、ubatch 512、固定 32K 和工作负载预热:在保留模型质量与输出稳定性的同时, 让长输入、首请求和服务生命周期都变得可预测。这才是这张 V100 上可长期使用的 27B 推理档位。