Local LLM Server
Run llama-server under ComfyUI so one GPU hosts your chat and your images
- draft
- vision
- embeddings
- status
- base_url
- server_log
- help
Local LLM Server exists for one specific headache: a chat model and an image model do not fit on the same GPU at once. If you've ever pointed a client like SillyTavern straight at llama-server while also generating images in ComfyUI, you know the failure - ComfyUI (or you) kills the LLM process to free the card, and the next chat message hits a closed port. Nothing is listening, so nothing can start the model back up. SillyTavern is still a genuinely live ecosystem in 2026, and the whole point of a local setup is keeping it off one card with your diffusion.
The node's answer is to split the listener from the model. It launches a real llama-server (or koboldcpp) as a subprocess under ComfyUI, behind a small gateway HTTP server that this ComfyUI process owns:
- the gateway starts when you queue this node once and stays up as long as ComfyUI runs. That's the address you configure in the chat client and never touch again;
- the model is a separate process on a private port that holds the VRAM. It loads on the first request that needs it and is killed whenever the VRAM is wanted elsewhere.
A chat message arriving with the model unloaded just waits for the load, then gets forwarded - the client sees a slow first reply, never an error. And requests that need no model, like the model list and health probe behind SillyTavern's Connect button, are answered by the gateway itself, so connecting works with nothing loaded at all.
The inputs that matter
It's a config-heavy node, but a beginner really sets five things:
- action -
serve(start the gateway, wait for the first request),serve + load the model now,reload the model, orstop everything. - server_binary - an executable to launch. This is the big gotcha: nothing is bundled. You download
llama-serveryourself from a llama.cpp release (or grab koboldcpp) and drop it underComfyUI/models/llm, subfolders fine - the dropdown auto-lists anything it finds there recursively. If it's elsewhere, pick the placeholder and type a path in server_binary_path. - model - the
.gguffromComfyUI/models/llmto serve (or type a full path in model_path). - n_ctx (default 8192) and n_gpu_layers (-1 = all) - the usual two, and context is what eats VRAM fast once a long chat plus a character card fills it.
- listen_port (default 5001) and listen_host (127.0.0.1 = this machine; 0.0.0.0 to reach it from the LAN).
Everything else is well-labelled and mostly "leave it alone until it bites": extra_args appends raw server flags (--flash-attn, --jinja, --model-draft …) and changing it reloads the model; autoload and unload_comfy_models handle the VRAM hand-off; fix_params repairs request bodies llama.cpp refuses (SillyTavern famously sends dry_sequence_breakers and friends as JSON strings where an array is required), and auto_retry drops an unknown field and retries when a 400 names one. free_on_prompt is the safety net: any queued prompt that isn't itself about the server unloads the model as it's queued, before a node of it runs. idle_unload_minutes frees VRAM after a quiet spell.
Four outputs: status, base_url (ends in /v1 - paste it into SillyTavern as a Custom OpenAI-compatible endpoint with no API key), server_log (your debugging friend when a load stalls), and help (a cheat sheet - wire it to a Preview as Text node). The gateway also answers /kinburg/status, /kinburg/unload and /kinburg/load in a browser.
Installing
Clone the pack or install "Kinburg-Nodes" via ComfyUI Manager and restart. One clarification people trip on: the pack's install.py installs the CUDA build of llama-cpp-python, but that's for the in-graph Local LLM (GGUF) nodes - this node doesn't use it at all, because it shells out to the external server binary you provide. If you only want the server pair, the binary and a .gguf in ComfyUI/models/llm are the actual prerequisites.
Where it bites
Model loads are slow the first time - raise startup_timeout (default 300s) if a big quant legitimately needs longer, and read server_log rather than guessing. Changing the model, n_ctx or extra_args reloads on the next request. And remember this node generates nothing itself: if you want a text answer inside a graph, that's Local LLM (GGUF), not this. This one is the sidecar - the thing that makes a local chat client and your image pipeline share one card without ever seeing each other's mess.
Inputs (45)
| Name | Type | Default | Description |
|---|---|---|---|
| action | COMBO | serve | serve = start the gateway and wait for the first request. 'load now' also loads the model straight away. 'reload' kills a loaded model so the next request starts it fresh. 'stop everything' shuts the gateway down too. |
| flavour | COMBO | llama-server | Which server is being launched. It picks the flag names for every setting below — and a few settings only one of them has (the status output names those). |
| server_binary | COMBO | Executable to launch. Auto-lists every llama-server / koboldcpp found anywhere under ComfyUI/models/llm, subfolders included; otherwise pick the placeholder and type a path below. Download or build it yourself — not bundled. | |
| server_binary_path | STRING | Full path to the server executable when the dropdown is the placeholder. | |
| model | COMBO | The .gguf from ComfyUI/models/llm to serve. Placeholder = type a path in model_path. | |
| model_path | STRING | Full path to the .gguf when 'model' is the placeholder. | |
| n_ctx | INT | 8192256–1048576 | Context size (--ctx-size / --contextsize). A long chat plus a character card eats this fast — and the KV cache grows with it. |
| n_gpu_layers | INT | -1-1–1000 | GPU layers (-ngl / --gpulayers). -1 = all. |
| extra_args | STRING | Raw flags for what has no widget: rope/yarn, --tensor-split, --override-tensor, --lora, --fit… Appended last, so they win. Changing this reloads the model. | |
| listen_host | STRING | 127.0.0.1 | Where the gateway listens. 127.0.0.1 = this machine only; 0.0.0.0 to reach it from another box on the LAN. |
| listen_port | INT | 50011–65535 | The port SillyTavern is pointed at. It stays open while ComfyUI runs, model or no model. |
| autoload | BOOLEAN | true | Load the model on the first request that needs one. Off = a request with nothing loaded gets a clear error instead. |
| free_on_prompt | BOOLEAN | true | Unload whenever a ComfyUI prompt is queued that is not itself about the server — the safety net for image workflows you did not edit. |
| idle_unload_minutes | INT | 00–1440 | Unload after this many minutes with no request. 0 = never. |
| unload_comfy_models | BOOLEAN | true | Free ComfyUI's own models from VRAM before loading the LLM. |
| fix_params | BOOLEAN | true | Repair the request bodies llama.cpp refuses — SillyTavern sends dry_sequence_breakers and friends as JSON strings where an array is required. |
| auto_retry | BOOLEAN | true | On a 400 that names a field, drop that field and retry once, then strip it from later requests. Keeps one unknown option from breaking every message. |
| drop_fields | STRING | Field names to strip from every request, one per line. The manual version of auto_retry. | |
| backend_port | INT | 00–65535 | Private port for the model server. 0 = pick a free one. |
| ready_path | STRING | Path polled until the model is ready. Blank = per-flavour default (llama-server /health, koboldcpp /v1/models). | |
| startup_timeout | INT | 30010–3600 | How long a load may take before it is called a failure. |
| request_timeout | INT | 90010–7200 | How long one forwarded request may take. |
| flash_attn | COMBO | auto | Flash Attention: faster, smaller KV cache. llama-server decides for itself on 'auto' and koboldcpp has it on already, so this is for forcing it off on a model that misbehaves. |
| kv_cache_type | COMBO | f16 | Quantize the KV cache to fit a longer chat in VRAM. q8_0 is nearly free; q4_0 is noticeable. Full effect needs Flash Attention — without it only K is quantized. |
| n_batch | INT | 00–65536 | Logical batch size (-b / --blasbatchsize). 0 = the server's default. Bigger reads a long prompt faster and costs VRAM. |
| n_ubatch | INT | 00–65536 | Physical batch size (-ub). 0 = default. llama-server only. |
| threads | INT | 00–256 | CPU threads (-t). 0 = the server's own choice. Matters only for what is not on the GPU. |
| cpu_moe_layers | INT | 00–1000 | Keep the Mixture-of-Experts weights of the first N layers in system RAM (-ncmoe / --moecpu). 0 = off. On a MoE model this frees more VRAM per point of speed than anything else here; on a dense model it does nothing. |
| parallel_slots | INT | 00–64 | Concurrent request slots (-np / --multiuser). 0 = the server's default. Each slot costs its own share of the KV cache, so 1 is right for one chat. |
| context_shift | BOOLEAN | true | Let the server drop the oldest tokens and keep going when the chat outgrows n_ctx. Off = it stops instead (--no-context-shift / --noshift). |
| alias | STRING | The model name the API reports, and what the gateway lists in /v1/models. Blank = the .gguf filename. llama-server only. | |
| api_key | STRING | Require this key on every request (--api-key / --password). Blank = no authentication. The gateway forwards whatever the client sends. | |
| reasoning | COMBO | model default | Thinking on or off (-rea). 'model default' leaves it to the model's template. koboldcpp can only express 'off'. |
| reasoning_budget | INT | -1-1–1048576 | How many tokens thinking may spend before it is cut off (--reasoning-budget). -1 = unrestricted, 0 = end it immediately. llama-server only. |
| reasoning_format | COMBO | auto | Where the thoughts go. 'auto' (the default) hands them back separately as reasoning_content, which SillyTavern renders as its own collapsible block; 'none' leaves the raw think tags in the reply. llama-server only. |
| enable_thinking | COMBO | model default | Chat-template variable (--chat-template-kwargs), not prompt text — so the model cannot ignore it. 'model default' leaves it undefined, which each family reads its own way (Qwen3.5/3.8: ON, Gemma-4: OFF). |
| reasoning_effort | COMBO | model default | How hard to think, as a chat-template variable. Qwen3.5/3.8 accept xhigh / medium / low and ERROR on anything else; use 'custom' for other families (gpt-oss: high). |
| reasoning_effort_custom | STRING | Effort value sent when reasoning_effort = custom (e.g. 'high' for gpt-oss). Empty = send nothing. | |
| chat_template_file | STRING | A .jinja chat template that OVERRIDES the one in the GGUF (--chat-template-file). Empty = the model's own, which is right for almost every model. llama-server only. | |
| log_events | BOOLEAN | true | Feed the 'LLM Server Live Log' node: every request with its status, duration, token counts and the sampler settings the client sent, plus loads, unloads and errors. No message text — see log_text. |
| log_text | BOOLEAN | false | Also log the last user message and the reply, trimmed to a few hundred characters. OFF by default on purpose: that is somebody's conversation, and the log is drawn on the ComfyUI canvas for whoever is sitting there. |
| log_server_output | BOOLEAN | false | Also log llama.cpp's own stdout (slots, prompt-eval timings). Useful when a model misbehaves, noisy the rest of the time. It always reaches the 'server_log' output regardless. |
| draftopt | KINBURG_LLM_SERVER_DRAFT | Optional — wire an 'LLM Server Draft' node here for speculative decoding. | |
| visionopt | KINBURG_LLM_SERVER_VISION | Optional — wire an 'LLM Server Vision' node here to serve an mmproj so the chat client can send images. | |
| embeddingsopt | KINBURG_LLM_SERVER_EMBED | Optional — wire an 'LLM Server Embeddings' node here to serve /v1/embeddings (SillyTavern's Vector Storage) from the same address. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| status | STRING | — |
| base_url | STRING | — |
| server_log | STRING | — |
| help | STRING | — |