I ported vLLM's serving stack to C++20: 66 MiB binary, no Python at inference, output checked token-for-token against vLLM
▲ 321 r/LocalAIStack+3 crossposts

I ported vLLM's serving stack to C++20: 66 MiB binary, no Python at inference, output checked token-for-token against vLLM

I'm the author, so discount the enthusiasm accordingly. This is an unaffiliated community port, not endorsed by the vLLM project, which it uses to verify its correctness.

What started it: I love vLLM, but a vLLM install here is 9.1 GiB of virtualenv, and I wanted to embed inference inside other software, on machines where having an interpreter in the process is a problem. And, honestly, Python dependencies have a different deployment story, in term of security (supply chain attacks), and bloat of Python itself. So vllm.cpp is vLLM's serving stack written from scratch in C++20. Nome TBD yet, calling it vllm.cpp until I have a better name.

Continuous batching, block-paged KV, automatic prefix caching, speculative decoding, an OpenAI-compatible server. It builds to a 66 MiB binary with no Python and no PyTorch at runtime.

The gate matters more to me than the size does. Every architecture is checked token-for-token against a pinned vLLM oracle on the same workload, and upstream's own test module gets ported in the same commit as the code. The ids have to match. 25 or so architectures so far. And yes, this project does extensive use of AI. I'm prepping follow-ups on how this is architectured (this is a port, which in some parts deviates, like support of MLX, Radix Attention, and such)

Speed, since it is the first question. You can see in the image that we are almost ties with vLLM on high concurrency. I've tested only on DGX Spark, Thor, and AGX Orin. Qwen3.6-27B NVFP4 on a DGX Spark (GB10), against vLLM in its production graphed config, medians of 3 interleaved reps, 1024 in / 128 out:

concurrency vllm.cpp vLLM ratio
1 86.05 82.32 1.045x
2 159.68 158.03 1.011x
4 292.34 290.31 1.007x
8 508.77 505.46 1.007x
16 801.76 789.16 1.016x
32 1095.01 1076.25 1.017x

Nominally ahead everywhere, but our run to run noise is 0.5% and five of those six sit inside 1.7%. That is one win at c1 and five ties, and I would rather say it than have someone work it out in the comments. Output is identical at every point. Memory is the less ambiguous axis: peak GPU 40,996 MiB against 70,531, though vLLM pre-reserves a fixed fraction up front and we allocate what the workload needs, so it is a difference in footprint rather than a cheaper KV.

Some other numbers people usually ask for: 1.18x llama.cpp's prefill on the same GGUF file on CPU aarch64 with decode a tie, 97.6% of MLX-LM warm total on an M4, and DeepSeek-V4-Flash in 2-bit GGUF on one Spark at 18.69 tok/s, which is 1.14x the fastest GGUF engine I could find for it.

Speculative decoding is in: MTP takes c1 from 9.97 to 15.10 tok/s, DFlash from 10.16 to 29.32, both landing on top of vLLM running the same speculator.

It loads safetensors and GGUF, does NVFP4, k-quants and i-quants, fp8, bf16. CUDA sm_80 through sm_121a, CPU with AVX-512 and Arm i8mm, Metal, Vulkan partially. Model list is in the repo rather than pasted here. There are also some pieces of sglang, and ideas I always wanted to see in a cpp engine, such as radix attention and LPM aware cache scheduling.

What does not work: many things have to be built yet, model architectures, hardware support, no multi-GPU on real hardware (tensor parallel is proven equal to tp=1 on CPU, I have one box), LoRA is not wired through the server, multimodal runs in the CLI and library but not over the HTTP API, no embedding or reranking models, no ROCm. It is also under heavy development, so flags and internals move between commits. There is a stable surface, which is the versioned C ABI.

Help from the community to port to new architectures is welcome!

To start with it, build is cmake and nothing else:

cmake -S . -B build && cmake --build build -j                      # CPU
cmake -S . -B build-cuda -DVLLM_CPP_CUDA=ON -DVLLM_CPP_TRITON=ON   # CUDA
cmake --build build-cuda -j

Apache 2.0. https://github.com/mudler/vllm.cpp

