vllm: serve models from the model list (nvidia/radeon-style), model_id optional

vLLM now works like the in-process engines: tag a model entry with backend:vllm and it's
served by its own path, under its own name (VllmBackend uses the requested model name as
--served-model-name, resolved from models.json). vllm.model_id/model_path are optional
(single-model convenience only); default blank -> no synthetic /v1/models entry, no alias
auto-routing, pin-only. Docs + admin card updated to reflect the model-list flow.
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mw2KQiswmD69T45fTfjKwW
parent 4223107e
......@@ -4014,7 +4014,7 @@ async def api_save_settings(request: Request, username: str = Depends(require_ad
v.enabled = bool(d.get("enabled", v.enabled))
if "venv" in d: v.venv = (d.get("venv") or "").strip()
if "model_path" in d: v.model_path = (d.get("model_path") or "").strip()
if "model_id" in d: v.model_id = (d.get("model_id") or v.model_id or "vllm").strip()
if "model_id" in d: v.model_id = (d.get("model_id") or "").strip()
if "gpu" in d: v.gpu = (d.get("gpu") or "").strip()
if "host" in d: v.host = (d.get("host") or "127.0.0.1").strip()
if "port" in d:
......
......@@ -768,13 +768,13 @@
</div>
<div id="vllm-fields" style="display:none">
<div class="form-group">
<label class="form-label">Model id (alias + --served-model-name)</label>
<input type="text" id="s-vllm-model-id" class="form-input" placeholder="vllm">
<span class="form-hint">This id routes to vLLM. Also matched by any model whose config <code>backend</code> is <code>vllm</code>.</span>
<label class="form-label">Model id <span class="muted">(optional — leave blank to serve models from the list)</span></label>
<input type="text" id="s-vllm-model-id" class="form-input" placeholder="(blank = per-model)">
<span class="form-hint">Leave blank and tag models in the <b>Models</b> list with <code>backend: vllm</code> (like nvidia/radeon) — vLLM serves each by its own path. Set an id/path only to serve a single model that has no list entry.</span>
</div>
<div class="form-group">
<label class="form-label">Model path (HF dir or repo id)</label>
<input type="text" id="s-vllm-model-path" class="form-input" placeholder="/nvme/Qwen3-8B or Qwen/Qwen3-8B">
<label class="form-label">Model path <span class="muted">(optional single model)</span></label>
<input type="text" id="s-vllm-model-path" class="form-input" placeholder="(blank = use the model list)">
</div>
<div class="form-group">
<label class="form-label">GPU(s) <span class="muted">(CUDA_VISIBLE_DEVICES; blank = all NVIDIA)</span></label>
......@@ -1646,7 +1646,7 @@ async function loadSettings(){
// vLLM
const vll = d.vllm || {};
document.getElementById('s-vllm-enabled').checked = !!vll.enabled;
document.getElementById('s-vllm-model-id').value = vll.model_id ?? 'vllm';
document.getElementById('s-vllm-model-id').value = vll.model_id ?? '';
document.getElementById('s-vllm-model-path').value = vll.model_path ?? '';
document.getElementById('s-vllm-gpu').value = vll.gpu ?? '';
document.getElementById('s-vllm-ctx').value = vll.ctx ?? 32768;
......@@ -1825,7 +1825,7 @@ async function saveSettings(){
},
vllm:{
enabled: document.getElementById('s-vllm-enabled').checked,
model_id: document.getElementById('s-vllm-model-id').value.trim() || 'vllm',
model_id: document.getElementById('s-vllm-model-id').value.trim(),
model_path: document.getElementById('s-vllm-model-path').value.trim(),
gpu: document.getElementById('s-vllm-gpu').value.trim(),
ctx: parseInt(document.getElementById('s-vllm-ctx').value) || 32768,
......
......@@ -71,9 +71,13 @@ class VllmBackend(ModelBackend):
if _ctx > 0:
self._ctx = _ctx
model_path = self._resolve_model_dir(model_name)
# Per-model: serve each model-list entry under ITS OWN name (like nvidia/radeon),
# not a single engine-wide model_id. Fall back to the config model_id only for the
# single-model convenience (a model with no list entry).
self._served_name = (model_name or getattr(self._cfg, "model_id", "") or "vllm")
_resolved, self._svc_key = vllm_worker.resolve_service_key(self._cfg, model_path)
self._url = vllm_worker.ensure_service(self._cfg, model_path=model_path)
self._served_name = getattr(self._cfg, "model_id", "vllm") or "vllm"
self._url = vllm_worker.ensure_service(self._cfg, model_path=model_path,
served_name=self._served_name)
def _resolve_model_dir(self, model_name: str) -> Optional[str]:
"""Resolve the requested model to an HF model dir / id for vLLM."""
......
......@@ -526,14 +526,19 @@ class VllmConfig:
vLLM pins its own torch/CUDA (e.g. torch 2.13 / cu13), which conflicts with the main
coderai venv, so it runs in an ISOLATED venv (``venv``; blank → baked
/opt/coderai/vllm_venv, else the /cache mount, else ~/.coderai/vllm_venv), built from
requirements-vllm.txt. Selected PER MODEL via a ``backend: "vllm"`` pin or the
``model_id`` alias — never by a broad name marker (it would collide with every engine).
requirements-vllm.txt.
Like the nvidia/radeon engines, vLLM serves MODELS FROM THE MODEL LIST: tag a model
entry with ``backend: "vllm"`` and vLLM serves that model using its own ``path`` (each
served under its own name). ``model_id``/``model_path`` below are OPTIONAL — only a
convenience for serving a single model that has no model-list entry (ds4/kt style), and
the OCR subsystem passes its own model. Leave ``model_id`` blank for the model-list flow.
Also reused by the OCR subsystem to serve Surya2 (a VLM) with continuous batching.
"""
enabled: bool = False
venv: str = "" # isolated venv dir; blank = auto (baked/cache/home)
model_path: str = "" # HF model dir or repo id (--model)
model_id: str = "vllm" # id/alias that routes to vllm (and --served-model-name)
model_path: str = "" # OPTIONAL single-model HF dir/repo id (--model); blank = use the model list
model_id: str = "" # OPTIONAL single-model alias/served-name; blank = per-model from the list
gpu: str = "" # CUDA device(s) for this vLLM instance (CUDA_VISIBLE_DEVICES,
# e.g. "0" or "0,1"); blank = all visible NVIDIA GPUs. CUDA-only.
host: str = "127.0.0.1"
......
......@@ -5204,10 +5204,14 @@ class MultiModelManager:
mid = getattr(kt_cfg, "model_id", "ktransformers") or "ktransformers"
_add(mid, "text", {"backend": "kt"})
# vLLM serves models from the model list (backend:vllm entries already surface
# via the normal path). Only add a synthetic entry when a single model_id is
# explicitly configured (the ds4/kt-style single-model convenience).
vllm_cfg = get_active_vllm_config()
if vllm_cfg is not None and getattr(vllm_cfg, "enabled", False):
mid = getattr(vllm_cfg, "model_id", "vllm") or "vllm"
_add(mid, "text", {"backend": "vllm"})
mid = (getattr(vllm_cfg, "model_id", "") or "").strip()
if mid:
_add(mid, "text", {"backend": "vllm"})
return models
......
......@@ -11,6 +11,15 @@
> Engine layering: nvidia/cuda/vulkan/opencl are **in-process base engines**; vLLM (like
> ds4/colibri/k3/kt) is a **managed external engine** — it must be out-of-process because
> it pins its own torch/CUDA (torch 2.13 / cu13) that conflicts with the main venv.
>
> **Use it like nvidia/radeon — from the model list.** Tag a model entry with
> `backend: vllm` and vLLM serves *that* model using its own `path`, each under its own
> name; multiple models can be tagged (they swap on the GPU via normal VRAM eviction). The
> `vllm.model_id`/`vllm.model_path` config fields are OPTIONAL — only for serving one model
> with no list entry (ds4/kt style). Engine-level config (`venv`, `gpu`, `ctx`,
> `gpu_memory_utilization`, `tensor_parallel_size`, `dtype`, `quantization`, `auto_build`)
> applies to whatever model it serves. `gpu` → `CUDA_VISIBLE_DEVICES` pins the card(s);
> CUDA-only.
## Why add vLLM
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment