1. 启动命令
llama-server \
--device CUDA1,CUDA0 \
--model /path/to/Qwen3.8-27B-UD-Q4_K_M.gguf \
--mmproj /path/to/mmproj-BF16.gguf \
--cache-type-k q8_0 --cache-type-v q8_0 --fit off --flash-attn on \
--jinja --chat-template-file /path/to/chat_template.jinja \
--reasoning-format deepseek --reasoning-preserve --reasoning auto \
--spec-default --spec-type draft-mtp --spec-draft-n-max 2 \
--temp 1.0 --top-p 0.95 --top-k 20 --min-p 0.0 --presence-penalty 0.0 --repeat-penalty 1.0 \
--batch-size 2048 --ubatch-size 1024 -ngl 99 \
--split-mode tensor \
--ctx-checkpoints 32 \
--cache-ram 24576 --cache-idle-slots \
--parallel 2 --kv-unified \
--cache-prompt --cache-reuse 256 \
--metrics \
--ctx-size 163840 \
--host 0.0.0.0 --port 11707
2. 总体概览
| 项 | 值 | 说明 |
|---|---|---|
| 模型 | Qwen3.8-27B(unsloth UD Q4_K_M)+ mmproj BF16 | 多模态 VL 模型,全量 GPU 卸载(-ngl 99) |
| 硬件 | 2 × GPU(CUDA1 为主设备) | --split-mode tensor:按张量切分到两卡 |
| 并发 | --parallel 2 --kv-unified |
2 个 slot 共享一个统一 KV 池(unified KV) |
| KV 池 | --ctx-size 163840 |
整个池 160K token,两个 slot 共享,不是每 slot 160K |
–parallel 是slot数量。每个slot是服务器中的一个逻辑座位,一次处理一个请求,拥有独立的 KV 缓存区域、独立的解码状态。当省略 –parallel 时,llama-server 会根据上下文大小和模型默认值来确定slot数量;但实际使用中,这个自动值很少符合生产部署的需求,显式指定数值才是正确的运维做法。
–batch-size 是服务器在一次逻辑前向传播中拉入的最大提示词 token 数。它控制预填充阶段,即生成开始前消耗长提示词的阶段。对于 4,000 个 token 的提示词和 –batch-size 2048,预填充会分两次逻辑批次完成。
–ubatch-size 是 GPU 实际看到的物理批次。逻辑批次会按 ubatch-size 个 token 切分为微批次,每个微批次对应一次 Metal 内核调度。在 Apple Silicon 上,这个参数通常是影响预填充吞吐量的关键,因为更大的微批次可以分摊内核启动开销,并更高效地利用矩阵乘单元。约束条件是 ubatch-size 必须能整除 batch-size。
–ctx-size是一个预算,而非每次请求的保证。该预算如何分配取决于槽位数量和–kv-unified设置,这两种情况会产生截然不同的故障模式。
Case 1: 显式slot数量,静态分区。当显式设置–parallel N且使用–no-kv-unified(或早期未默认启用统一KV的构建版本)时,–ctx-size M会为每个槽位分配M / N个令牌。因此,–ctx-size 32768搭配–parallel 8,每个请求的有效上下文只有4,096个令牌。如果你的智能体系统提示词有8,000个令牌,那么每个请求要么被截断,要么失败。
Case 2: 自动slot或开启–kv-unified,共享池。一个共享的KV缓冲区覆盖整个ctx-size,按请求到达时进行分配。异构请求长度能更灵活地适应,因为短请求紧邻长请求时,会从池中借用资源,而不是浪费在隔离的插槽分配上,总预算仍为ctx-size只是不再预先切片。
3. KV / 缓存策略
3.1 统一 KV 池 + idle slot 换出
--kv-unified:所有 slot 共享同一 KV pool,空闲 cell 可被其他 slot 复用,池子利用率高于每 seq 独立池。--cache-ram 24576+--cache-idle-slots(二者必须配套,缺一则 idle 换出被禁用):- 新任务到来选中 idle slot 时,先把该 slot 的 per-seq KV state(target + MTP draft 两份) 拷贝进 24 GiB 的 RAM 缓存;
- unified 模式下随后
prompt_clear()真正释放共享池 cell → 池子腾空给新任务; - 同一 prompt(前缀匹配)回来时,从 RAM 缓存恢复 KV,跳过重算(LRU 淘汰,限额 24 GiB);
- 池子分配不下时还会
try_clear_idle_slots()强制 purge 一个 idle slot。
3.2 前缀复用
--cache-prompt:新任务与 slot 现有 prompt 的最长公共前缀直接续算,不重算。--cache-reuse 256:当前配置下实际不生效。加载了--mmproj的模型在启动时会被直接禁用(server 按"模型是否多模态"一刀切,与请求有没有传图无关)。纯文本流量 + cache-reuse",需另起一个不带--mmproj的实例,实现按照256最小块移动复用。
3.3 上下文检查点
--ctx-checkpoints 32(32 也是默认值):每 slot 最多 32 个 RAM 检查点,快照"不可回滚"的部分(SWA cache / recurrent state,PARTIAL_ONLY),公共前缀变短时可回滚到检查点而非全量重算。- 可配合
--checkpoint-min-step(默认 8192)控制快照密度。
3.4 KV 量化
--cache-type-k q8_0 --cache-type-v q8_0:K/V cache 用 Q8_0,显存约为 F16 的一半,精度损失很小;quantized V 要求 flash-attn。--fit off:关闭自动 fit(不做内存拟合估算,按给定参数硬分配)。
4. 推理加速
--flash-attn on:flash attention(tensor split 模式的硬性前提)。- 投机解码:
--spec-default --spec-type draft-mtp --spec-draft-n-max 2- 用模型自带的 MTP 层做 draft,每次最多投 2 个 token;
- draft 有独立 KV(ctx_dft),idle slot 换出时 target/draft 两份 state 一起存 RAM;
- spec 的 seq_id 与 slot id 相同(复用同一 seq 编号,只是内存模块不同)。
--batch-size 2048 --ubatch-size 1024:prefill 批 2048,微批 1024。
5. 对话 / 采样
--jinja --chat-template-file .../chat_template.jinja:用自定义 Jinja 模板。--reasoning-format deepseek --reasoning-preserve --reasoning auto:- deepseek 风格 reasoning 解析(thinking 与正文分离输出);
preserve:保留 thinking token 在上下文里(多轮思维连续);auto:默认 thinking 模式按模板/请求决定。
- 采样:
temp 1.0, top-p 0.95, top-k 20, min-p 0.0。