feat(vllm-cpp): wire the full engine config surface through engine_args - #11159
Conversation
08b7a0c to
a8fadc5
Compare
|
Refreshed and reconciled: merged up to Pin is now master's Post-merge verification: lint clean, Still not covered: a live generation with the new knobs actually engaged (speculative decoding, LMCache, non-fcfs scheduling). Those are verified at the mapping and handshake level only. |
|
On the red DCO check: it flags three commits, all pre-dating today's refresh and all authored by Deliberately not fixing it by rebasing: that would rewrite commits already pushed to this shared branch. The plan is to squash-merge, which collapses the branch into a single commit authored and signed off by the merger and satisfies the DCO in substance. Repo settings already disallow merge commits, so squash is the path anyway. One wart to ignore: commit 578e784 is an empty DCO remediation commit I added before the app told me which commits it was actually complaining about. It is inert under a squash merge. If anyone does decide to rebase this branch instead, drop that commit first, since DCO's own guidance says an empty commit breaks the rebase remedy. |
The backend could configure four of the engine's knobs (block size, KV block
count, max sequence length, max concurrent sequences) out of a config surface
that is considerably larger. Speculative decoding, prefix caching, the
chunked-prefill token budget, the scheduling policy and the external KV
connector were reachable from vllm.cpp's own HTTP server and from nothing
LocalAI could write in a model config.
Config now goes through `engine_args:`, the same map the vLLM and SGLang
backends take, with keys spelled as vLLM's own CLI flags so a speculative_config
or kv_transfer_config block written for vLLM works verbatim. The legacy
`options:` list keeps working and reads every key too; engine_args wins where
both set one. Unknown keys are logged and ignored rather than fatal: the field
is shared with the other engines, so a config carrying their knobs must not take
the model down.
Two details worth knowing:
`enable_prefix_caching: false` maps to the ABI tri-state force-OFF (2), not 0.
0 means "let the model capability decide" and dense architectures default the
cache on, so collapsing the two would silently enable it against an explicit
false. enable_jump_forward (ABI v10) shares the encoding, deferring to
VT_ENABLE_JUMP_FORWARD instead of to the model.
The importer probes config.json on a vllm-cpp import and writes
speculative_config: {method: mtp} when the checkpoint declares an MTP head, the
safetensors analogue of the llama-cpp importer's GGUF probe. DFlash draft repos
are refused with a warning instead, since a drafter cannot serve alone and the
pairing is not derivable from either repo. The draft path is resolved against
LocalAI's model directory, because the engine only looks in a directory holding
config.json or in the HF cache and never downloads: the repo-id spelling the
vLLM docs teach used to die deep in the load with "draft checkpoint not found".
docs/content/features/text-generation.md gains a vllm.cpp section covering the
engine_args table, all three speculative methods, LMCache and the legacy list.
The backend had no documentation page before.
This replaces a branch that had gone stale behind master and carried its own
route to ABI v10, which #11386 has since landed in minimal form. Rebased onto
that as a single commit rather than replaying the intermediate steps, whose
ABI v9 mirrors no longer make sense against master's pin. The Darwin build
fixes for Apple Clang's gnu-folding-constant diagnostic on C++, Objective-C and
Objective-C++, originally authored by localai-org-maint-bot, are folded in here.
Verified: `make abi-check` agrees at v10; unit specs, core/config and
core/gallery/importers green; and the full e2e passes in 1330s against a CPU
libvllm.so reporting ABI v10 with Qwen_Qwen3.5-0.8B-Q4_K_M.gguf (load, blocking
completion, streaming, chat and tool calls).
Assisted-by: Claude:claude-fable-5 golangci-lint
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
578e784 to
4b4f9ad
Compare
|
Rebased onto current master as a single commit ( The intermediate commits were deliberately not replayed. They stepped through ABI v9 and master is now at v10 via #11386, so each replay conflicted and would have produced intermediate trees that do not build. The final tree is byte-identical to the merge-forward that was verified before the rebase: Re-verified on the rebased commit: The previous tip is kept locally as |
What
The
vllm-cppbackend could configure four of the engine's knobs — block size, KV block count, max sequence length, max concurrent sequences — out of a config surface that is considerably larger. Speculative decoding, prefix caching, the chunked-prefill token budget, the scheduling policy and the external KV connector (LMCache) were reachable from vllm.cpp's own HTTP server and from nothing LocalAI could write in a model config.Part of that gap was the C ABI itself, which carried strictly less than
EngineParamsdoes. That is fixed upstream in vllm.cpp ABI v9 (merged tomainaseec09bed, which this PR pins). The rest was here: the backend parsed a flatoptions:list with five recognised keys and had no way to express a nested JSON document at all.Configuration
Config now goes through
engine_args:— the same map the vLLM and SGLang backends already take — with keys spelled as vLLM's own CLI flags, so aspeculative_configorkv_transfer_configblock written for vLLM works verbatim:The
options:list keeps working and now reads every key too, so no existing config breaks;engine_argswins where both set the same key.All three speculative methods the engine supports are reachable:
mtp(draft head inside the target checkpoint, safetensors only),dflash(separate draft checkpoint,model:required), andngram(draft-free).Two details worth reviewer attention
enable_prefix_caching: falsemaps to the ABI tri-state force-OFF (2), not 0. 0 means "let the model capability decide", and dense architectures default the cache on — collapsing the two would silently enable it against an explicitfalse.cSamplingParamsgrows the ABI v8 logits-processor tail. LocalAI installs no processor, but the C side reads those fields off the pointer we hand it, so a Go struct that stopped atStructuredJSONObject(120 bytes vs C's 136) would have had the engine read past our allocation and call whatever sat there. Latent only because the old v5 ABI gate refused to load a v8 library.Importer
A
vllm-cppimport of a HuggingFace repo now probesconfig.jsonand writesspeculative_config: {method: mtp}into the generatedengine_argswhen the checkpoint declares an MTP head — the safetensors analogue of the llama-cpp importer's GGUF header probe. An explicitspeculative_configis never overwritten, and every probe failure is non-fatal.Two asymmetries versus the llama.cpp hook, both deliberate:
spec_type:draft-mtpwhen the chosen backend isvllm-cpp. Those are llama.cpp option keysvllm-cppdoes not read, and vllm.cpp rejects MTP over a GGUF source outright because themtp.*draft tensors do not survive GGUF conversion. This was a pre-existing bug — a GGUF import with thevllm-cpppreference emitted dead llama.cpp options.Docs
docs/content/features/text-generation.mdgains avllm.cppsection covering theengine_argstable, all three speculative methods, LMCache, and the legacyoptions:list. The backend previously had no documentation page at all.Testing
make lintclean.core/config,core/gallery/importers,backend/go/vllm-cppall green. 9 new importer specs, 11 newengine_argsspecs, plus updated struct-offset assertions for the v9 / v8 layouts.libvllm.soat the pinned commit and confirmed purego binds all 19 symbols withvllm_abi_version()returning 9. That check is now a spec: setVLLM_CPP_LIBRARYand it runs without needing model weights, so a future pin bump with a stale struct mirror fails in CI rather than at a user's first load.Re-run after the merge to
master(2026-08-05), now at ABI v10 and pin0757cac2:make lint LINT_NEW_FROM=origin/master: 0 issues.backend/go/vllm-cpp,core/config,core/gallery/importers: green.make abi-check(from fix(vllm-cpp): mirror the engine's ABI v10 so the backend loads again #11386) reports v10 on both sides, and fails as intendedagainst a header doctored to v11.
verified: full suite green in 1330s against a CPU
libvllm.soreporting ABIv10 and
Qwen_Qwen3.5-0.8B-Q4_K_M.gguf- load, blocking completion, streaming,and the chat / tool-call paths. Weights loaded, tokens generated.
Still not covered: a live generation with the new knobs actually engaged
(speculative decoding, LMCache, a non-fcfs scheduling policy). Those are verified
at the mapping and ABI-handshake level; the e2e above exercises the default path.
🤖 Generated with Claude Code