unsloth/unsloth_cli
Daniel Han 16ec45112b
unsloth run: add --engine-parallelism and --gpus for multi-GPU serving (#13838)
Refs https://github.com/unslothai/unsloth/issues/6488

`unsloth run --engine vllm` / `--engine sglang` already serve
safetensors models, and Studio's run settings already have a "Multi-GPU
mode" with "Replicas (data parallel)". The headless one-liner had no way
to reach either: an engine load from the CLI always landed on the first
GPU only, so a 6-GPU box ran one GPU.

This adds two flags to `unsloth studio run` (and `unsloth run`):

| Flag | Sends | Notes |
|---|---|---|
| `--engine-parallelism tensor\|pipeline\|data` | `engine_parallelism` |
Same field the Studio "Multi-GPU mode" picker sends. Only valid with
`--engine vllm/sglang`. `pipeline` and `data` default to every GPU
Studio can see, since a single GPU makes them a no-op. |
| `--gpus 0,1,...` | `gpu_ids` | Same field the Studio GPU picker sends.
Works for GGUF and engine loads. |

```
# One vLLM replica per visible GPU behind one endpoint, requests spread across them
unsloth run --model unsloth/Qwen3-8B --engine vllm --engine-parallelism data

# Only GPUs 2-5
unsloth run --model unsloth/Qwen3-8B --engine vllm --engine-parallelism data --gpus 2,3,4,5

# Pin a GGUF server to one card
unsloth run --model unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q6_K_XL --gpus 3
```

## Compatibility

- Backend, frontend and the load API are untouched. The payload only
gains `engine_parallelism` / `gpu_ids` when the flags are set, so
default runs send exactly what they send today.
- The studio-venv re-exec forwards the new flags only when set, so an
older studio-venv CLI (which would hand an unknown flag to llama-server)
still sees today's argv for default runs.
- `--engine-parallelism` without `--engine` and malformed `--gpus`
(`0,x`, `0,0`, `-1`) exit 2 before anything starts.

## Not in this PR

GGUF replicas (several llama-server copies of one model on spare GPUs
behind one endpoint) are still not implemented. That needs a router plus
multi-process lifecycle in the GPU arbiter and is a separate change. For
GGUF on one host today, `--parallel N --no-kv-unified` on a single GPU
is usually the fastest option for MoE models (see the benchmark in the
issue).

## Tests

- New: payload fields, `--gpus` parsing, re-exec forwarding when set and
omission when unset, both refusals. They fail on `main` (16 failures)
and pass here.
- `unsloth_cli/tests`: 1935 passed, 4 skipped.
- Wiring check through the real backend code (CPU, two GPUs visible):
CLI payload -> `LoadRequest` -> `managed_engine.validate_load` -> vLLM
argv.

| CLI | `gpu_ids` sent | `validate_load` | vLLM argv |
|---|---|---|---|
| `--engine vllm` (today's only option) | none | `[0]` |
`--tensor-parallel-size 1` |
| `--engine vllm --engine-parallelism data` | `[0, 1]` | `[0, 1]` |
`--tensor-parallel-size 1 --data-parallel-size 2` |
| `--engine vllm --engine-parallelism data --gpus 1` | `[1]` | `[1]` |
`--data-parallel-size 1` |
2026-10-15 06:46:40 -07:00
..
commands unsloth run: add --engine-parallelism and --gpus for multi-GPU serving (#13838) 2026-10-15 06:46:40 -07:00
tests unsloth run: add --engine-parallelism and --gpus for multi-GPU serving (#13838) 2026-10-15 06:46:40 -07:00
__init__.py install-kernels: add flash-attn and install every kernel by default (#12744) 2026-10-05 19:00:03 -07:00
__main__.py Fix scanned PDF uploads with local OCR fallback (#10620) 2026-09-10 05:46:02 +03:00
_inference.py CLI: show a thinking model's reasoning with --think when attached to a running Unsloth (#11956) 2026-10-05 03:04:27 -07:00
_install_kernels.py Add unsloth install-kernels for prebuilt xformers / causal_conv1d / mamba_ssm wheels (#12732) 2026-10-05 05:38:57 -07:00
_model_catalog.py Studio: unsloth chat loads the model you picked, not another GGUF in the same folder (#10357) 2026-09-06 05:48:31 -03:00
_ssl_keylog.py Name utf-8 on the SSLKEYLOGFILE writability probe (#12190) 2026-09-28 04:13:55 -07:00
_studio_deps.py Keep the regenerable caches inside the Studio root (#10597) 2026-09-20 06:20:41 -07:00
_studio_runtime_gate.py Studio (Windows): read a runtime lock held by an elevated Unsloth process as busy, not a broken install (#13301) 2026-10-11 05:35:23 -07:00
_studio_stage.py Studio: remove the background staged desktop update and return to the classic update (#10604) 2026-09-09 05:33:48 -07:00
_system_dir_guard.py Studio: add audio.cpp as a native engine for speech, music and dictation (#12342) 2026-10-02 09:32:09 -07:00
_tool_policy.py
claude_subagent_mcp.py Studio: send routine coding work to the local model with unsloth start --auto-route (#13478) 2026-10-13 12:08:01 -07:00
codex_fallback_prompt.md fix: expose codex apply_patch for local models (#9114) 2026-08-30 12:37:23 +12:00
codex_subagent_mcp.py Studio: send routine coding work to the local model with unsloth start --auto-route (#13478) 2026-10-13 12:08:01 -07:00
config.py Studio: seed the LoRA init with the Random Seed setting (#13637) 2026-10-14 10:50:18 -07:00
options.py Trim comments in the studiobench harness and unsloth_cli (#10118) 2026-09-02 03:21:16 -07:00
pi_subagent.ts Studio: make unsloth start sampling and reasoning flags apply only to that agent (#12493) 2026-10-02 19:35:43 +08:00