diff --git a/studio/backend/core/inference/llama_cpp.py b/studio/backend/core/inference/llama_cpp.py index 0531dd0e93..b8d168ccc5 100644 --- a/studio/backend/core/inference/llama_cpp.py +++ b/studio/backend/core/inference/llama_cpp.py @@ -608,7 +608,19 @@ class LlamaCppBackend: 3. unload_model() — terminates llama-server subprocess """ - def __init__(self): + def __init__(self, kill_orphans: bool = True): + """Construct a backend wrapper around llama-server. + + ``kill_orphans`` (default True): at construction time, reap any + llama-server processes lingering from a prior studio crash. Safe + for the global singleton (only one LlamaCppBackend exists at + startup). Pass ``False`` for short-lived secondary instances + spawned alongside an already-running chat-model server (e.g. + the RAG captioner helper, `_run_with_helper`) — otherwise the + constructor will kill the parent's healthy chat model because + it can't distinguish "another instance's healthy server" from + "a stale process". + """ self._process: Optional[subprocess.Popen] = None self._port: Optional[int] = None self._model_identifier: Optional[str] = None @@ -691,7 +703,8 @@ class LlamaCppBackend: # to decide whether to wait for the VRAM reclaim to finish. self._last_kill_monotonic: float = 0.0 - self._kill_orphaned_servers() + if kill_orphans: + self._kill_orphaned_servers() atexit.register(self._cleanup) # ── Properties ──────────────────────────────────────────────── diff --git a/studio/backend/core/rag/captioner.py b/studio/backend/core/rag/captioner.py index cc34e7c9a7..561dd5e659 100644 --- a/studio/backend/core/rag/captioner.py +++ b/studio/backend/core/rag/captioner.py @@ -74,7 +74,12 @@ def _load_helper_vlm() -> Optional[tuple[Any, str, str]]: try: from core.inference.llama_cpp import LlamaCppBackend - backend = LlamaCppBackend() + # kill_orphans=False is critical: the global singleton is + # already running the user's chat-model llama-server. Killing + # "orphans" here would reap that healthy chat process because + # the orphan-killer can't tell two LlamaCppBackend instances + # apart by PID ownership. + backend = LlamaCppBackend(kill_orphans = False) logger.info( "RAG captioner: loading helper VLM %s (%s) as fallback", _HELPER_REPO, diff --git a/studio/backend/utils/datasets/llm_assist.py b/studio/backend/utils/datasets/llm_assist.py index a36a121c5d..004dd5b354 100644 --- a/studio/backend/utils/datasets/llm_assist.py +++ b/studio/backend/utils/datasets/llm_assist.py @@ -155,7 +155,9 @@ def _run_with_helper(prompt: str, max_tokens: int = 256) -> Optional[str]: try: from core.inference.llama_cpp import LlamaCppBackend - backend = LlamaCppBackend() + # kill_orphans=False so the helper backend doesn't reap the + # parent's chat-model llama-server while loading itself. + backend = LlamaCppBackend(kill_orphans = False) logger.info(f"Loading helper model: {repo} ({variant})") ok = backend.load_model(