> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tokios.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Tokios exposes private local models through https://api.tokios.com using an outbound-only connector tunnel.
> Use 'connector' for the local tokios-connector process.
> Use 'deployment' for the public model name in the API model field.
> Use 'upstream model id' for the model served by Ollama, llama.cpp, vLLM, LM Studio, or another local backend.
> API keys use the prefix sk-tok-. Connector tokens use the prefix ct-tok-.

# 优化 llama.cpp 的速度和内存

> 针对 llama.cpp 进行性能调优 —— flash attention、mmap 与 mlock、线程调优、GPU 卸载策略、批处理大小、KV 缓存精度以及 MoE 专家层放置。

llama.cpp 是便携性最强的本地推理运行时。它可以在 CPU、NVIDIA GPU、AMD GPU 和 Apple Silicon 上运行 —— 通常使用同一个二进制文件。这种灵活性伴随着大量的命令行参数，而默认值并不总是最适合你的硬件。本指南介绍最重要的参数以及每个参数背后的权衡。

> [!NOTE]
>
> 最后验证：2026-10-14 —— llama.cpp build b11609。

> [!NOTE]
>
> 本指南中的所有参数适用于 `llama-server` 和 `llama-cli`（llama.cpp build **b11609**，十月 14 日，2026 年）。参数名称可能在不同 build 之间发生变化 —— 运行 `llama-server --help` 确认你的二进制文件支持哪些参数。

## Flash attention

使用 `-fa` 或 `--flash-attn on` 启用 flash attention。在大多数基准测试中，这是 llama.cpp 提供的最接近免费性能提升的选项 —— 你可以用相同或更少的内存获得更快的推理速度，质量损失几乎可以忽略不计。

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf -fa
```

Flash attention 改变了模型计算 token 之间注意力分数的方式。它不再将整个注意力矩阵加载到内存中，而是以适合快速 SRAM 的分块方式计算注意力。结果是：

* **更低的 KV 缓存内存占用** —— 在长上下文长度时收益最大。
* **更快的推理速度** —— 尤其在 GPU 上，分块计算可以很好地映射到 tensor core。
* **相同的输出质量** —— flash attention 在数学上等价于标准注意力，不是近似计算。

> [!TIP]
>
> **始终以 `-fa` 开头。** 除非遇到特定模型或平台的兼容性问题，否则没有理由不启用它。这是本指南中影响最大的单一参数。

## mmap 与 mlock

llama.cpp 使用 2 种策略将模型权重加载到内存中。默认策略是 `--mmap`，它将模型文件直接映射到进程的虚拟地址空间。另一种策略是 `--mlock`，它将整个模型锁定在物理内存中。

| 参数 | 作用 | 适用场景 |
| - | - | - |
| `--mmap`（默认） | 映射文件；操作系统按需分页调入调出数据 | 一次性运行、内存受限的机器、快速实验 |
| `--mlock` | 将所有数据锁定在物理内存中；不会被换出 | 重复推理、专用推理服务器、全天运行的模型 |

### mmap 的优势

`--mmap` 是默认选项，因为它适用于大多数交互式使用场景。操作系统按需加载模型页面，因此启动速度快，在实际访问页面之前模型文件不会重复占用内存。如果你在测试模型或运行短时会话，默认值就足够了。

### mlock 的优势

`--mlock` 阻止操作系统将模型页面换出到交换空间。这在以下情况下很重要：

* 你全天运行同一个模型并希望获得一致的延迟 —— 没有页面错误导致的冷启动惩罚。
* 你的系统受到其他进程的内存压力，可能会换出模型权重。
* 你使用的机器交换空间很慢（或没有交换空间），页面错误会导致推理停滞数秒。

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf -fa --mlock
```

> [!WARNING]
>
> `--mlock` 要求整个模型能放入可用的物理内存。如果放不下，进程将无法启动。启用前请在 Linux 上使用 `free -h` 或在 macOS 上使用活动监视器检查可用内存。

## 线程调优

