llama.cpp 架构

llama.cpp 是 Georgi Gerganov 用纯 C/C++ 编写的 LLM 推理引擎,最初为 LLaMA 模型设计,现已支持 40+ 模型架构。其核心设计哲学:

  • 零依赖:仅依赖 C/C++ 标准库,编译后单二进制运行
  • 跨平台:x86/ARM CPU、NVIDIA/AMD/Apple GPU、WebAssembly
  • 量化优先:原生 GGML/GGUF 量化格式,在 CPU 上实现实用级推理速度
┌─────────────────────────────────────────┐
│         CLI / Server / API              │
│   (llama-cli / llama-server)           │
├─────────────────────────────────────────┤
│         GGML Compute Graph              │
│   (Operator Fusion + SIMD/NEON)        │
├──────────┬───────────┬──────────────────┤
│  CPU     │  CUDA     │  Metal / Vulkan  │
│  Backend │  Backend  │  Backend         │
│ (AVX2/   │ (NVIDIA)  │ (Apple/AMD/Intel)│
│  AVX512/ │           │                  │
│  NEON)   │           │                  │
└──────────┴───────────┴──────────────────┘

GGUF 格式

GGUF(GGML Universal Format)是 llama.cpp 的模型文件格式,取代了早期的 GGML 格式。

GGUF 结构

GGUF File Layout:
┌────────────────────┐
│   Magic Number     │  "GGUF" (4 bytes)
├────────────────────┤
│   Metadata         │  KV pairs (architecture, vocab, hyperparams)
├────────────────────┤
│   Tokenizer        │  Token embeddings / vocabulary
├────────────────────┤
│   Tensor Data      │  Quantized weights (aligned blocks)
└────────────────────┘

GGUF vs SafeTensors

特性GGUFSafeTensors
量化支持✅ 内置多种量化❌ 仅原始精度
元数据✅ 丰富 KV⚠️ 有限
加载速度快(内存映射)
通用性llama.cpp 生态HF 生态
分片支持

量化方案详解

llama.cpp 支持丰富的量化方案,命名规则为 Q<bits>_<variant>

量化方案对比

量化每权重比特模型大小 (7B)PPL 变化速度 (tok/s)推荐场景
Q8_08.57.2 GB+0.0342最高质量
Q6_K6.65.5 GB+0.0548高质量
Q5_K_M5.74.8 GB+0.0854均衡之选
Q4_K_M4.84.1 GB+0.1560最推荐
Q4_04.53.8 GB+0.3568极致速度
Q3_K_M3.93.3 GB+0.5265低端设备
Q2_K2.62.2 GB+1.270极限压缩

量化原理

// Q4_K_M 量化结构(简化)
// 每个 block 包含 32 个权重
typedef struct {
    uint8_t scales[16];   // 6-bit 量化刻度
    uint8_t quants[128];  // 4-bit 量化值 (32 weights × 4 bits / 8 bits)
} block_q4_K;

// 每个权重的实际值 = scale × quant
// Q4_K_M 中的 "K" 表示使用 super-block 结构
// "M" 表示混合精度:attention 层用 Q6_K,其余用 Q4_K

模型转换与量化

# 从 HuggingFace 下载原始模型
huggingface-cli download meta-llama/Llama-3.1-8B-Instruct \
  --local-dir ./Llama-3.1-8B

# 转换为 GGUF(需要 llama.cpp 源码)
cd llama.cpp
python convert_hf_to_gguf.py \
  ../Llama-3.1-8B \
  --outfile ../Llama-3.1-8B-FP16.gguf \
  --outtype f16

# 量化为不同精度
./llama-quantize Llama-3.1-8B-FP16.gguf Llama-3.1-8B-Q4_K_M.gguf Q4_K_M
./llama-quantize Llama-3.1-8B-FP16.gguf Llama-3.1-8B-Q5_K_M.gguf Q5_K_M
./llama-quantize Llama-3.1-8B-FP16.gguf Llama-3.1-8B-Q8_0.gguf Q8_0

CPU/GPU 混合推理

llama.cpp 支持将模型的不同 layer 分配到不同计算后端。

Layer Offload 策略

# 全 CPU 推理
./llama-cli -m Llama-3.1-8B-Q4_K_M.gguf -p "Hello" -n 512

# 全 GPU 推理(-ngl 999 = 所有层放 GPU)
./llama-cli -m Llama-3.1-8B-Q4_K_M.gguf -p "Hello" -n 512 -ngl 999

# 混合推理(-ngl 20 = 20 层放 GPU,其余放 CPU)
./llama-cli -m Llama-3.1-70B-Q4_K_M.gguf -p "Hello" -n 512 -ngl 20

性能参考

以 Llama 3.1 8B Q4_K_M 为例:

配置硬件速度 (tok/s)说明
纯 CPURyzen 9 7950X2816 核全用
纯 CPUApple M2 Pro35统一内存优势
-ngl 10Ryzen + RTX 4060 8G45部分 layer offload
-ngl 33 (全部)RTX 4060 8G62全 GPU
-ngl 999RTX 4090 24G110全 GPU

自动 Layer 分配

# 自动计算最优 layer offload 数量
import subprocess, json