Benchmarks, methodology, and the rows we lose: https://github.com/mudler/vllm.cpp/blob/main/docs/BENCHMARKS.md

Happy to answer anything!

u/mudler_it — 11 days ago

I ported NVIDIA Parakeet (speech-to-text) to ggml: same output as NeMo, faster, GGUF-quantized, no Python

I ported NVIDIA's Parakeet speech-to-text models to pure C++/ggml (the engine behind llama.cpp and whisper.cpp). It runs the FastConformer TDT / CTC / RNNT / hybrid models with no Python and no PyTorch, on CPU and GPU (CUDA, HIP, Vulkan, Metal).

The goal was to match NeMo exactly, then make it deployable anywhere. Where it landed:

  • Output is byte-for-byte identical to NeMo (WER 0 on the f32/f16 path).
  • Faster than NeMo's own PyTorch runtime: up to ~5x on the larger TDT/hybrid models on GPU, up to ~1.86x on CPU when quantized, and about 2x less memory.
  • Around 600x realtime on GPU on a 23s clip (one hour of audio in roughly 6 seconds).
  • Quantized GGUF for every variant: f16, q8_0, q6_k, q5_k, q4_k.

https://preview.redd.it/t33li6b5aj4h1.png?width=1600&format=png&auto=webp&s=e50eaf8e1e3ba22314ad25586ec40ec613154b23

It also does cache-aware streaming with real-time end-of-utterance, word-level timestamps with confidence, and exposes a small flat C-API so you can embed it pretty much everywhere. The GGUF is self-contained: the tokenizer/vocab is baked into the model file, no external files needed.

It ships as a backend in LocalAI too, so you get an OpenAI-compatible /v1/audio/transcriptions endpoint fully local. (Disclosure: I work on LocalAI.)

https://reddit.com/link/1tt6oja/video/nxngb7x1aj4h1/player

Links:

All credit to NVIDIA for the Parakeet models and to ggml for the runtime. Benchmarks, methodology, and per-model plots are in the repo. Happy to answer questions about the port, the decoders, or the numbers.

reddit.com
u/mudler_it — 3 months ago

