大模型推理框架 llama.cpp 开发流程与常用函数解析
本文介绍了 llama.cpp 高性能推理框架的核心架构与开发流程。涵盖从模型加载、上下文初始化到 Token 预测采样的完整链路。详细解析了 llama_init_from_gpt_params、llama_decode、llama_sampling_sample 等关键 API 的使用场景。补充了编译构建步骤及参数调优建议,帮助开发者在本地设备实现大模型私有化部署与推理应用。

本文介绍了 llama.cpp 高性能推理框架的核心架构与开发流程。涵盖从模型加载、上下文初始化到 Token 预测采样的完整链路。详细解析了 llama_init_from_gpt_params、llama_decode、llama_sampling_sample 等关键 API 的使用场景。补充了编译构建步骤及参数调优建议,帮助开发者在本地设备实现大模型私有化部署与推理应用。

llama.cpp 是一个高性能的 CPU/GPU 大语言模型推理框架,适用于消费级设备或边缘设备。开发者可以通过工具将各类开源大语言模型转换并量化成 gguf 格式的文件,然后通过 llama.cpp 实现本地推理。对于中小型研发企业而言,相较于动辄千万级的硬件投入,使用 llama.cpp 可能是唯一可行的产品落地方案。项目通常需要具备在垂直领域落地的能力,且大多数情况下需要支持私有化部署。
本文基于 llama.cpp 较新版本(参考代码 examples/main.cpp)进行讲解。由于作者 Georgi Gerganov 更新较快且官方文档相对简略,学习曲线较为陡峭。本文旨在介绍如何使用 llama.cpp 进行推理和介绍重点函数,帮助开发人员入门。
在使用 llama.cpp 之前,首先需要完成环境的搭建与编译。
通过 Git 克隆官方仓库:
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
根据操作系统不同,可能需要安装相应的依赖库。例如在 Ubuntu 上:
sudo apt-get install build-essential cmake git libboost-all-dev
使用 CMake 进行编译,默认会生成 main 可执行文件:
mkdir build && cd build
cmake ..
cmake --build . --config Release
若需启用 GPU 加速(如 CUDA),可在 cmake 命令中添加 -DGGML_CUDA=ON 参数。
编译完成后,生成的可执行文件位于 build/bin/ 目录下。
以常见的交互推理为例,程序逻辑主要包含五个子功能模块。
初始化阶段负责加载模型权重并创建推理上下文。这是最关键的一步,决定了后续推理的性能上限。
llama_backend_init() 初始化底层后端。接收用户的文本信息。大语言模型本质是对人类文本信息的分析和理解。在实际开发中,系统提示词(System Prompt)与用户输入通常在概念上有所区分,但在程序处理过程中可以合并处理。
现代模型大多没有明确定义的编码器(encoder),因此通常直接对文本进行分词处理。如果模型支持 encoder-decoder 架构,则需要先调用 llama_encode。
这是大语言模型的核心能力之一。它需要分析上下文(系统提示词、用户输入、已推理的内容)再进一步完成下一个词语(token)的预测。
核心函数为 llama_decode。该函数接受一个 batch 数据,计算当前 token 的概率分布。需要注意的是,每次推理都有一个处理数量限制(n_batch),主要是为了防止一次性输入内容过多导致系统长时间无响应。如果推理的上下文长度超限,超出部分会被丢弃。
从分析预测的结果中随机选择一个 token,并将它作为输入反向发送给分析预测模块继续进行,直到输出结束(EOS)。
采样过程涉及温度(temperature)、Top-K、Top-P 等参数控制。每次采样生成 1 个 token,写进 embd 向量,然后再次进入 decode 循环。这个过程和分析预测交替进行,直到遇到 eos-token。
严格说不属于大模型核心,但是完成用户交互必须模块。从产品设计上,可以选择逐字输出(token-by-token)或者一次性输出(token-by-once)。逐字输出能提供更好的用户体验,但需要处理网络延迟和渲染问题。
全局参数结构体 gpt_params 主要用于接收用户输入和后续用来初始化模型与推理上下文。
gpt_params params;
系统初始化函数:
llama_backend_init();
llama_numa_init(params.numa);
系统资源释放函数:
llama_backend_free();
创建模型和推理上下文:
llama_init_result llama_init = llama_init_from_gpt_params(params);
llama_model *model = llama_init.model;
llama_context *ctx = llama_init.context;
如果需要更精细的控制,可以将模型和上下文分开创建:
llama_model_params model_params = llama_model_params_from_gpt_params(gpt_params_);
llama_model *model_ = llama_load_model_from_file(param.model.c_str(), model_params);
llama_context_params ctx_eval_params = llama_context_params_from_gpt_params(gpt_params_);
llama_context *ctx_eval = llama_new_context_with_model(llama_model_, ctx_eval_params);
创建 ggml 的线程池,这个过程与模型加速密切相关:
struct ggml_threadpool * threadpool = ggml_threadpool_new(&tpp);
llama_attach_threadpool(ctx, threadpool, threadpool_batch);
对输入进行分词并转换成 token:
std::vector<llama_token> llama_tokenize(
const struct llama_context * ctx,
const std::string & text,
bool add_special,
bool parse_special = false);
获取特殊 token(如句子开始、结束等):
LLAMA_API llama_token llama_token_bos(const struct llama_model * model); // beginning-of-sentence
LLAMA_API llama_token llama_token_eos(const struct llama_model * model); // end-of-sentence
判断推理是否结束,注意这个 token 可能和 llama_token_eos 获取的不一致,建议通过专用函数判断:
bool llama_token_is_eog(const struct llama_model * model, llama_token token);
批量处理 token 并进行预测:
LLAMA_API struct llama_batch llama_batch_get_one(
llama_token * tokens,
int32_t n_tokens,
llama_pos pos_0,
llama_seq_id seq_id);
LLAMA_API int32_t llama_decode(
struct llama_context * ctx,
struct llama_batch batch);
执行采样和接收采样:
llama_token llama_sampling_sample(
struct llama_sampling_context * ctx_sampling,
struct llama_context * ctx_main,
struct llama_context * ctx_cfg,
int idx = -1);
void llama_sampling_accept(
struct llama_sampling_context * ctx_sampling,
struct llama_context * ctx_main,
llama_token id,
bool apply_grammar);
将 token 转成自然语言:
std::string llama_token_to_piece(
const struct llama_context * ctx,
llama_token token,
bool special = true);
在实际落地场景中,合理调整参数对推理效果至关重要。
设置模型能处理的最大 token 数。过大会消耗大量显存/内存,过小则无法处理长文档。建议根据业务需求动态调整,一般设置为 2048 或 4096。
每次解码处理的 token 数量。增大此值可以提高吞吐量,但会增加单次推理的延迟。通常设置为 512 或 1024。
llama.cpp 实现了上下文存储与读取。上下文切换的前提是不能换模型,且仅首次推理接收用户输入的 prompt。利用这个特性,可以实现上下文的动态切换,加快后续推理速度。
std::string path_session = params.path_prompt_cache;
std::vector<llama_token> session_tokens;
// 保存会话
llama_state_save_file(ctx, path_session.c_str(), session_tokens.data(), session_tokens.size());
// 加载会话
llama_state_load_file(ctx, path_session.c_str(), session_tokens.data(), session_tokens.size());
本文详细介绍了 llama.cpp 的基础用法、核心流程及关键 API。由于框架更新较快且缺少详尽文档,实际开发中建议结合源码 examples/main.cpp 进行调试。通过合理配置编译选项和推理参数,可以在消费级设备上高效运行大模型,满足私有化部署的需求。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online