Adding an engine
This page describes how to add a launch backend, so that kllm serve --engine NAME
starts another inference engine. kLLM 0.1.0.dev0 supports two engines, sglang and
vllm, defined in src/kllm/backends/launch.py.
What an engine must provide
kLLM does not patch or wrap the engine. An engine can serve sealed models without changes if it meets these conditions.
It loads a Hugging Face checkpoint directory with its stock model class for the architecture. Sealed checkpoints keep the tensor names, shapes and dtypes of the original.
It accepts a tokenizer directory separate from the model directory, because the permuted tokenizer of a sealed LLM is decrypted into its own directory under
/dev/shm.For client-keyed mode, it starts without a tokenizer and takes and returns token ids over HTTP.
It is started as a single foreground process that kLLM can execute in place of itself.
How an engine is launched
cmd_serve in src/kllm/cli.py builds a LaunchSpec and passes it to
exec_server(), which replaces the kllm process with the engine through
os.execvpe. LaunchSpec.argv() holds all engine-specific logic:
Field |
|
|
|---|---|---|
Base command |
|
|
Tensor parallelism |
|
|
Tokenizer |
|
|
Diffusion pipelines |
|
refused ( |
Host and port |
|
|
<python> is the running interpreter (sys.executable) and <bin> its directory:
_tool(name) resolves a console script installed next to the interpreter, so the engine
always comes from the same environment as kLLM. After the base command, argv() appends
the recipe’s arguments and then the user’s passthrough arguments, so the user always has
the last word.
When LaunchSpec.command is set (client-keyed Z-Image), argv() runs that command with
--host, --port and the extra arguments, and no engine is involved.
Procedure
Register the name. Add the engine to
ENGINESinsrc/kllm/backends/launch.py. The--enginechoices of kllm serve, kllm unlock and kllm client proxy are taken from this tuple.ENGINES = ("sglang", "vllm", "newengine")
Render the command line. Add a branch to
LaunchSpec.argv()that maps the model, the tensor-parallel size andspec.tokenizeronto the engine’s own flags. Keep the common tail unchanged: host and port, recipe arguments, thenextra_args. If the engine cannot serve diffusion pipelines, raiseValueErrorwhenspec.diffusionis set, as the vLLM branch does.Check keyed serving.
Provider.prepare_servesets onlyspec.tokenizerfor thel1scheme, so no change is needed there if step 2 passes the tokenizer. MiniMax H3 pipelines are served with SGLang only, andprepare_serverefuses other engines for them.Support client-keyed mode.
Provider.prepare_client_serveprepends--skip-tokenizer-initto the engine arguments of an LLM. If the new engine spells this option differently, handle it there. On the user’s side,src/kllm/keyed/client/llm.pydefines oneEnginesubclass per engine (SGLangposts to/generate,VLLMto/v1/completions) and maps names to classes in its ownENGINESdictionary. Add a subclass whoserun()sends token ids with the sampling parameters and stop ids, and yieldsStepobjects with the new output ids, the finish reason and the usage counts. Engine-specific endpoints of the proxy are guarded byclient.engine.nameinsrc/kllm/keyed/client/proxy.py.Leave recipes alone, or add them separately.
cmd_serveconsults recipes only when--engine sglangis given, because every built-in recipe was measured on SGLang. Recipes for another engine need a change to that condition and their own measurements; see Contributing a serving recipe.Add tests.
tests/test_cli.pyshows the pattern: monkeypatch the GPU inventory, runcli.main([... "--dry-run"])and assert on the printed command line.test_tokenizer_flag_per_enginechecks the tokenizer flag of each engine directly onLaunchSpec:def test_newengine_flags(): spec = LaunchSpec(model="m", tp=2, tokenizer="/dev/shm/t", engine="newengine") argv = spec.argv() assert argv[argv.index("--tokenizer") + 1] == "/dev/shm/t"
Measure. Serve a supported model plain and sealed on the new engine with
benchmarks/llm.shand report the result in the pull request. For the client-keyed path,benchmarks/client.shdrives the proxy. See Benchmarking plain and sealed serving.
Checking the result
kllm serve --dry-run prints the command line without starting the engine:
$ kllm serve Qwen/Qwen3-8B --engine newengine --dry-run
$ kllm serve ./Qwen3-8B-sealed --key --engine newengine --dry-run -- --some-engine-flag
The second command unlocks the key and decrypts the tokenizer into /dev/shm before it
prints the command line; remove the directory afterwards.
Note
benchmarks/llm.sh and benchmarks/client.sh know the engines of 0.1.0.dev0 only.
A new engine needs its own branch in each script, for its server flags, its health
endpoint and its load generator.
See also
Architecture overview for the launch layer.
Serving for the user’s view of engines.
Contributing a serving recipe for engine-specific recipes.