def auto_offload(model_path, gpu_vram_gb):
    """根据 GPU 显存自动计算 offload 层数"""
    # 获取模型信息
    result = subprocess.run(
        ['./llama-gguf', model_path, '--json'],
        capture_output=True, text=True
    )
    info = json.loads(result.stdout)
    total_layers = info['metadata']['llm.tensor_count']
    layer_size_mb = info['metadata']['file_size_mb'] / total_layers

    # 预留 1GB 给 KV Cache 和上下文
    available_mb = (gpu_vram_gb * 1024) - 1024
    max_offload = int(available_mb / layer_size_mb)
    return min(max_offload, total_layers)

offload = auto_offload("Llama-3.1-70B-Q4_K_M.gguf", gpu_vram_gb=24)
print(f"Offloading {offload} layers to GPU")

性能调优

线程配置

# 物理核心数(不用超线程)
nproc  # 查看核心数

# 设置线程数 = 物理核心数
./llama-cli -m model.gguf -t 16 -p "Hello" -n 512

# 批处理线程(prefill 阶段)可以更多
./llama-cli -m model.gguf -t 16 -tb 24 -p "Hello" -n 512
线程数速度 (tok/s)说明
418不足
828线性提升
1635接近峰值
3234超线程无收益
6430下降(调度开销)

上下文长度与 KV Cache

# 默认上下文 2048,生产环境需要增大
./llama-cli -m model.gguf -c 8192 -p "Hello" -n 512

# KV Cache 量化(减少显存/内存占用)
./llama-cli -m model.gguf -c 32768 \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  -p "Hello" -n 512
KV Cache 类型内存占用 (32K ctx, 8B)PPL 变化
f16 (默认)4.0 GB基准
q8_02.0 GB+0.02
q4_01.0 GB+0.15

Flash Attention

# 启用 Flash Attention(需要编译时开启)
cmake -B build -DGGML_CUDA=ON -DGGML_FLASH_ATTN=ON
cmake --build build

# 运行时启用
./llama-cli -m model.gguf -fa -p "Hello" -n 512

Server 模式

# 启动 OpenAI 兼容 API 服务器
./llama-server \
  -m Llama-3.1-8B-Q4_K_M.gguf \
  --host 0.0.0.0 \
  --port 8080 \
  -c 8192 \
  -ngl 33 \
  -t 16 \
  -fa \
  --api-key "your-secret-key"

# 支持 OpenAI 格式请求
curl http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer your-secret-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama3.1",
    "messages": [{"role": "user", "content": "Hello"}],
    "stream": true
  }'

并发处理

# 启用 continuous batching(llama.cpp 新版本)
./llama-server \
  -m model.gguf \
  -c 8192 \
  -np 4 \          # 4 个并行 slot
  -cb \            # continuous batching
  --port 8080

移动端部署

Android 编译

# 交叉编译 for Android (ARM64)
mkdir build-android && cd build-android
cmake .. \
  -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
  -DANDROID_ABI=arm64-v8a \
  -DANDROID_PLATFORM=android-28 \
  -DGGML_NEON=ON \
  -DGGML_OPENMP=ON
cmake --build . -j

# 在手机上运行(通过 Termux 或 adb push)
./llama-cli -m model-Q4_K_M.gguf -t 8 -p "Hello" -n 256

性能参考(移动端)

设备模型量化速度 (tok/s)内存占用
iPhone 15 Pro (A17 Pro)Llama 3.2 3BQ4_K_M282.1 GB
Samsung S24 (SD8 Gen3)Llama 3.2 3BQ4_K_M222.1 GB
iPhone 15 ProLlama 3.1 8BQ4_K_M125.2 GB
Pixel 8 ProLlama 3.2 3BQ4_K_M182.1 GB

Apple Silicon 优化

# Metal 后端(Apple GPU 加速)
cmake -B build -DGGML_METAL=ON
cmake --build build

# 运行时使用 Metal
./llama-cli -m model.gguf -ngl 99 -p "Hello"  # 全部 layer offload 到 Metal
配置模型速度 (tok/s)
M2 Pro CPU only8B Q4_K_M35
M2 Pro + Metal8B Q4_K_M58
M2 Max + Metal70B Q4_K_M14
M3 Ultra + Metal70B Q4_K_M22

编译优化指南

# 针对 CPU 特定指令集优化
cmake -B build \
  -DGGML_AVX2=ON \       # Intel/AMD Haswell+
  -DGGML_AVX512=ON \     # Intel Skylake-X+ / AMD Zen4+
  -DGGML_FMA=ON \        # FMA3 指令
  -DGGML_F16C=ON \       # FP16 转换指令
  -DGGML_OPENMP=ON       # 多线程并行

# 编译时 LTO 优化
cmake -B build -DGGML_LTO=ON -DCMAKE_BUILD_TYPE=Release

# 最优 CPU 编译(AVX512 系统)
cmake -B build \
  -DGGML_AVX512=ON \
  -DGGML_AVX2=ON \
  -DGGML_FMA=ON \
  -DGGML_F16C=ON \
  -DCMAKE_BUILD_TYPE=Release \
  -DGGML_LTO=ON

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。