LocalAI vllm-cpp 后端完全指南:无 Python 的 vLLM C++20 移植、安装、模型与推理配置
vllm-cpp 是 LocalAI 团队基于 vLLM 用 C++20 重写的推理引擎,在推理路径上完全不依赖 Python,同样具备 continuous-batching 调度器、分页 KV 缓存与自动前缀缓存。LocalAI 通过原生 vllm-cpp 后端暴露该引擎,可加载 HuggingFace safetensors 目录或 .gguf 文件,并将聊天模板、工具调用解析与推理分段(reasoning split)全部收敛到引擎内部完成。本文以 docs/content/features/vllm-cpp.md 为主干,结合 backend/go/vllm-cpp 源码与 gallery/index.yaml 中的画廊条目,系统讲解后端的安装与硬件选型、LocalAI 内置的可直接运行模型、KV 缓存与推测解码配置要点,以及由同一后端承载的 MiniMax-H3 音视频联合生成能力。
vllm-cpp 后端是什么
vllm.cpp 是 LocalAI 团队维护的 vLLM C++20 移植:它保留了 vLLM 的核心运行时特性——连续批处理(continuous batching)、分页 KV 缓存(paged KV cache)与自动前缀缓存(automatic prefix caching),区别在于推理阶段没有任何 Python 参与,这让部署链路更简单、更可预测。
LocalAI 通过原生 vllm-cpp 后端把它接入 OpenAI 兼容 API。一个后端同时覆盖两类负载:
- 文本生成:加载 safetensors 模型目录或
.gguf文件,提供聊天 / 补全 / 流式输出、工具调用、推理分段; - MiniMax-H3 音视频联合生成:经由独立的视频引擎句柄,返回带真实 AAC 音轨的 MP4。
从 backend/go/vllm-cpp/backend.go 的实现看,该后端通过 purego 以 dlopen 方式加载引擎的稳定 C ABI(libvllm,ABI v20):
Load对应vllm_engine_load,接受.gguf文件或 HF 风格模型目录(config.json+ safetensors);context_size映射为max_model_len,options中的block_size、num_blocks、max_num_seqs决定 KV 缓存与调度准入规模;Predict对应阻塞式vllm_complete,PredictStream对应vllm_complete_stream;多个并发 gRPC 请求会持续汇入引擎共享的 AsyncLLM 调度器实现连续批处理——这正是后端内嵌base.Base而非单线程基类的原因。
聊天与工具调用与 llama.cpp 的 autoparser 走同一条代码路径:在 use_tokenizer_template: true 时,后端基于 ABI v3 聊天入口(vllm_chat / vllm_chat_stream)实现 PredictRich/PredictStreamRich,由引擎套用模型的聊天模板(GGUF tokenizer.chat_template 或 tokenizer_config.json),并自行完成工具调用触发判断、解析与推理分段。
安装后端
在任意终端执行:
local-ai backends install vllm-cpp
也可以直接在 LocalAI Web UI 的 Backends 页面点击安装。官方发布的镜像覆盖 CPU、CUDA 13、Vulkan、Metal 与 Jetson L4T 五类运行环境,按宿主机能力选择即可。
CUDA 镜像的 GPU 覆盖范围(重要前提)
当前 CUDA 镜像只为 Blackwell 系架构构建:
- x86-64:
sm_120a(RTX 50 系列、RTX PRO 6000 Blackwell)与sm_121a(GB10 / DGX Spark); - arm64:仅
sm_121a。
由于要求 CUDA 13,不存在 CUDA 12 变体。这比 vllm.cpp 上游自己构建的十种架构要窄。在 Ampere、Ada、Hopper、Jetson Orin 或 Jetson Thor GPU 上,CUDA 后端会成功安装,但第一个请求即失败,报错为 no kernel image is available for execution on the device(无可执行内核镜像)。
在架构支持放宽之前,上述旧卡的推荐方案是改装 Vulkan 或 CPU 镜像:vulkan-vllm-cpp 以完全关闭 CUDA 的方式编译,能为这些卡提供 GPU 加速路径(代价是没有 NVFP4 与 Marlin 内核)。架构下限是选择入口模型时最需要先确认的硬约束。
LocalAI 内置的现成 vllm-cpp 模型
模型画廊(见 gallery/index.yaml 中 qwen3.6-*、qwen3-coder-*、qwen3-* 系列条目)为 vllm-cpp 维护了一套精选配置。每个条目在下载时已带好引擎设置,工具调用、推理分段与推测解码开箱即用,无需手改 YAML。
| 画廊条目 | 模型 | 体量 | 硬件要求 |
|---|---|---|---|
qwen3.6-27b-nvfp4-vllm-cpp |
Qwen3.6-27B,NVFP4 | 25 GB | Blackwell GPU |
qwen3.6-27b-nvfp4-mtp-vllm-cpp |
同上,启用 MTP 推测解码 | 25 GB | Blackwell GPU |
qwen3.6-27b-nvfp4-dflash-vllm-cpp |
同上,启用 DFlash 推测解码 | 28 GB | Blackwell GPU |
qwen3.6-35b-a3b-nvfp4-vllm-cpp |
Qwen3.6-35B-A3B MoE,NVFP4 | 23 GB | Blackwell GPU |
qwen3.6-35b-a3b-nvfp4-mtp-vllm-cpp |
同上,启用 MTP 推测解码 | 23 GB | Blackwell GPU |
qwen3-coder-30b-a3b-vllm-cpp |
Qwen3-Coder-30B-A3B,bf16 | 57 GB | Blackwell GPU 或 CPU |
qwen3-4b-vllm-cpp |
Qwen3-4B,bf16 | 8 GB | CPU、Metal、Vulkan、Blackwell GPU |
qwen3-0.6b-vllm-cpp |
Qwen3-0.6B,bf16 | 1.4 GB | CPU、Metal、Vulkan、Blackwell GPU |
安装任一条目:
local-ai models install qwen3-0.6b-vllm-cpp
两个小体量 bf16 条目是"后端能跑的地方它们都能跑"的选择,包括纯 CPU 环境,因此也最适合先用来验证一次 vllm-cpp 安装是否真的能对外服务(如 gallery/index.yaml 对 qwen3-0.6b-vllm-cpp 的说明,它是一颗真实可对话、可演练工具调用与推理分段的模型,而非桩)。NVFP4 条目则需要 Blackwell 级 NVIDIA GPU,原因有二:NVFP4 在更老架构上没有对应 kernel;且 CUDA 镜像本身只针对 Blackwell 构建。
KV 缓存内存:num_blocks 不是白送的
尺寸提示:每个条目都通过 num_blocks 预留约一到四个完整上下文的 KV 缓存,这只是起点而非调优值。KV 缓存并非免费:例如 4B 条目每 token 占用 144 KiB,其 1024 个 block 意味着在权重之外还要再支付约 4.5 GB 内存。需要更高并发就调高 num_blocks,小内存机器则应调低。以 qwen3-4b-vllm-cpp 的默认配置为例(对应 gallery/index.yaml):
engine_args:
block_size: 32
# 一个完整上下文的 KV(32768 token),在该模型 144 KiB/token 下约 4.5 GB。
# 这是刻意克制的大小:该条目必须能和小机器上的其他任务共存。内存够就调大。
num_blocks: 1024
max_num_seqs: 8
为什么 27B 条目要锁定 revision
Qwen3.6-27B 系列条目将权重固定到 HuggingFace 的某个具体 commit,而不是跟随仓库默认分支。这是有意为之,在复制这些配置前值得理解。
上游仓库后来在同名下被原地重新量化,从 NVFP4 换成了 FP8 W8A8。一个只写仓库名而不写 revision 的配置,因此会解析到完全不同的权重——不同的数值精度、不同的性能,而加载过程不会报告任何变化。锁定 revision 正是保证条目可复现的手段:
artifacts:
- name: model
target: model
source:
type: huggingface
repo: unsloth/Qwen3.6-27B-NVFP4
revision: 890bdef7a42feba6d83b6e17a03315c694112f2a
同样的道理适用于任何你依赖的量化社区仓库:配置一经发布,就把权重来源锁到具体 commit 上,避免"静默换芯"。
推测解码:如何在三个 27B 变体间选择
推测解码用内存换取解码吞吐。三个 Qwen3.6-27B 条目服务的是相同权重、产出相同质量,区别只在 token 如何被"提议":
| 条目 | 方法 | 额外权重 | 额外内存 |
|---|---|---|---|
qwen3.6-27b-nvfp4-vllm-cpp |
无 | 无 | 无 |
qwen3.6-27b-nvfp4-mtp-vllm-cpp |
MTP,深度 1 | 无(草稿头随 checkpoint 自带) | 约 3.6 GB |
qwen3.6-27b-nvfp4-dflash-vllm-cpp |
DFlash,16-token 块 | 独立的 3.5 GB drafter | drafter 加草稿缓存 |
MTP(多 token 预测)从目标 checkpoint 自带的 mtp.* 张量中取草稿头,每步起草一个 token,因此不增加任何下载量。在 27B 入口上,画廊元数据记录的实测约为散文 85%、代码 92% 的草稿接受率,相对关闭推测带来约 1.5–1.6 倍解码吞吐,且并发 2/4/8 下优势仍保持(见 gallery/index.yaml)。
DFlash 从独立 drafter 出发,在一次非自回归前向中起草整块 16 个 token,再由目标单步验证整块——是更大的吞吐收益,代价是磁盘上多一个 checkpoint。画廊记录其单并发下约为关闭推测时的 2.9 倍。
务实建议:内存紧张从普通条目起步;内存宽裕直接上 DFlash 条目。DFlash 草稿与目标共享 embed_tokens 与 lm_head,两者不可独立互换,安装时会由画廊自动把 drafter 放到 models/Qwen3.6-27B-DFlash,这正是后端解析 speculative_config.model 时查找的位置。
engine_args:引擎级配置参考
上述画廊条目覆盖了常见用法;若需自行编写模型配置,完整参数参考见 text-generation 指南 的 vllm.cpp 小节。vllm-cpp 后端接受与 vLLM、SGLang 后端相同的 engine_args: 映射,键名与 vLLM 自身的 CLI 标志完全一致——因此为 vLLM 写好的 speculative_config 或 kv_transfer_config 结构可以原样使用。未知键会被忽略而不会致命;引擎会校验交给它的文档并在加载时报出精确错误。
name: qwen35-a3b
backend: vllm-cpp
parameters:
model: "Qwen/Qwen3.5-A3B"
context_size: 16384
template:
use_tokenizer_template: true
engine_args:
# KV 缓存容量:num_blocks * block_size 个 token 的缓存。
block_size: 32
num_blocks: 1024
# 并发度与每步 chunked-prefill 的 token 预算。
max_num_seqs: 32
max_num_batched_tokens: 8192
# 自动前缀缓存。省略则沿用模型自身默认
#(稠密模型默认开,hybrid/无注意力模型默认关)。
enable_prefix_caching: true
# 调度准入顺序:fcfs(默认)、priority 或 lpm
#(cache-aware 最长前缀匹配;需前缀缓存开启才生效)。
scheduling_policy: lpm
常用键速查表
| 键 | 含义 | 默认值 |
|---|---|---|
block_size |
KV 缓存块大小(token/块) | 32 |
num_blocks |
分配的 KV 缓存块数 | 256 |
max_model_len |
最大序列长度;也可用 context_size / max_model_len 设置 |
模型配置 |
max_num_seqs |
调度器准入的最大并发序列数 | 8 |
max_num_batched_tokens |
每步 chunked-prefill 的 token 预算 | 按架构(稠密 2048,MoE 4096/8192) |
enable_prefix_caching |
自动前缀缓存;enable_radix_attention 是接受的别名 |
模型默认 |
enable_jump_forward |
Jump-forward 解码:被文法强制出的 token 无需模型步进。仅影响受限请求(grammar、JSON schema) | 关 |
scheduling_policy |
fcfs、priority 或 lpm |
fcfs |
tool_parser / reasoning_parser |
强制指定解析器,而非聊天模板自动探测 | 自动 |
tokenizer_config |
覆盖读取聊天模板所用的 tokenizer_config.json |
<model_dir>/tokenizer_config.json |
speculative_config |
推测解码(见下) | 禁用 |
kv_transfer_config |
外部 KV 连接器 / LMCache | 无 |
提高 max_num_batched_tokens 能让更多 prefill 落入单步执行,代价是排在其后的请求解码延迟上升。默认值刻意不随 max_num_seqs 缩放,这是避免大并发 prefill 在 hybrid 架构上撑爆单步激活的关键设计。
enable_prefix_caching 与 enable_jump_forward 在引擎边界是三态:省略键会退化为默认(前缀缓存取模型自身能力、jump-forward 取环境变量),显式 false 则强制关闭。两者含义真实不同——前缀缓存在稠密模型上默认开——所以只在确实需要覆盖时才写该键。
推测解码的三种方法
speculative_config: 接受与 vLLM --speculative-config 相同的 JSON 对象。需要特别注意架构限制:在当前引擎 pin 下,mtp 与 dflash 仅支持 Qwen3.5 / Qwen3.6(引擎为这两个系列直接构建了加宽的推测 KV 缓存,而非经模型注册表),Llama、GLM、Gemma、Mistral 等其他架构即使换了 checkpoint 格式也无法生效;ngram 无需草稿权重,不受此限制。
MTP 使用目标 checkpoint 自带 mtp.* 张量中的草稿头,无需下载第二个模型,但要求 safetensors 格式(mtp.* 张量无法在 GGUF 转换中幸存,对 .gguf 模型配置 MTP 会在加载时被拒绝):
engine_args:
speculative_config:
method: mtp
# 可选;默认取 checkpoint 自带草稿头深度,通常即正确值。必须是该深度的倍数。
num_speculative_tokens: 1
DFlash 使用独立的分块扩散 drafter,一次非自回归前向提出整块 token。与 MTP 不同,草稿是独立 checkpoint,因此 model: 必填:
engine_args:
speculative_config:
method: dflash
model: z-lab/Qwen3.6-27B-DFlash
num_speculative_tokens: 4
草稿与目标共享 embed_tokens 与 lm_head,因此两者必须出自同一模型家族,且目标必须是 safetensors。引擎不会下载草稿:model: 依次按"原样路径 → 以最后一段作为 LocalAI models 目录下的路径(即 LocalAI 自带下载器的产物布局)→ models 目录下的完整引用"解析。请先把 drafter 安装进 LocalAI,或给出含 config.json 的目录绝对路径;全部解析失败时加载会立刻失败,并列出所有尝试过的位置,而不是在引擎内部报告一个缺失 checkpoint。
N-gram 完全不需要草稿模型——它从提示自身的后缀历史中提议:
engine_args:
speculative_config:
method: ngram
num_speculative_tokens: 4
prompt_lookup_min: 5
prompt_lookup_max: 5
此外,导入 safetensors 仓库时 LocalAI 会读取 config.json:若声明了 MTP 头(mtp_num_hidden_layers),会自动向生成的 engine_args 写入 speculative_config: {method: mtp};自己显式写的 speculative_config 永远不会被覆盖。导入 DFlash 草稿 仓库则会被拒绝并告警——drafter 无法独立服务,应导入目标模型并把 speculative_config.model 指向草稿。
外部 KV 缓存:LMCache
kv_transfer_config: 接受 vLLM --kv-transfer-config 的 JSON,选择外部 KV 缓存连接器。lm:// LMCache 客户端允许把 prefill 的 KV 存入共享的 lmcache.v1.server 并按需重载,使一个副本算出的前缀不必被下一个副本重算:
engine_args:
kv_transfer_config:
kv_connector: LMCacheConnector
kv_role: kv_both # 设置 kv_connector 时必填
kv_connector_extra_config:
host: 127.0.0.1
port: 65432
kv_role 取 kv_producer(只存)、kv_consumer(只取)或 kv_both 之一。未注册的连接器名、缺失的 role 或畸形的文档都会使加载显式失败,而不是在缺少缓存时静默运行。
兼容旧的 options: 列表写法
早期版本用扁平 options: 列表配置此后端,这些配置仍然有效——上表每个键都能以 key:value 形式从 options: 读到,且键同时出现时 engine_args 优先:
options:
- max_num_seqs:32
- enable_prefix_caching:true
新配置应优先使用 engine_args:,它是嵌套的 speculative_config / kv_transfer_config 文档唯一能被自然书写(而非挤成单行 JSON 字符串)的位置。
工具调用与引擎内解析
上表每个条目都设置 use_tokenizer_template: true 并禁用 LocalAI 的 Go 侧文法路径,因此工具调用由引擎自带的流式解析器检测与解析,最终以 OpenAI 响应中真实的 tool_calls 到达客户端。
解析器通常根据聊天模板自动探测,但有一种情况无法自动完成:Qwen3-Coder 的工具方言在线缆上与另一模型家族的字节完全相同,模板嗅探会选错解析器。因此 qwen3-coder-30b-a3b-vllm-cpp 条目显式点名解析器——任何你自行编写的 Qwen3-Coder 配置都应照做(参见 gallery/index.yaml):
engine_args:
tool_parser: qwen3_coder
画廊中大模型条目同时显式给出 reasoning_parser: think_auto,以保证推理分段(<think> 输出切分)在模板将来被上游修订后依旧可用。
超出文本生成:MiniMax-H3 音视频联合生成
vllm-cpp 后端同样服务 MiniMax-H3——从文本提示联合生成视频与音频,产出的是带真实音轨的 MP4(可在提示中要求语音,模型会做口型同步),详见 Video generation 指南。
值得注意的实现细节:视频引擎是第二个句柄(vllm_video_engine,ABI v12),而非文本引擎的一种模式。因为 H3 是一组 checkpoint(DiT、文本编码器、两个 VAE 各自独立),而 vllm.cpp 的两个加载器会互相拒绝对方的 checkpoint;Load 在模型配置携带任一视频选项时走视频分支。后端 C ABI 文档(backend/go/vllm-cpp/README.md)与画廊的 minimax-h3-fl2va-q4 条目给出了完整配置骨架:
name: minimax-h3-fl2va-q4
backend: vllm-cpp
cuda: true
known_usecases: [video]
parameters:
model: minimax-h3/MiniMax-H3-FL2VA-Q4_K_M.gguf
options:
- video_encoder:minimax-h3/qwen3vl-32B-MiniMax-H3-Q4_K_M.gguf
- video_tokenizer:minimax-h3/tokenizer.json
- video_vae:minimax-h3/video_vae.safetensors
- video_vae_config:minimax-h3/video_vae_config.json
- audio_vae:minimax-h3/audio_vae.safetensors
- audio_vae_config:minimax-h3/audio_vae_config.json
- video_partition:fl2va
- video_device:cuda
- video_dequant_bf16:true
- video_width:1344
- video_height:768
- video_num_frames:124
三条选型须知:
- partition 靠声明而非探测,且不匹配不会干净失败。 FL2VA DiT 服务
t2va(文生视频)与fl2va(首/末帧条件);ref2va是另一个 checkpoint。社区的 GGUF/NVFP4 量化剥离了发布元数据,且两个 DiT 字节结构相同,引擎会在video_partition表明身份前拒绝一切生成;后端还会在调用引擎前拒绝把参考条件送入 FL2VA DiT 的组合。 - ffmpeg 来自宿主机。 libvllm 只负责写帧与 WAV、拼装 mux 的 argv,进程边界由上游决定;后端镜像
FROM scratch且不带 ffmpeg,与vibevoice-cpp的做法一致。运行时宿主机需要提供 ffmpeg。 - 它很慢。 在 1344x768、20-SM 设备上约 176 秒/去噪步,50 步默认意味着数小时量级的任务。
另外可留意画廊元数据中的坐标约定:画布会截断到 32 像素网格、帧数落在 17n+5 网格,未指定画布而给定关键帧时按 768 短边由图片宽高比推导(MiniMaxH3ResolveShape 与 minimax_h3_planner.cpp)。
小结:如何开始
- 按宿主硬件选择镜像:Blackwell 新卡用 CUDA 13 镜像,旧卡与 Jetson 用
vulkan-vllm-cpp,无 GPU 走 CPU; local-ai backends install vllm-cpp安装后端(或 Web UI Backends 页);- 用
local-ai models install qwen3-0.6b-vllm-cpp起步验证服务,再按内存预算选择 4B bf16(通用)或 27B NVFP4 系列(Blackwell,可选 MTP/DFlash 提速); - 需要自定义配置时,以
engine_args:书写引擎参数,并牢记:KV 缓存要按并发与上下文显式预留、依赖社区量化仓库务必锁 revision、Qwen3-Coder 必须显式声明tool_parser: qwen3_coder。
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 StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00