llama.cpp 批处理推理教程:多序列并发生成的实用指南
【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp
用 llama.cpp 做本地 LLM 推理时,默认一次只服务一个请求:多用户同时提问,硬件利用率上不去,排队等待也在拉长。这篇文章带你走一遍 llama.cpp 批处理推理的最小路径——用自带的llama-batched示例让多条序列共享同一份提示词并并发生成,总吞吐量会有肉眼可见的提升,且全程只需改几个命令行参数。
为什么单序列会浪费硬件
结论先行:解码阶段每生成一个 token 都要过一次完整的 Transformer,如果每次 decode 只喂 1 个 token,矩阵运算的并行度用不满;把多个序列的 token 装进同一次llama_decode,相当于让同一次矩阵计算"顺路"处理更多请求。
一个类比:货车一趟只拉一单货和一趟装满货,跑的距离一样,但满载那趟的单位成本更低。可验证的现象是,运行结束后llama_perf_context_print打印的eval time里,每次 decode 处理的 token 数应等于并行序列数,而不是 1。
三步跑通最小批处理示例
examples/batched/下就是这个主题的最小实现,编译后即可使用。
- 克隆并构建:
git clone https://gitcode.com/GitHub_Trending/ll/llama.cpp cmake -B build && cmake --build build --config Release -j- 运行示例,
-np指定并行序列数:
./build/bin/llama-batched -m ./models/your-model.gguf -p "Hello my name is" -n 32 -np 4- 看两个输出确认生效:一是 4 段互不相同的续写(同一提示词、各自独立采样);二是结尾的
decoded X tokens in Y s, speed: Z t/s,用它对比-np 1和-np 4的t/s,即可量化批处理带来的吞吐收益(官方 README 中给出的示例输出约为 30 t/s 量级,你的硬件上数字会不同)。
🧩 先看懂这三件事,再谈调优
1) llama_batch 是一摞带"车道号"的 token。它在 include/llama.h 中定义,内容是token、pos、seq_id、logits几个平行数组——每个 token 标号属于哪条序列,调度就是往这摞 token 里按车道放数据。核心初始化只有两行:
llama_batch batch = llama_batch_init(std::max(tokens_list.size(), (size_t) n_parallel), 0, n_parallel); // 主循环中:每条序列采样 1 个新 token 后 common_batch_add(batch, new_token_id, n_cur, { i }, true);2) 提示词只算一次。源文件examples/batched/batched.cpp里,提示词 token 入批时同时挂上全部序列号,所以 KV 缓存里这份前缀被所有序列共用,不需要逐条复制;生成阶段才按序列各自分头。这也是 KV 需求量的由来:提示词长度 + (每序列生成长度 - 提示词长度) × 并行数。
3) 每条序列有独立的采样器。每个seq_id配一条llama_sampler_chain,温度、top-k 各管各的,所以各条输出不同是正常现象;日志里也能看到stream i finished逐条结束,短序列不拖长序列。
n_parallel、n_ctx 怎么配置:推荐起步值
| 参数 | 建议起点 | 作用与判断依据 |
|---|---|---|
-np(n_parallel) | 4,再试 8 | 并行序列数;每加一档对比一次t/s,不再涨就停 |
-n(n_predict) | 32 | 每条序列的总生成长度,影响 KV 需求 |
n_ctx | 按公式自动放大 | 必须 ≥n_kv_req,否则启动即报错 |
n_batch | ≥ max(n_predict, n_parallel) | 单次提交的最大 token 数 |
--kv-unified | 开启 | 所有序列共用一块 KV 缓冲,省显存 |
原则:先固定-n 32,把-np从 1 逐档加到 8,用结尾的speed一行做判断。延迟优先就取小值,吞吐优先取大值——不要凭感觉一次拉满。
⚠️ 批处理常见坑与排查
n_kv_req > n_ctx启动报错:错误信息会直接提示二选一,减-np或加大-c(n_ctx)。-np加大后速度不涨:显存带宽或容量可能已是瓶颈,回退到上一档即可,不必强求大并行。- 各序列输出差异大:预期行为,各序列独立采样;需要可复现结果时加
--top-k 1做确定性验证。 - decode 失败或 OOM:先降
n_ctx,再换量化更低的 GGUF 文件,两者都比盲目调线程数有效。
下一步往哪走
- 想模拟真实请求流量:读 examples/parallel/ 的说明,它模拟"128 个请求、8 路并发",是批处理到服务端的中间形态。
- 想直接上 HTTP 服务:看 tools/server/README.md,其中的连续批处理(continuous batching)与
-np、--kv-unified参数是同一套机制的工程化版本。 - 想读源码细节:从 examples/batched/batched.cpp 的主循环入手,配合 include/llama.h 中
llama_batch的注释看字段含义。
具体动作:今天先跑-np 1和-np 4各一次,记下两行的t/s;再跑一次llama-parallel -np 8 -ns 128观察多请求下的分配行为;之后把注意力放在eval time与prompt eval time的占比上,它是判断瓶颈在提示词还是在解码的直接依据。
【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考