llama.cpp 简介

项目起源 —— 从一个人的 Saturday Night 开始

2023 年初,大模型刚火起来那会儿,大家都在用 Python + PyTorch 跑推理。显卡贵得离谱,显存动不动几十 G。我一个朋友做嵌入式,想给树莓派上个对话机器人,结果发现传统框架根本跑不动。就在那时候,一个叫 ggerganov 的开发者搞了个实验性项目 —— llama.cpp。

为什么叫 .cpp?因为他用纯 C++ 重写了 LLaMA 模型的推理代码。不依赖 PyTorch,不依赖 CUDA,甚至连 Python 都不需要。我当时看到第一版代码,只有几个头文件,一个 makefile,跑起来后 terminal 里直接出文字,震惊了。

说白了,这个项目的初心就一句话:让大模型在普通 CPU 上也能跑,而且跑得动。你想想看,一台没有独立显卡的笔记本,能跑 7B 参数模型,每秒出两三个 token,这在 2023 年初简直是天方夜谭。但 ggerganov 做到了。

一个小背景:ggerganov 之前做过 whisper.cpp(语音识别)和 stable-diffusion.cpp,他一直在尝试用 C++ 把 AI 模型“瘦身”到边缘设备上。llama.cpp 是他思路的自然延续。

到 2023 年底,社区围绕 llama.cpp 发展出了完整的工具链:量化工具、OpenAI 兼容 API 服务器、多模态支持、甚至是图形化界面。我亲眼看着它从一个纯命令行 demo 变成了生产级的推理框架。

设计理念

llama.cpp 的设计理念可以用四个关键词概括:轻量、无依赖、性能优先、CPU 友好。下面我展开说说。

1. 零外部依赖

你不需要装 CUDA Toolkit,不需要装 cuDNN,甚至不需要 Python 环境。下载一个可执行文件,./llama-cli -m model.gguf -p "hello" 就能跑。我在一个干净的 Ubuntu 22.04 docker 里测试过,apt 装个 g++ 就直接编译通过了。

2. 极致的内存管理

它使用 mmap(内存映射文件) 加载模型,操作系统按需调入页面,而不是一口气全部读到内存。对于大模型,这能节省大量物理内存。我曾在 8GB 内存的 MacBook Air 上跑过 13B 参数模型,虽然慢,但没崩溃。这在传统框架里基本不可能。

3. 量化优先

llama.cpp 内置了从 Q4_0 到 Q8_0 的多种量化格式(GGUF 格式)。你能在精度和速度之间自由权衡。比如 4 比特量化,可以把 7B 模型从 14GB 压缩到 4GB 左右,速度反而更快——因为缓存利用率高了。

实战经验:我个人习惯把 7B 模型切成 Q4_K_M 或 Q5_K_M。Q4 速度最快,Q5 保留更多质量。如果你显存 6GB 以上,推荐 Q5;6GB 以下只能 Q4。这个规则我踩过好几次坑才总结出来。

4. 批处理与并行

它支持批处理(batch)和多线程(通过 -t 参数设置线程数)。我试过在 16 核服务器上跑,吞吐量随线程数近似线性增长,直到内存带宽成瓶颈。对个人开发来说,8 线程是个甜点。

5. 极简交互

所有选项都是命令行参数,没有复杂配置文件。--prompt, -m, -t, -ngl(GPU offload 层数)搞定一切。新手十分钟就能上手。

适用场景

根据我这两年的使用经验,llama.cpp 最适合这几类场景:

场景 说明 典型硬件
个人开发/实验 快速测试模型效果、调试提示词、对比量化精度 笔记本、台式机 CPU
边缘/嵌入式设备 树莓派、Jetson Nano、老旧工控机 ARM Cortex-A, Intel Atom
离线/隐私敏感 文档处理、本地知识库、数据不出内网 普通服务器、无 GPU 工作站
教学/演示 大模型推理原理教学、Transformer 内部结构可视化 任何 x86 机器
服务端轻量部署 并发量不高的聊天机器人、代码补全等 CPU 服务器 16~32 核

我们一个一个聊。

