
LLaMA
从源码编译 llama.cpp 1.0 并用 GGUF 模型跑通本地对话与 OpenAI 兼容 API
llama.cpp 1.0 把版本号从提交号换成了语义化版本,公开 C API 的兼容性从此有了承诺。本文从源码编译 llama-cli、llama-server、llama-bench,用 GGUF 模型跑通终端对话、OpenAI 兼容接口与速度基准,并说明思考型小模型耗尽 token 预算、脚本调用时标准输入挂起等实际会踩到的坑。
llama.cpp 是一个用 C/C++ 写的本地大语言模型推理引擎,负责把 GGUF 格式的模型文件加载进内存、在 CPU 或 GPU 上完成推理。它本身不含模型,只提供一组命令行可执行文件:llama-cli 做终端对话与文本生成,llama-server 起一个 OpenAI 兼容的 HTTP 服务,llama-bench 测提示处理与生成速度,llama-quantize 把模型量化成更小的体积。Ollama、LM Studio 这类本地 AI 应用的内部也在用它,所以想弄清那些应用背后在做什么、或者要把本地模型接进自己的程序,直接操作引擎本体是最直接的路子。它适合不打算把数据发到云端、希望完全离线推理的人,也适合需要把本地模型封装成 API 供其他工具调用的开发者。如果你只是想开箱即用地聊天,带图形界面的封装应用会更省事;llama.cpp 没有 GUI,构建和参数都得自己在命令行里处理。站内也有对应的工具条目可以对照:LLaMA。
1.0 这个版本的意义主要在稳定性承诺,而不是功能跃升。此前版本号是 b12359 这样的提交计数,从编号上看不出兼容性;1.0 起引入语义化版本,破坏公开 C API 的改动升主版本,向后兼容的功能新增升次版本,修 bug 升补丁版本。同时清理了 35 个已弃用函数,以及 llama_set_warmup、--defrag-thold 等选项,依赖旧 API 的程序需要在这个节点迁移。新功能方面包括 FP8 格式的 KV 缓存、把 MoE 模型的专家权重放在主机内存的缓存、若干新模型架构支持、TTS 语音合成,以及 llama-server 的 SSRF、CORS、DNS 重绑定防护。这些能力的具体行为与可用范围,请以官网当前信息为准。
准备工作
需要先确认三件事:构建工具链、模型文件、以及版本选择。
- 构建工具:
git、cmake、一个 C++ 编译器(Linux 上通常是g++)。素材中的验证环境是 Linux x86_64 + GNU 13.3.0,没有 GPU 也能完成全部构建与运行。 - 模型文件:llama.cpp 不附带模型,需要自行下载 GGUF 格式文件。Hugging Face 上 ggml-org 账号发布的量化模型可以直接用。素材中用到两个:Qwen3.5-0.8B 的 4 比特量化版(约 537MB)与 Gemma-3-1b-it 的 Q4_K_M 量化版(约 769MB)。
- 内存:进程峰值内存大致是模型文件大小加上 KV 缓存与运行时开销。素材实测 0.8B 级模型在上下文长度 2048 时峰值约 971MiB,1B 级模型在上下文 1024 时约 937–960MiB,也就是模型体积之外还要多留几百 MB。按这个比例估算,8GB 内存的机器跑 0.8B–1B 级模型很宽裕,7B 级(模型约 4–5GB)也能装下,但要留出系统和其他进程的空间。
- 磁盘与网络:源码克隆加构建产物需要一定空间,模型下载按体积计流量。
关于版本,需要注意 v1.0.0 这个标签下并没有附带预编译二进制,发布资产里只有一个 nightly 标记文件,所以要走源码构建。如果你不想自己编译,可以看看官网当前是否提供了其他渠道的构建产物,以官网信息为准。
操作步骤
第一步:获取源码并构建
用浅克隆拉取指定标签,并递归拉取子模块:
git clone --depth 1 --branch v1.0.0 --recurse-submodules https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
配置构建。这里关掉测试与示例,只编译需要的目标,能明显缩短时间:
cmake -B build -DCMAKE_BUILD_TYPE=Release -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_EXAMPLES=OFF
然后编译三个目标。-j 4 是并行任务数,按自己机器的核数调整:
cmake --build build --target llama-cli llama-server llama-bench -j 4
产物落在 build/bin/ 下。确认版本:
./build/bin/llama-cli --version
自己构建时版本串通常显示为 1.0.0-dev,后面跟着构建号与提交号。原因是 CMakeLists.txt 里有一个 LLAMA_BUILD_IS_DEV 选项默认开启,官方发布构建会把它关掉。另外浅克隆会让构建号显示为 1,因为提交计数只算到了 1 个。标签本身可以用 git describe --tags 核对,应输出 v1.0.0。这些差异只影响版本串显示,不影响功能。
第二步:下载 GGUF 模型
从 Hugging Face 下载量化模型文件。素材中使用的两个文件如下,下载地址请以模型页面当前提供的为准:
curl -L -o Qwen3.5-0.8B-Q4_0.gguf <模型文件地址>
curl -L -o gemma-3-1b-it-Q4_K_M.gguf <模型文件地址>
文件名里的 Q4_0、Q4_K_M 是量化方案,数字表示权重位宽,后缀区分同一档位下的不同混合策略。位宽越低文件越小、速度通常越快,精度损失也越大。
第三步:在终端里对话
最简形式:
./build/bin/llama-cli -m Qwen3.5-0.8B-Q4_0.gguf -c 2048 -t 4
三个关键参数:-m 指定模型文件,-c 是上下文长度(对话能记住的 token 总量),-t 是使用的线程数。启动后进入交互界面,输入提示词即得到回复,/exit 退出。
只问一次就结束的一次性执行:
./build/bin/llama-cli -m gemma-3-1b-it-Q4_K_M.gguf \
-p "日本的首都是哪里?请简洁回答。" \
-n 256 --temp 0 -c 1024 -t 4 \
--no-display-prompt < /dev/null
参数含义:-p 是提示词,-n 是最大生成 token 数,--temp 0 让采样确定化(同一输入尽量给同一输出),--no-display-prompt 不在输出里重复提示词。
末尾的 < /dev/null 不是可选项。llama-cli 1.0 默认进入交互模式,如果标准输入保持打开,第一次回复结束后进程会继续等下一次输入而不退出。素材中把标准输入接成管道直接运行时,进程卡在输入等待上超过四分钟没有进展,检查发现主线程停在管道读取状态。脚本里调用时,要么关闭标准输入,要么用管道把输入喂进去。
第四步:起一个 OpenAI 兼容的 API 服务
./build/bin/llama-server -m gemma-3-1b-it-Q4_K_M.gguf -c 2048 -t 4 --port 8899 --host 127.0.0.1
端口建议显式指定,避免和机器上其他服务冲突;--host 127.0.0.1 表示只监听本机,不要在不清楚防护措施的情况下暴露到公网。
服务起来后先做健康检查:
curl http://127.0.0.1:8899/health
返回 {"status":"ok"} 说明就绪。列出可用模型:
curl http://127.0.0.1:8899/v1/models
调用对话补全接口:
curl -X POST http://127.0.0.1:8899/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gemma-3-1b-it-Q4_K_M.gguf",
"messages": [{"role": "user", "content": "日本的首都是哪里?"}],
"max_tokens": 256,
"temperature": 0
}'
因为接口与 OpenAI 的格式一致,任何支持自定义 base URL 的客户端或 SDK 都可以把地址指向这里,把 API key 随便填一个非空值即可(本地服务不校验)。
第五步:测速
./build/bin/llama-bench -m Qwen3.5-0.8B-Q4_0.gguf -t 4 -p 512 -n 128
-p 512 表示测 512 token 的提示处理(pp),-n 128 表示测 128 token 的生成(tg),结果以 token/秒 给出,并带标准差。提示处理速度决定长输入的首字延迟,生成速度决定回复吐字快慢,两者要分开看。
一个完整示例
下面从零走一遍:编译、下载、一次性问答、起服务、用 API 提问、测速。假设工作目录为空,模型文件放在当前目录。
# 1. 取源码并构建
git clone --depth 1 --branch v1.0.0 --recurse-submodules https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
cmake -B build -DCMAKE_BUILD_TYPE=Release -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_EXAMPLES=OFF
cmake --build build --target llama-cli llama-server llama-bench -j 4
./build/bin/llama-cli --version
# 2. 下载模型(地址以模型页面为准)
cd ..
curl -L -o gemma-3-1b-it-Q4_K_M.gguf <模型文件地址>
# 3. 一次性问答,注意关闭标准输入
./llama.cpp/build/bin/llama-cli -m gemma-3-1b-it-Q4_K_M.gguf \
-p "日本的首都是哪里?请简洁回答。" \
-n 256 --temp 0 -c 1024 -t 4 \
--no-display-prompt < /dev/null
# 4. 起服务(另开一个终端)
./llama.cpp/build/bin/llama-server -m gemma-3-1b-it-Q4_K_M.gguf \
-c 2048 -t 4 --port 8899 --host 127.0.0.1
# 5. 验证并调用
curl http://127.0.0.1:8899/health
curl -X POST http://127.0.0.1:8899/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"gemma-3-1b-it-Q4_K_M.gguf","messages":[{"role":"user","content":"日本的首都是哪里?"}],"max_tokens":256,"temperature":0}'
# 6. 测速
./llama.cpp/build/bin/llama-bench -m gemma-3-1b-it-Q4_K_M.gguf -t 4 -p 512 -n 128
素材在无 GPU 的共享 Linux 环境(AMD EPYC,实际可用约 1.5 个 CPU,空闲内存仅 1–2GB)中跑这套流程,构建耗时 11 分 45 秒,cmake 配置约 2 秒,没有遇到依赖问题;llama-server 从加载模型到开始监听约 1.6 秒。基准测试结果:Qwen3.5-0.8B Q4_0 的提示处理为 96.27 ± 6.04 t/s、生成为 14.59 ± 0.97 t/s;Gemma-3-1b-it Q4_K_M 的提示处理为 51.46 ± 1.62 t/s、生成为 11.95 ± 0.23 t/s。用 Gemma-3-1b-it 回答「日本的首都是哪里?请简洁回答。」,3.84 秒返回「东京」,生成速度 11.0 t/s。
这些数字来自一台资源极度受限的共享机器,属于下限参考。普通笔记本或台式机通常快数倍。同一台机器上 llama-cli 的实际显示速度波动也很大,提示处理在 18–71 t/s 之间跳动,生成在 11–16 t/s 之间,所以不要把单次读数当成稳定性能。
注意事项
思考型小模型可能耗尽预算,答不出正文
这是素材中最值得注意的坑。Qwen3.5-0.8B 属于先输出推理过程再给答案的思考型模型,在默认配置下,推理过程会把 token 预算吃光,正文答案出不来。
- 英文提示「The capital of France is」:
-n 256时经过 7 步思考后正确输出「The capital of France is Paris.」;-n 64时思考阶段就用完了预算。 - 日文提示「日本的首都是哪里?」:
-n 256与-n 512都在思考中途耗尽预算。-n 512时陷入「Wait, I should write it in Japanese. Answer: 东京.」这类同一句式的重复,最终没有给出答案。 - 通过服务端问「17 + 25」:
max_tokens设为 256 或 1024,返回的content都是空的,推理内容只出现在reasoning_content字段里。1024 token 时仍在「Let's check again: 10+20=30…」的循环中结束,耗时 66.95 秒。推理过程中一度把算式错误拆成「10+25=35、7+25=32、35+32=67」,随后自己发现并纠正。
也就是说,小体量思考模型配 llama.cpp 默认设置,简单问题也可能拿不到答案。素材没有区分这是模型侧的问题还是聊天模板交互导致的问题。实用上可以这样选:改用不思考的模型(如 Gemma-3-1b-it,素材中表现最直接);把 -n 或 max_tokens 调大(但 1024 都不够的例子说明这招不万能);换更大的模型(受内存限制)。
在提示词末尾加 /no_think 并不能关闭思考
Qwen 系列常见做法是在消息末尾加 /no_think 跳过推理。素材实测在这个组合下无效:模型没有停止思考,反而开始对「no_think 这个指令」本身进行推理,128 token 后预算耗尽。llama.cpp 侧另有控制思考输出的选项(例如 --reasoning-format),素材未做验证,需要时请查官网当前文档。
脚本调用必须处理标准输入
如前所述,默认交互模式下标准输入不关闭,进程会在首次回复后挂起等待输入。批处理、定时任务、CI 里调用时务必加 < /dev/null 或用管道传入内容。
速度与内存高度依赖环境
共享 CPU 环境下提示处理速度在 18–71 t/s 之间大幅波动。素材的测量值应视为低配环境的下限,用于横向比较模型之间的相对快慢,不要当作绝对性能指标。内存方面,进程峰值约为模型体积加数百 MB,上下文长度越长 KV 缓存越大,-c 设得过大在内存紧张的机器上会直接失败。
1.0 的多数新功能未在素材中验证
FP8 KV 缓存、MoE 专家权重的主机内存缓存、新增模型架构支持、llama-server 的 SSRF/CORS/DNS 重绑定防护,都只有发布说明层面的信息,没有实际运行验证,安全加固部分也没有做攻击测试。macOS 与 Windows 的官方桌面应用同样未验证。如果你的场景依赖这些能力,请以官网当前信息为准并自行测试。
许可与费用
llama.cpp 本体是 MIT 许可的开源软件,没有付费版本或计费功能。可能产生的成本只有运行机器的电费与算力、模型文件的下载流量。但模型有自己的许可,Qwen3.5 与 Gemma-3 各有独立条款,商用可行性与限制需按模型逐个确认——引擎是 MIT 不代表模型也是 MIT。具体条款与最新价格政策请以官网当前信息为准。
旧 API 迁移
1.0 删除了 35 个已弃用函数以及 llama_set_warmup、--defrag-thold 等选项。如果你的程序或脚本依赖这些接口,升级前需要先改代码。语义化版本只保证今后主版本内的兼容性,不追溯修复已有的破坏性变更。