参数 `-t` 设置用于推理的 CPU 线程数。正确的值取决于 CPU 实际承担的工作量。

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf -t 8
```

| 场景 | 线程建议 |
| - | - |
| 完全 GPU 卸载（所有层在 GPU 上） | `-t 2` 到 `-t 4` —— CPU 只处理编排和分词，不做计算 |
| 部分 GPU 卸载（部分层在 CPU 上） | 将 `-t` 设为 CPU 的物理核心数 —— 不是超线程数 |
| 纯 CPU（无 GPU） | 将 `-t` 设为物理核心数 |

> [!TIP]
>
> 线程越多并不总是越快。超过物理核心数后，线程会争抢缓存和内存带宽，反而会拖慢推理速度。不确定时，从物理核心数开始基准测试。

在 Apple Silicon 上，线程调优的重要性较低，因为 GPU 和 CPU 共享统一内存，Metal 后端会处理调度。默认值通常就能很好地工作。

## GPU 卸载策略

参数 `-ngl` 控制你将多少模型层卸载到 GPU。GPU 上的层越多，推理速度越快，但每层都会消耗显存。

### 部分卸载

将 `-ngl` 设为你能放入 GPU 内存的层数。剩余的层在 CPU 上运行。

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf -ngl 20 -fa
```

当整个模型无法放入显存时，使用部分卸载。从一个较高的值开始，逐步降低直到服务器启动且不内存溢出。

### 完全卸载

设置 `-ngl 999` 卸载每一层。llama.cpp 将 999 理解为"所有剩余层" —— 它并不会真的尝试卸载 999 层。

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf -ngl 999 -fa
```

完全卸载提供最佳的推理速度，因为每次前向传播都在 GPU 上运行。模型权重和 KV 缓存都必须放入显存。

### 每层内存预算

每个卸载的层同时为权重和 KV 缓存消耗显存。粗略估算：

```
VRAM per layer ≈ (parameter_count_per_layer × bytes_per_weight) + KV_cache_per_layer
```

对于 7B 模型使用 Q4\_K\_M（每权重约 4.5 位，约 40 层）：

| 组件 | 每层 | 40 层总计 |
| - | - | - |
| 权重 | \~0.15 GB | \~6 GB |
| KV 缓存（f16，4K 上下文） | \~0.05 GB | \~2 GB |
| **总计** | | **\~8 GB** |

预留 1-2 GB 显存余量用于 CUDA 上下文和开销。

## 批处理大小调优

两个参数控制 llama.cpp 在预填充阶段一次处理多少 token：

| 参数 | 控制内容 |
| - | - |
| `-b`（批处理大小） | 提示词摄入期间一个批次中处理的 token 总数 |
| `-ub`（微批处理大小） | 单个批次内每个微批次的最大 token 数 |

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf -b 512 -ub 512 -fa
```

### 两者的交互关系

* **`-b`** 设定外部上限。如果提示词的 token 数超过 `-b`，llama.cpp 会将其拆分为多个批次。
* **`-ub`** 设定内部分块大小。llama.cpp 以最多 `-ub` 个 token 的微批次处理该批次。
* `-ub` 必须小于或等于 `-b`。

### 权衡

| 设置 | 效果 |
| - | - |
| 较大的 `-b`（512-2048） | 长提示词的预填充更快 —— 每次前向传播处理更多 token |
| 较大的 `-b` | 提示词摄入期间消耗更多显存/内存 |
| 较小的 `-b`（128-256） | 更低的内存占用，更慢的预填充 |
| `-ub` 等于 `-b` | 最简单的配置；一个微批次覆盖整个批次 |
| `-ub` 小于 `-b` | 限制每个微批次的内存；当 `-b` 较大但显存紧张时有用 |

> [!TIP]
>
> 对于短提示词（1K token 以下）的交互式聊天，默认的 `-b 512` 就足够了。只有当你经常摄入长文档并希望更快的首 token 时间时才增大它。

## KV 缓存精度

KV 缓存存储每个活跃序列中每个 token 的键和值张量。默认情况下，llama.cpp 对键和值都使用 f16（16 位浮点数）。你可以切换到量化精度以较小的质量代价降低内存占用。

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf -fa \
  --cache-type-k q8_0 --cache-type-v q8_0
```

| 精度 | 每元素内存 | 质量 | 使用时机 |
| - | - | - | - |
| `f16`（默认） | 2 字节 | 基准 | 最高质量；内存充足时 |
| `q8_0` | 1 字节 | 与 f16 几乎相同 | 最佳平衡 —— KV 缓存内存减半，质量损失可忽略 |
| `q4_0` | 0.5 字节 | 略有下降 | 内存紧张；长上下文或多个并发序列 |

你可以独立设置键和值的精度。常见模式是两者都使用 `q8_0`，这在大多数基准测试中将 KV 缓存占用减半，质量差异不到 1%。

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
# Aggressive: quarter the KV cache memory
llama-server -m model.gguf -fa \
  --cache-type-k q4_0 --cache-type-v q4_0
```

