框架换代
Ollama 迁移为固定版本 llama.cpp server,显式控制 GPU 层、KV、MTP 和批处理。
V100 32GB · llama.cpp · Qwen3.6
从虚拟机内的 Ollama 迁移到原生 llama.cpp server,在只保留一档 GPU 大模型的约束下,完成 MTP、批处理、上下文、模型常驻和工作负载预热的系统调优。
Executive summary
优化目标不是追求单次跑分峰值,而是在 V100 32GB 上建立一个资源可预期、 模型不反复换入换出、真实请求首轮不承担编译成本的 27B 长期服务。
Ollama 迁移为固定版本 llama.cpp server,显式控制 GPU 层、KV、MTP 和批处理。
V100 只加载一份 27B。Terra 与 Sol 是同一物理模型的两种推理策略。
生成用 MTP,长输入用 ubatch,首请求用健康门控预热,各自解决不同瓶颈。
New API 统一暴露三档模型,OpenWebUI、Agent 与 Lab 使用同一组模型身份。
Performance trajectory
不同阶段解决不同瓶颈,因此采用相对性能指数展示趋势:每项优化前均设为 100,生产值保留真实单位。折线斜率表示提升幅度,不混淆不同工作负载。
稳态生成 · MTP
34.0 → 38.7 t/s 同一固定提示词,开启 n=2 MTP长提示词 · ubatch
465 → 608 t/s 22,022-token、无缓存预填充首任务吞吐 · 预热
34.5 → 47.0 t/s 同一解释任务的首次生产请求Architecture
原方案把虚拟机、Ollama 调度和模型生命周期叠在一起。新方案把物理推理后端与 对外模型身份拆开,避免上下文差异触发额外 runner。
Optimization stack
生成、预填充、冷启动和服务治理不是同一个问题。把它们拆开,才能知道每个参数究竟改善了什么。
llama.cpp CUDA server 固定为 b9445,直接提供 OpenAI 兼容接口。
Q4_K_M 主模型与 Q8 MTP draft 同卡常驻,不允许请求改变上下文形状。
MTP 先预测、主模型批量验证;最终选择 n-max=2,而不是盲目扩大草稿。
ubatch 从 256 调到 512,让 V100 在 prompt processing 阶段吃到更大的物理批次。
健康检查执行真实 128/384-token 推理,CUDA 与 MTP 图热好后才开放流量。
Benchmark lab
固定 seed、固定提示词、每类任务重复三次,同时记录服务端 timings、MTP 接受率和输出哈希。以下数据均来自实际 V100 运行。
Technical deep dive
MTP draft 先给出未来 token 候选,27B 主模型在一个批次内验证多个候选。 只有接受率足够高时,少做的串行前向才大于草稿生成和验证成本。
ubatch 是一次物理计算可处理的 token 数。更大的 ubatch 能提高长提示词并行度, 但也改变显存和 kernel 行为;它并不天然提升逐 token 解码。
只检查 `/health` 会把 CUDA graph 编译成本留给第一个用户。预热提示词还要制造 真实的 MTP 接受和拒绝,否则只热到“容易预测”的分支。
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
End-to-end validation
公网请求经过 Cloudflare、New API 和 llama.cpp,而不是绕开网关直接测本机端口。
Conclusion
最终方案没有采用单项跑分最高的 ubatch 1024,也没有采用更激进的 MTP 深度。 它选择的是 n=2、ubatch 512、固定 32K 和工作负载预热:在保留模型质量与输出稳定性的同时, 让长输入、首请求和服务生命周期都变得可预测。这才是这张 V100 上可长期使用的 27B 推理档位。