llama.cpp INI Presets:用 preset.ini 与系统级 config.ini 构建可复用的参数配置
本文基于 docs/preset.md 展开,系统讲解 llama.cpp 的 INI Preset 机制:如何用 preset.ini 为模型固化可复用的推理参数、如何通过 Hugging Face 仓库分发命名预设、以及如何在系统级 config.ini 中为所有工具共享默认选项。读完本文,你将掌握预设文件的完整语法、参数覆盖优先级、服务端路由模式(router mode)下的加载流程,并能定位到 common/preset.cpp、common/arg.cpp 中对应的解析与生效逻辑。
INI Presets 是什么
INI Preset 功能由 PR #17859 引入,允许用户把 llama.cpp 的一组 CLI 参数写成标准 INI 配置文件,实现可复用、可分享的参数组合。其核心数据结构与接口定义在 common/preset.h 中:
common_preset:单个预设,内部是一个std::map<common_arg, std::string>,即"CLI 参数 -> 字符串值"的映射;common_presets:std::map<std::string, common_preset>,表示一个 INI 文件中的多个预设(按 section 名索引);common_preset_context:预设的加载与编辑上下文,提供load_from_ini、load_from_cache、load_from_models_dir、load_from_args、cascade等入口。
从源码结构看,预设本质上就是"一份待解析的 CLI 参数集合"。common_preset::to_args()(见 common/preset.cpp#L37-L79)可以把它还原成命令行参数列表,apply_to_params()(见 common/preset.cpp#L142-L168)则逐项调用对应参数的 handler,把值写入 common_params。因此预设中支持的任何键,都是该工具本来就认识的命令行参数。
preset.ini 的语法与键名规则
INI 文件的解析实现位于 common/preset.cpp#L170-L249 的 parse_ini_from_file(),它使用 llama.cpp 内置的 PEG 语法解析器(common/peg-parser.h)构建了一份 INI 文法:
- 注释:以
;或#开头,到行尾为止; - 行结构:
[section]表头行、key = value键值行、注释行、空行,四者之一; - 键名:
[a-zA-Z_][a-zA-Z0-9_.-]*,值可以包含空格。
关于键名的对应关系,get_map_key_opt()(见 common/preset.cpp#L251-L262)会为每个参数建立两类索引:去除前导 - 的参数名(长参数如 n-gpu-layers、短参数如 c、ngl)和环境变量名(如 LLAMA_ARG_N_GPU_LAYERS)。因此按 服务端文档 的说法,以下三种写法都是合法的键:
; 长参数名
n-gpu-layers = 8
; 短参数名(例如上下文长度)
c = 4096
; 环境变量名
LLAMA_ARG_CACHE_RAM = 0
几个需要注意的细节(均可在源码中确认):
version键被跳过:load_from_ini()中version是保留键,供未来使用(见 common/preset.cpp#L305-L308);- 布尔值的否定写法:
parse_bool_arg()(见 common/preset.cpp#L268-L277)支持以no-为前缀的否定参数名。例如参数同时注册了--jinja和--no-jinja时,写no-jinja = true等价于把jinja置为 false; - section 名中的量化 tag 会被规范化:
canonical_tag()会把形如xxx:q4_K_M的 tag 统一转为大写Q4_K_M(见 common/preset.cpp#L20-L35),与 GGUF tag 的书写习惯保持一致; - 未知键的两种策略:默认情况下,预设中出现工具不认识的键会直接报错
option 'xxx' not recognized in preset 'yyy';而共享配置场景可以设置ignore_unknown_keys = true,此时未知键只打印警告ignoring option 'xxx' from yyy: not supported by this program(见 common/preset.cpp#L325-L332)。
在服务端路由模式中使用本地预设文件
llama-server 的路由模式(router mode)是预设最主要的消费场景:启动时不指定模型,主进程作为路由器,把请求转发给动态加载的模型实例。路由模式下模型文件有三个来源(见 服务端文档):
- 缓存中的模型(由
LLAMA_CACHE环境变量控制); - 自定义模型目录(
--models-dir参数); - 自定义预设文件(
--models-preset参数,对应环境变量LLAMA_ARG_MODELS_PRESET)。
指定预设文件的方式:
llama-server --models-preset ./my-models.ini
INI 中每个 section 定义一个预设,section 名可以是服务器中已存在的模型名(作为该模型的默认配置),也可以是自定义名称(此时 section 内必须至少给出 model 或 hf 指向的模型)。官方示例:
version = 1
; (可选)全局设置,所有预设共享;
; 若具体预设中定义了同名键,将覆盖全局值
[*]
c = 8192
n-gpu-layers = 8
; 若键对应服务器上已有的模型,则作为该模型的默认配置
[ggml-org/MY-MODEL-GGUF:Q8_0]
; 字符串值
chat-template = chatml
; 数值
n-gpu-layers = 123
; 标志位(部分标志需用 "no-" 前缀表示否定)
jinja = true
; 短参数(例如上下文长度)
c = 4096
; 环境变量名
LLAMA_ARG_CACHE_RAM = 0
; 文件路径相对于服务器 CWD
model-draft = ./my-models/draft.gguf
; 但推荐使用绝对路径
model-draft = /Users/abc/my-models/draft.gguf
; 若键不对应已有模型,必须指定至少模型路径或 HF 仓库
[custom_model]
model = /Users/abc/my-awesome-model-Q4_K_M.gguf
预设参数的优先级规则为:
- 命令行参数(传给
llama-server本身,优先级最高); - 模型专属 section 中的选项(如
[ggml-org/MY-MODEL...]); - 全局 section
[*]中的选项。
另外有三个仅预设可用(不出现在 CLI)的选项,定义于 common_params_add_preset_options()(见 common/arg.cpp#L4742-L4766,通过 set_preset_only() 标记,to_args() 会跳过它们):
| 选项 | 类型 | 说明 |
|---|---|---|
load-on-startup |
布尔 | 服务器启动时是否自动加载该模型。仅在启动时生效;之后重新加载模型列表时,新增模型只列出、不加载 |
stop-timeout |
整数(秒) | 请求卸载后等待优雅退出的最长时间,超时强制终止(默认 10) |
dedup-cache-models |
布尔 | 当预设的 hf-repo 指向已下载的模型时,从 GET /models 中隐藏对应的缓存模型条目(预设条目保留)。写入 [*] 可对所有预设生效 |
服务端加载自定义预设的入口在 tools/server/server-models.cpp#L518-L520:当 --models-preset 非空时,调用 ctx_preset.load_from_ini() 读取文件并打印 Loaded N custom model presets from ... 日志。
使用 Hugging Face 预设
重要:只使用你信任的预设!来自不明来源的预设可能不安全(可以覆盖任意参数,相当于远程代码配置注入面)。
你可以把预设推送到 Hugging Face Hub 与用户共享,步骤:
- 在 Hugging Face 上创建一个空的模型仓库;
- 在仓库根目录放置一个
preset.ini文件。
官方给出的 preset.ini 示例(来自 docs/preset.md):
[*]
ctx-size = 0
mmap = 1
kv-unified = 1
parallel = 4
spec-default = 1
[Qwen3.5-4B]
hf = unsloth/Qwen3.5-4B-GGUF:Q4_K_M
ctx-size = 262144
batch-size = 2048
ubatch-size = 2048
top-p = 1.0
top-k = 0
min-p = 0.01
temp = 1.0
[gpt-oss-120b-hf]
hf = ggml-org/gpt-oss-120b-GGUF
ctx-size = 262144
batch-size = 2048
ubatch-size = 2048
top-p = 1.0
top-k = 0
min-p = 0.01
temp = 1.0
chat-template-kwargs = {"reasoning_effort": "high"}
其中 [*] 是全局 section(spec-default = 1 对应 CLI 中的 --spec-default 开关,其默认配置见 common/arg.cpp#L4722-L4737),其余 section 每个对应一个模型,hf 键指向 Hugging Face 仓库(可带量化 tag)。
由于预设的加载方式与 --models-preset 相同,命令行参数仍然可以覆盖预设中的值:
# 强制 temp = 0.1,覆盖预设中的值
llama-cli -hf username/my-preset --temp 0.1
底层加载流程(源码印证)
当你用 -hf 指向一个包含 preset.ini 的仓库时,仓库扫描阶段会识别它:common/download.cpp#L744-L750 中,若仓库根目录存在 preset.ini,则只下载这一个文件并填入 plan.preset,不再按常规方式寻找 GGUF 模型文件。随后在 common/arg.cpp#L677-L684:
// if HF repo is a preset repo, we simply run server in router mode with the preset.ini file
params.models_preset_hf = params.model.hf_repo; // only for showing a warning
params.models_preset = hf_cache::finalize_file(plan.preset);
params.model = common_params_model{}; // make sure to clear model, so server starts in router mode
也就是说:预设仓库的 preset.ini 被下载到本地缓存后,等价于给用户传了 --models-preset <本地文件>,同时清空模型字段,使 llama-server 以路由模式启动。服务器启动时会打印提示(见 tools/server/server.cpp#L525-L526):NOTE: using preset.ini from HF repo 'xxx'。相关端到端行为在 tests/test-model-resolution.cpp 中有覆盖,例如断言 params.models_preset 指向缓存中的 preset.ini(见 tests/test-model-resolution.cpp#L463)。
命名预设(Named Presets)
如果一个预设文件要为多个 GGUF 模型提供配置,推荐做法是:创建一个空白 HF 仓库,其中只放一个 preset.ini,各 section 通过 hf 键引用真实的模型仓库:
[*]
mmap = 1
[gpt-oss-20b-hf]
hf = ggml-org/gpt-oss-20b-GGUF
batch-size = 2048
ubatch-size = 2048
top-p = 1.0
top-k = 0
min-p = 0.01
temp = 1.0
chat-template-kwargs = {"reasoning_effort": "high"}
[gpt-oss-120b-hf]
hf = ggml-org/gpt-oss-120b-GGUF
batch-size = 2048
ubatch-size = 2048
top-p = 1.0
top-k = 0
min-p = 0.01
temp = 1.0
chat-template-kwargs = {"reasoning_effort": "high"}
然后可以直接用 llama-cli 或 llama-server 加载,通过 仓库:section 选择具体预设:
llama-server -hf user/repo:gpt-oss-120b-hf
文档特别提醒:请务必为每个子预设填写正确的 hf 仓库地址。如果 section 名被误当作"仓库 + tag"去解析而找不到匹配的量化文件,就会得到报错 The specified tag is not a valid quantization scheme.。
系统级配置(System-level Config)
系统级配置由 PR #26118 加入,目的是让多个工具和示例程序共享同一组选项——与上文不同,它不受限于服务端场景。
文件位置与加载顺序
这些文件在程序启动时若存在则自动加载,后加载的文件覆盖先加载的(见 common/arg.cpp#L716-L760 的 common_params_apply_system_config()):
- 系统级:
/etc/llama.cpp/config.ini(Windows 上为%PROGRAMDATA%\llama.cpp\config.ini); - 用户级:
$XDG_CONFIG_HOME/llama.cpp/config.ini,默认即~/.config/llama.cpp/config.ini(Windows 上为%APPDATA%\llama.cpp\config.ini)。
源码中的实现与文档一致:非 Windows 平台先探测 /etc/llama.cpp/config.ini,再尝试 fs_get_config_directory() + "config.ini" 得到的用户级目录;文件存在才加入加载列表,加载时打印 using config file: <path>。
生效优先级
配置文件最先应用,其选项随后被环境变量、CLI 参数、模型预设(路由模式下)依次覆盖。完整的优先级链条是:
- 系统级 config.ini;
- 用户级 config.ini(覆盖 1);
- 环境变量(如
LLAMA_ARG_*); - 命令行参数;
- 模型预设 section(仅路由模式,且 CLI > 模型 section >
[*])。
在 common/arg.cpp#L762-L769 中可以看到,common_params_parse_ex() 的第一步就是调用 common_params_apply_system_config(),注释明确写着 "config file applies first, so env variables and CLI arguments override it"。
使用限制与注意事项
- 只使用
[*]和默认 section:写在任何表头之前的键属于默认 section;命名 section(如[my-model])会被忽略。源码中对应逻辑是:load_from_ini()把[*]的内容装入global预设,随后apply_system_config()依次应用global和名为default的预设(见 common/arg.cpp#L750-L759); - 工具专属选项会被静默容忍:同一份配置文件被所有 llama.cpp 程序共享,因此这里使用
ignore_unknown_keys = true。例如你写了port = 1234,只有llama-server会采用,其他工具打印警告后忽略; - 不建议在系统级配置
model或hf-repo:它们可能引入冲突。典型坑是——配置文件中的hf-repo在命令行传了-m时仍然生效,导致实际加载的不是你以为的那个模型。
一个用户级 config.ini 的保守示例(只放通用、低冲突的选项):
; ~/.config/llama.cpp/config.ini
[*]
mmap = 1
预设的组合与转换:从源码结构看更多能力
除文档主线的三个场景外,common/preset.h 还暴露了若干组合工具,可用于理解(或二次开发)预设的流转方式:
cascade(base, added):两套预设按名合并,同名预设用后者覆盖前者选项(merge()),类似 CSS 层叠;cascade(base_preset, presets):把某个基础预设作为底,叠加到一组命名预设上;load_from_cache():为每个已缓存的模型(LLAMA_CACHE目录)自动生成一个预设,hf键指向该模型(见 common/preset.cpp#L350-L362)——这就是路由模式"默认从缓存发现模型"的实现;load_from_models_dir():扫描本地模型目录生成预设,支持单文件、分片(-00001-of-)、多模态mmproj伴生文件,以及mtp-/dspark-/dflash-前缀的投机解码 draft 伴生文件(见 common/preset.cpp#L387-L463);load_from_args():把一次 CLI 调用直接固化为default预设,便于"命令行试出来的参数组合"转写成 INI。
小结与相关资源
| 场景 | 入口 | 关键文件 |
|---|---|---|
| 本地预设(路由模式) | llama-server --models-preset ./my-models.ini |
tools/server/server-models.cpp |
| HF 预设 | 仓库根目录 preset.ini,llama-server -hf user/repo[:section] |
common/download.cpp、common/arg.cpp |
| 系统级配置 | /etc/llama.cpp/config.ini、~/.config/llama.cpp/config.ini |
common/arg.cpp |
| 解析与数据结构 | PEG 文法 INI 解析、common_preset* |
common/preset.h、common/preset.cpp |
使用前提:INI Presets 是较新的功能(PR #17859 / #26118),请以当前仓库构建版本的行为为准;HF 预设涉及联网下载,需确保来源可信;version 键目前仅为保留字段,写不写均可。更多路由模式的模型目录结构与 API 细节,可继续参考 tools/server/README.md。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00