> [!WARNING]
>
> `q4_0` KV 缓存在依赖长上下文精确注意力的任务中会带来可衡量的质量损失 —— 大海捞针检索、多文档摘要和长对话。在决定使用 `q4_0` 之前，请先针对你的具体工作负载进行测试。

## MoE 优化

混合专家模型（如 Qwen3.5-35B-A3B 或 Mixtral）在每一层存储大量专家子网络，但每个 token 只激活其中少数几个。专家权重即使不活跃也仍然驻留在内存中，这使得 MoE 模型相对于其活跃参数规模而言占用过大。

在多 GPU 系统上，当显存紧张时，你可以将专家层放在 CPU 上：

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf -ngl 999 --n-cpu-moe 4 -fa
```

`--n-cpu-moe <num>` 将指定数量的专家子层保留在 CPU 上，而模型的其余部分在 GPU 上运行。这是以增加少量延迟为代价来适配更大的模型。

| 场景 | 配置 |
| - | - |
| MoE 完全放入显存 | `-ngl 999` —— 不需要 CPU 专家层 |
| MoE 几乎放入，少量专家溢出 | `--n-cpu-moe 2` 到 `--n-cpu-moe 8` |
| MoE 对于任何合理的 GPU 配置都太大 | 结合使用 `--n-cpu-moe` 与部分 `-ngl` |

> [!TIP]
>
> 从 `--n-cpu-moe 0`（所有专家在 GPU 上）开始，仅在显存不足时才增加。每个移到 CPU 的专家都会增加延迟，因为数据在前向传播期间必须跨越 PCIe 总线。

## 示例配置

### Apple Silicon —— M 系列 Mac 优化

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf \
  -fa \
  --mlock \
  -b 512 \
  -ub 512 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  -ngl 999 \
  --port 8080
```

这将模型锁定在统一内存中，启用 flash attention，并量化 KV 缓存以充分利用内存预算。Apple Silicon 的统一内存意味着 GPU 可以访问整个内存池，因此只要模型和 KV 缓存放得下，完全卸载（`-ngl 999`）就能工作。

> [!NOTE]
>
> llama.cpp 在 Apple Silicon 上运行良好，但如果你专门在 Mac 上部署，[MLX](https://github.com/ml-explore/mlx) 针对 Apple 的 Metal 后端进行了优化，可能对同一模型提供更快的推理。当你需要跨平台可移植性或 OpenAI 兼容服务器时，使用 llama.cpp。

### GPU 卸载 —— NVIDIA 或 AMD 独立 GPU

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf \
  -fa \
  -ngl 999 \
  -b 512 \
  -ub 512 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  -t 4 \
  --port 8080
```

完全 GPU 卸载，配合 flash attention 和量化 KV 缓存。4 个 CPU 线程处理编排和分词。如果模型放不下，降低 `-ngl` —— 从总层数开始，每次减少 5 直到能加载。

### 纯 CPU —— 无 GPU

```bash theme={"theme":{"light":"github-light","dark":"css-variables"}}
llama-server -m model.gguf \
  -t 8 \
  -b 256 \
  -ub 256 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --port 8080
```

没有 GPU 卸载，所以 CPU 承担所有工作。线程数匹配物理核心数。较小的批处理大小保持内存占用可控。对模型权重使用 Q4\_K\_M 或 Q5\_K\_M 量化以保持较小的占用。

## 后续步骤

> **[llama.cpp 远程访问](/zh/guides/llama-cpp-remote-access.md)**
>
> 通过 Tokios 将你的 llama.cpp 服务器暴露给团队成员和代理 —— 无需开放端口。

> **[推测解码](/zh/guides/speculative-decoding.md)**
>
> 使用草稿模型、n-gram 和 EAGLE 加速解码 —— 适用于 llama.cpp 后端。

> **[测试你的部署](/zh/guides/benchmark-your-deployment.md)**
>
> 调优后测量延迟和吞吐量以确认改进效果。

> **[KV 缓存与上下文](/zh/concepts/kv-cache-and-context.md)**
>
> 深入解释 KV 缓存如何在不同模型架构和运行时中工作。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.