llama.cpp 的 Bash 命令行补全:`--completion-bash` 的用法、生成逻辑与源码原理
llama.cpp 提供了数十个命令行工具(llama-cli、llama-server、llama-quantize 等),其参数众多且命名冗长,逐个记忆成本很高。本文以 docs/completions.md 为主线,完整讲解如何通过 --completion-bash 参数为一键式启用 Bash 命令补全,并结合 common/arg.cpp 中的实现源码,剖析该补全脚本是如何被动态生成、如何按文件扩展名过滤候选值,以及哪些可执行文件被纳入了补全范围,帮助你在日常运行、量化、部署推理服务时大幅减少手敲参数的错误。
一、功能概述:命令行补全在 llama.cpp 中的定位
llama.cpp 的核心功能是大语言模型推理,而围绕推理主流程,仓库提供了批量推理、基准测试、嵌入提取、量化、服务端等大量配套工具。这些工具共享同一套由 common 库实现的参数解析体系,因此也共享一套统一的补全能力:
- 补全仅在 Bash 环境下可用,官方文档的表述是"Command-line completion is available for some environments",目前仓库内置的只有 Bash 脚本生成方案;
- 补全能力不依赖任何外部插件或单独安装的 shell 扩展,而是由二进制自身通过
--completion-bash参数直接打印出一段可source的脚本; - 每个工具文档的参数表中都能看到该参数,例如 tools/cli/README.md 与 tools/server/README.md 的选项表里均列有
--completion-bash,其描述均为 "print source-able bash completion script for llama.cpp"(打印一份可 source 的 Bash 补全脚本)。
需要注意区分:llama-completion 本身也是一个可执行文件名(负责文本续写任务的工具),它与 --completion-bash 这个参数名只共享"completion"一词,功能上毫无关系。
二、启用 Bash 补全:官方文档的完整步骤
2.1 生成并加载补全脚本
按照 docs/completions.md 的原始步骤,只需两行命令:
$ build/bin/llama-cli --completion-bash > ~/.llama-completion.bash
$ source ~/.llama-completion.bash
第一步执行的是 llama-cli(编译产物位于 build/bin/ 目录),由于 --completion-bash 的语义是"把脚本打印到标准输出后退出",因此重定向到 ~/.llama-completion.bash 即可得到完整脚本文件;第二步用 source 将脚本加载进当前 shell,补全函数随即生效。
之后在命令行输入参数名前缀并按 Tab,Bash 就会列出候选项,例如输入 llama-cli --mo 再按 Tab 可补全 --model,输入 -l 可补全相关短参数。
2.2 让补全随 shell 自动加载
source 只对当前终端会话有效。官方文档给出了一次性写入 rc 文件的做法,使之后每次打开的 Bash 终端自动具备补全能力:
$ echo "source ~/.llama-completion.bash" >> ~/.bashrc
也可以把该行加入 ~/.bash_profile。写入后新开一个终端即可验证:输入 llama-server -- 按 Tab 应能列出服务端参数。
三、--completion-bash 的源码实现剖析
3.1 参数注册与分发路径
--completion-bash 作为通用参数注册在参数解析库中,见 common/arg.cpp:
add_opt(common_arg(
{"--completion-bash"},
"print source-able bash completion script for llama.cpp",
[](common_params & params) {
params.completion = true;
}
));
该参数属于通用参数(common options),因此所有链接了 common 解析器的工具都具备它。参数被识别后的分发逻辑在 common/arg.cpp:
if (ctx_arg.params.completion) {
common_params_print_completion(ctx_arg);
exit(0);
}
这里有两个值得注意的实现细节:
- 先完整解析参数,再判断是否需要打印补全。也就是说解析流程会先走一遍常规路径,确认参数合法后才进入补全分支,保证脚本内容与当前二进制实际注册的参数完全一致;
- 打印脚本后直接
exit(0),不会加载模型、初始化后端或做任何推理相关工作。整个动作只是向 stdout 输出纯文本,这也是重定向到文件可行、且执行瞬间完成的原因。
3.2 生成的补全脚本结构
核心生成函数是 common_params_print_completion,位于 common/arg.cpp。它并非输出一份静态文本,而是根据当前二进制实际注册的所有参数动态拼装一份 Bash 函数。生成逻辑分三步:
第一步:按类别归集参数。 遍历上下文中注册的全部选项,按四个维度分组(common/arg.cpp):
is_sampling的采样类参数;is_spec的投机解码类参数;in_example(ctx_arg.ex)命中的、当前示例(即当前可执行文件)专用的参数;- 其余的通用参数。
这四个分组与 --help 打印 usage 时的分组逻辑一致。由于"当前示例专用参数"这一维度依赖于你运行的是哪个二进制,llama-cli --completion-bash 生成的脚本会包含 CLI 专属参数,而 llama-server --completion-bash 生成的则包含服务端专属参数——参数列表因工具而异,这是动态生成的直接结果。
第二步:拼装 _llama_completions 函数。 生成的函数遵循 Bash 标准补全协议,其骨架(由源码逐行 printf 输出)如下:
_llama_completions() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="...(所有已注册参数的短名与长名)..."
case "$prev" in
--model|-m)
COMPREPLY=( $(compgen -f -X '!*.gguf' -- "$cur") $(compgen -d -- "$cur") )
return 0
;;
--grammar-file)
COMPREPLY=( $(compgen -f -X '!*.gbnf' -- "$cur") $(compgen -d -- "$cur") )
return 0
;;
--chat-template-file)
COMPREPLY=( $(compgen -f -X '!*.jinja' -- "$cur") $(compgen -d -- "$cur") )
return 0
;;
*)
COMPREPLY=( $(compgen -W "${opts}" -- "$cur") )
return 0
;;
esac
}
其中:
cur/prev分别取自COMP_WORDS数组的当前词与前一词,是 Bash 程序化补全的通用写法;opts字符串由所有参数的所有写法拼成——源码对每个common_arg会遍历其args列表逐个输出(common/arg.cpp),因此短选项(如-m)和长选项(如--model)都在候选之列;- 默认分支
*)用compgen -W "${opts}"按已输入前缀过滤参数名,实现"输入--后 Tab 列出全部参数"的基本体验。
第三步:按文件扩展名过滤的参数级补全。 上面 case "$prev" 部分是脚本中最有价值的细节——它识别"前一个词是哪个参数",从而对参数取值做类型感知的补全:
| 前一个词(待填取值的参数) | 补全策略 | 含义 |
|---|---|---|
--model 或 -m |
compgen -f -X '!*.gguf' |
只列出 *.gguf 文件,同时保留目录补全 |
--grammar-file |
compgen -f -X '!*.gbnf' |
只列出 *.gbnf 语法文件 |
--chat-template-file |
compgen -f -X '!*.jinja' |
只列出 *.jinja 聊天模板文件 |
这与 llama.cpp 的资源约定完全对应:模型权重是 .gguf 格式、约束语法是 .gbnf(仓库的 grammars/ 目录存放的即此类文件)、聊天模板是 .jinja(对应 models/templates/ 目录)。因此补全后你输入 --model ./m + Tab,弹出的正是本地 gguf 模型列表,而不是满屏无关文件。
3.3 哪些可执行文件被纳入补全范围
生成的脚本末尾会为一批可执行文件注册同一个补全函数。源码中维护了一个硬编码的名单(common/arg.cpp):
std::set<std::string> executables = {
"llama-batched",
"llama-bench",
"llama-cli",
"llama-completion",
"llama-server",
"llama-quantize",
"llama-imatrix",
"llama-mtmd-cli",
"llama-tts",
// ... 其余工具
};
for (const auto& exe : executables) {
printf("complete -F _llama_completions %s\n", exe.c_str());
}
当前名单共包含 45 个可执行文件,覆盖推理(llama-cli、llama-completion、llama-parallel)、服务端(llama-server)、评测(llama-bench、llama-batched-bench、llama-perplexity)、量化与矩阵(llama-quantize、llama-imatrix、llama-cvector-generator)、状态管理(llama-lookup 系列、llama-save-load-state)、多模态(llama-mtmd-cli)等全部主要工具类别。
由于所有工具注册到的是同一个 _llama_completions 函数,一次 source 即可让名单内全部命令共享补全能力,无需为每个工具分别配置。也正因为名单是在源码中硬编码的,从源码结构看,后续新增的命令行工具需要同步加入该集合才能被生成脚本覆盖——如果某个工具名按 Tab 无反应,可优先检查它是否在该名单内。
四、使用注意事项与适用前提
- 仅支持 Bash。文档明确限定了适用范围,仓库中没有提供 zsh、fish 等 shell 的对应生成逻辑;zsh 用户可自行基于同一脚本改造(例如用
compdef注册_llama_completions),但这属于文档范围之外的自行为。 - 脚本内容与二进制版本绑定。参数列表来自二进制的运行时注册表,llama.cpp 迭代较快,参数增删频繁。升级
build/下的构建产物后,建议重新执行一次--completion-bash重定向,避免旧脚本中残留已删除的参数或遗漏新参数。 - 不同二进制生成的选项集不同。如 3.2 节所述,
in_example过滤使脚本携带了生成它的工具专属参数。文档以llama-cli为例只是惯例选择;若你主要使用llama-server,用build/bin/llama-server --completion-bash生成脚本可以让服务端的专属参数也进入候选列表。 - 补全不校验取值合法性。
--model之后只按扩展名过滤文件,文件存在但不一定是当前架构支持的模型,加载阶段的错误检查依然由推理引擎负责。
五、延伸阅读
- 原始文档:docs/completions.md(本文主线,Bash 补全的最小操作指南);
- 参数实现:common/arg.cpp 中
common_params_print_completion(L1004–L1114)、--completion-bash注册(L1467–L1473)与分发逻辑(L1302–L1305); - 各工具的参数表:tools/cli/README.md、tools/server/README.md,可对照确认某个参数是否会在补全候选中出现;
- 补全过滤所依赖的资源格式:GBNF 语法示例见 grammars/ 目录,Jinja 聊天模板见 models/templates/ 目录。
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