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 ...@@ -4014,7 +4014,7 @@ async def api_save_settings(request: Request, username: str = Depends(require_ad
v.enabled = bool(d.get("enabled", v.enabled)) v.enabled = bool(d.get("enabled", v.enabled))
if "venv" in d: v.venv = (d.get("venv") or "").strip() 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_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 "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 "host" in d: v.host = (d.get("host") or "127.0.0.1").strip()
if "port" in d: if "port" in d:
......
...@@ -768,13 +768,13 @@ ...@@ -768,13 +768,13 @@
</div> </div>
<div id="vllm-fields" style="display:none"> <div id="vllm-fields" style="display:none">
<div class="form-group"> <div class="form-group">
<label class="form-label">Model id (alias + --served-model-name)</label> <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="vllm"> <input type="text" id="s-vllm-model-id" class="form-input" placeholder="(blank = per-model)">
<span class="form-hint">This id routes to vLLM. Also matched by any model whose config <code>backend</code> is <code>vllm</code>.</span> <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>
<div class="form-group"> <div class="form-group">
<label class="form-label">Model path (HF dir or repo id)</label> <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="/nvme/Qwen3-8B or Qwen/Qwen3-8B"> <input type="text" id="s-vllm-model-path" class="form-input" placeholder="(blank = use the model list)">
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="form-label">GPU(s) <span class="muted">(CUDA_VISIBLE_DEVICES; blank = all NVIDIA)</span></label> <label class="form-label">GPU(s) <span class="muted">(CUDA_VISIBLE_DEVICES; blank = all NVIDIA)</span></label>
...@@ -1646,7 +1646,7 @@ async function loadSettings(){ ...@@ -1646,7 +1646,7 @@ async function loadSettings(){
// vLLM // vLLM
const vll = d.vllm || {}; const vll = d.vllm || {};
document.getElementById('s-vllm-enabled').checked = !!vll.enabled; 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-model-path').value = vll.model_path ?? '';
document.getElementById('s-vllm-gpu').value = vll.gpu ?? ''; document.getElementById('s-vllm-gpu').value = vll.gpu ?? '';
document.getElementById('s-vllm-ctx').value = vll.ctx ?? 32768; document.getElementById('s-vllm-ctx').value = vll.ctx ?? 32768;
...@@ -1825,7 +1825,7 @@ async function saveSettings(){ ...@@ -1825,7 +1825,7 @@ async function saveSettings(){
}, },
vllm:{ vllm:{
enabled: document.getElementById('s-vllm-enabled').checked, 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(), model_path: document.getElementById('s-vllm-model-path').value.trim(),
gpu: document.getElementById('s-vllm-gpu').value.trim(), gpu: document.getElementById('s-vllm-gpu').value.trim(),
ctx: parseInt(document.getElementById('s-vllm-ctx').value) || 32768, ctx: parseInt(document.getElementById('s-vllm-ctx').value) || 32768,
......
...@@ -71,9 +71,13 @@ class VllmBackend(ModelBackend): ...@@ -71,9 +71,13 @@ class VllmBackend(ModelBackend):
if _ctx > 0: if _ctx > 0:
self._ctx = _ctx self._ctx = _ctx
model_path = self._resolve_model_dir(model_name) 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) _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._url = vllm_worker.ensure_service(self._cfg, model_path=model_path,
self._served_name = getattr(self._cfg, "model_id", "vllm") or "vllm" served_name=self._served_name)
def _resolve_model_dir(self, model_name: str) -> Optional[str]: def _resolve_model_dir(self, model_name: str) -> Optional[str]:
"""Resolve the requested model to an HF model dir / id for vLLM.""" """Resolve the requested model to an HF model dir / id for vLLM."""
......
...@@ -526,14 +526,19 @@ class VllmConfig: ...@@ -526,14 +526,19 @@ class VllmConfig:
vLLM pins its own torch/CUDA (e.g. torch 2.13 / cu13), which conflicts with the main 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 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 /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 requirements-vllm.txt.
``model_id`` alias — never by a broad name marker (it would collide with every engine).
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. Also reused by the OCR subsystem to serve Surya2 (a VLM) with continuous batching.
""" """
enabled: bool = False enabled: bool = False
venv: str = "" # isolated venv dir; blank = auto (baked/cache/home) venv: str = "" # isolated venv dir; blank = auto (baked/cache/home)
model_path: str = "" # HF model dir or repo id (--model) model_path: str = "" # OPTIONAL single-model HF dir/repo id (--model); blank = use the model list
model_id: str = "vllm" # id/alias that routes to vllm (and --served-model-name) 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, 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. # e.g. "0" or "0,1"); blank = all visible NVIDIA GPUs. CUDA-only.
host: str = "127.0.0.1" host: str = "127.0.0.1"
......
...@@ -5204,10 +5204,14 @@ class MultiModelManager: ...@@ -5204,10 +5204,14 @@ class MultiModelManager:
mid = getattr(kt_cfg, "model_id", "ktransformers") or "ktransformers" mid = getattr(kt_cfg, "model_id", "ktransformers") or "ktransformers"
_add(mid, "text", {"backend": "kt"}) _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() vllm_cfg = get_active_vllm_config()
if vllm_cfg is not None and getattr(vllm_cfg, "enabled", False): if vllm_cfg is not None and getattr(vllm_cfg, "enabled", False):
mid = getattr(vllm_cfg, "model_id", "vllm") or "vllm" mid = (getattr(vllm_cfg, "model_id", "") or "").strip()
_add(mid, "text", {"backend": "vllm"}) if mid:
_add(mid, "text", {"backend": "vllm"})
return models return models
......
...@@ -11,6 +11,15 @@ ...@@ -11,6 +11,15 @@
> Engine layering: nvidia/cuda/vulkan/opencl are **in-process base engines**; vLLM (like > 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 > 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. > 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 ## 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