个人开发/实验:我经常在写 prompt 模板时先用 llama-cli -n 50 快速跑一下,看效果,再改。Python 那边还得等 torch 加载,这边已经出结果了。你想想看,迭代速度翻了 10 倍。

边缘设备:有一次我给客户演示,对方只有一台树莓派 4(4GB 内存)。我用 llama.cpp 加载 Q4_0 量化的 TinyLlama 1.1B,虽然每秒只跑 1 个 token,但确实能跑。这比没得跑强一万倍。嗯,真事儿。

离线隐私:医疗文档、金融数据这些,不能送到云端。你用 llama.cpp 在自己服务器上起个 server 模式,前端调用 OpenAI 兼容接口,数据完全不出网。我记得一个银行客户,他们内部就用的这个方案。

教学:新同事入职,我让他先编译 llama.cpp,再改几行代码跑推理,过程中理解 KV cache、attention 计算、tokenizer 原理。比看论文快多了。

服务端轻量部署:如果你的 QPS(每秒请求数)要求低于 10,用户数少于 50,纯 CPU 也能扛。我测试过 7B Q4_K_M,8 核虚拟机,单请求 200 token,延迟约 2 秒,并发 5 个请求时延迟增加到 5 秒。够用了。

避坑指南:我曾经以为 llama.cpp 可以立刻取代传统推理框架。后来发现它不适合高并发(50+ 用户同时请求)、长上下文(超过 8K tokens 时显存/内存暴涨)、以及需要严格 JSON schema 输出的场景。你如果必须用到这些,还是要搭配 vLLM 或 TensorRT-LLM。

核心知识体系

下面这张图能把 llama.cpp 的模块和流程串起来。你看一眼就能理解它是怎么工作的。

llama.cpp 核心架构与推理流程 GGUF 模型文件 (权重 + 配置) 量化模块 Q4 / Q5 / Q8 等 量化 推理引擎 多层 Transformer KV cache / mmap 加载 采样器 top-p / temp / mirostat logits → token 上下文管理器 窗口 / 扩展 / 批处理 输入序列 交互界面 CLI / Server / API 输出 token 用户输入 💡 关键设计特点: • 所有组件都在单一进程中运行,无外部依赖 • mmap 解决大模型加载速度,量化解决内存占用 • 交互层与核心引擎解耦,可替换为 GUI、Web 等

从上图可以清楚看到:模型文件经过量化压缩后,被推理引擎加载,同时上下文管理器维护对话历史。引擎每步输出 logits 给采样器,采样器选出一个 token 交给交互界面。用户输入又从交互界面回流到上下文管理器,形成闭环。

这个架构的优雅之处在于 —— 每个模块都可以独立替换。比如你想换一个自定义采样策略,只需要改采样器的几十行代码。我想换一个模型后端?只要它暴露相同的 GGUF 接口就行。我曾在自己的项目里只用了推理引擎和采样器部分,把交互层换成 HTTP server,花了一下午就集成好了。

社区生态与未来

到 2024 下半年,llama.cpp 已经不仅仅是一个推理框架了。社区贡献了大量周边:

  • llama-server:内置 OpenAI 兼容 API,一行命令起服务
  • llama-perplexity:评估模型困惑度
  • llama-tts:文本转语音(实验功能)
  • Python 绑定:llama-cpp-python 让你在 Python 里调用 C++ 核心

对了,我记得有一次社区里有人把 llama.cpp 移植到了 iOS 上,直接在 iPhone 上跑通了 7B 模型。虽然每秒只有 0.5 个 token,但确实跑起来了。这种“一切皆有可能”的氛围,是我一直喜欢这个项目的原因。

我的建议:如果你刚接触大模型部署,别急着上分布式、显存调度那些高大上的东西。先从 llama.cpp 开始,亲手编译、跑一次推理、量化一个模型。这个过程会让你对模型怎么吃内存、推理时 CPU 的瓶颈在哪、量化到底损失了什么,有最直观的理解。那些大厂框架,说白了都是在这些基础能力上加速而已。

好了,关于 llama.cpp 的起源、设计理念和适用场景,我该说的都说了。下一部分我们准备动手 —— 编译、下载模型、跑出第一个 token。不过那是第二章的事了。