A few weeks ago I shipped vibevoice.cpp, a pure-C++ ggml port of Microsoft
VibeVoice (the speech-to-speech model with voice cloning, https://github.com/microsoft/VibeVoice). Wanted to post a follow-up here because we're at a point where the engine has grown well past "first-pass port" and into something other people might actually want to run.

This work was brought to you with <3 from the LocalAI team!

What it does:

  • TTS with pre-converted voice prompts (any of upstream's .pt voices, ours or yours converted via scripts/convert_voice_to_gguf.py): give it a 30s reference clip, generate 24kHz speech in the cloned voice. Ships pre-converted GGUFs (0.5B realtime model) on https://huggingface.co/mudler/vibevoice.cpp-models
  • Long-form ASR with speaker diarization : 7B-parameter model, returns
  • JSON segments {start, end, speaker, content}. Tested up to 17 minutes
  • audio in one shot.

Backends: CPU (CPU-only baseline), CUDA, Metal, Vulkan, hipBLAS via ggml's
backend dispatch. Single binary or libvibevoice.so + flat C ABI for embedding (purego/cgo/dlopen-friendly).

Numbers:

                               Inference   RTF    Peak RSS
68s sample, CUDA Q4_K (GB10):  28 s       0.41   ~6 GB
68s sample, CPU  Q4_K (R9):    150 s      2.20   ~8 GB
17min audio, CPU Q8_0:         1929 s     1.94   ~26 GB

Compared to upstream Microsoft Python + Transformers + vLLM plugin:

  • Same Qwen2.5 7B/0.5B backbone, same DPM-Solver diffusion head, same windowed prefill (5 text tokens / 6 speech frames per the mlx-audio pattern).
  • Closed-loop TTS→ASR test asserts 100% source-word recall on a fixed seed; runs in CI.
  • No Python at inference, no vLLM, no torch.

Limitations / honest:

  • 17min audio peak is still 26 GB on CPU because of the encoder activation pool + 14 GB Q8_0 weights. Q4_K cuts the model side (~10 GB on disk), but the encoder pool needs its own work.
  • The diffusion head builds 20 small graphs per latent frame; graph reuse there is the next obvious win.
  • No streaming output yet. emits a complete WAV / full transcript.
  • ASR transcript quality is what upstream gives you; on a 17min Italian audio the recovered transcript is faithful through natural sentence boundaries.

Repo: https://github.com/mudler/vibevoice.cpp (MIT)

Models: https://huggingface.co/mudler/vibevoice.cpp-models

LocalAI integration: This work was done with <3 from the LocalAI team. vibevoice.cpp is already a backend which can be used ready-to-go in LocalAI !

Happy to answer questions and feedback!

u/mudler_it — 4 months ago

Quick follow-up on APEX, the MoE-aware mixed-precision quant strategy. The original post was just about Qwen 3.5 35B-A3B ( https://www.reddit.com/r/LocalLLaMA/comments/1s9vzry/apex_moe_quantized_models_boost_with_33_faster/ ); since then the collection has grown to 30+ MoEs across most major families. Plus a new ultra-compressed tier landed.

Feedback so far

The reports coming back have been honestly better than I expected!

  • Long context holds up. People report APEX I-Balanced and I-Compact retaining coherence well past 32k tokens on the 30-50B-class MoEs, even at sizes where uniform Q4_K starts visibly degrading. The hypothesis: keeping shared experts and edge layers high-precision (where rare/long-range tokens get routed and embedded) preserves the long-context behavior that aggressive uniform quants tend to break. Numbers back this up by having by far best KL99% value across other models
  • Coding quants punch above their size. Qwen3.6 35b a3b users in particular have been flagging that I-Compact and I-Mini stay surprisingly close to F16 on real code tasks vs the size class would suggest.

Thanks to everyone reporting back, that's what justifies pushing further on the low-bit tiers below.

Models added since the first post

Grouped by family, most are 30-70B-class MoEs that fit one consumer GPU at I-Mini/I-Compact:

Qwen lineage

  • Qwen 3.5 122B-A10B, Qwen 3.5 397B-A17B, Qwen3.5 Claude-Distilled, Qwen3.5 Fernflower (uncensored), Qwen3.5 TQ
  • Qwen 3.6 35B-A3B, +heretic, +Claude 4.6 distill, +Claude 4.7 distill
  • Qwen3-Coder 30B, Qwen3-Coder Next

Frontier-size MoEs (rented Blackwell to quantize)

  • MiniMax-M2.5, MiniMax-M2.7 — 228B / 24B active, the biggest yet
  • Mistral-Small 4 119B-2603
  • NVIDIA Nemotron-3-Super 120B-A12B
  • GLM-4.7 Flash, Step-3.5 Flash
  • Nemotron-3-Nano 30B-A3B, Nemotron-3-Nano-Omni Reasoning — multimodal (vision + audio + text)
  • Holo3 35B-A3B
  • Huihui3.5 67B-A3B

Hybrid Mamba / SSM MoEs

  • Nemotron-3-Nano 30B-A3B, Nemotron-3-Nano-Omni Reasoning — multimodal (vision + audio + text)
  • Holo3 35B-A3B
  • LFM2 24B-A2B

Gemma 4 family

  • gemma-4 26B-A4B-it (just re-quantized today with Google's updated chat template), +Claude Opus distill, +heretic, Gemopus-4 Preview

Community MoE merges

  • Carnice MoE 35B-A3B, Carnice-Qwen3.6, Qwopus MoE 35B-A3B

New tier: I-Nano (IQ2_XXS)

Pushes mid-layer routed experts down to 2.06 bpw, near-edge to IQ2_S, edges to Q3_K, shared experts at Q5_K. About 20% smaller than I-Mini, viable only on MoE thanks to sparse per-token expert activation. Requires imatrix.

Examples:

  • Qwen 3.5 35B-A3B: I-Mini 13 GB → I-Nano 11 GB
  • Nemotron Omni 30B: I-Mini 18 GB → I-Nano 17 GB (less savings — denser shared expert)

Links

If you've used APEX quants and have feedback, comments welcome!

u/mudler_it — 4 months ago