Self-hosted model servers: how they place models, and where nobody has solved it #

Researched 2026-10-08 (claude session e053c857, via a web-research agent). Dates/versions are what was seen that day. Some details came from search summaries or third-party mirrors where the repo could not be opened — marked where it matters. Frozen: a re-check is a new dated file.

Question (operator): "where has this problem reached a solution void?" — the problem being one OpenAI-compatible front door per box that decides, per call, what to load, what to evict and how to make a model fit, across engine types, and learns from what loads really cost.

The projects #

LocalAI (mudler/LocalAI) #

llama-swap (mostlygeek/llama-swap) — the closest design to ours #

Ollama #

LM Studio (closed source) #

GPUStack (gpustack/gpustack) — the fleet one #

Xinference (xorbitsai/inference) #

vLLM #

llama.cpp itself #

Others #

KoboldCpp (single model; --gpulayers -1 guesses layers, "experimental"); Paddler (llama.cpp load balancer by free slots, fleet UI, StatsD; model management only a future plan — https://github.com/intentee/paddler); LiteLLM proxy (routing/keys/budgets, never loads models); Text Generation WebUI (one model, manual).

Where no project has a solution #

Documented absence or open requests (higher confidence):

  1. Measured per-model footprint feeding placement. LocalAI says it cannot estimate across backends; GPUStack's estimate-bug trail (#1601 … #5880); llama-swap #1004 asks for hand-declared sizes and rules out automatic detection; Ollama measures pre-load for its new engine only and still ships estimate regressions.
  2. Learning from past loads. Nobody documents keeping what a load really used (VRAM after load, CUDA context, growth during generation) and reusing it next time.
  3. Planning WHICH residents to evict so a model fits. Everyone uses count + LRU, hand-written sets, or a fixed card fraction; LocalAI documents proceeding into a possible OOM.
  4. Choosing quant + context + layers + MoE offload together, with eviction. llama.cpp --fit (documented: unset args incl. context, min 4096) and LM Studio's guardrail fit ONE model against free memory; Xinference recommends quant from a fixed assumption (not image/video). None combines it with eviction or measured history.
  5. One memory planner across engine types on one card. llama-swap/LocalAI run llama.cpp, diffusers, whisper and TTS side by side under static rules or counts; vLLM takes a fixed fraction; GPUStack reserves by estimate.

Not found (lower confidence — absence of evidence): 6. Raw per-call telemetry feeding scheduling. Everyone exports metrics; nobody reads them back. 7. Fleet placement from each box's MEASURED per-model footprints, with tuned per-model settings pushed back out (LocalAI uses measured free VRAM but no per-model need; GPUStack estimates). 8. Auth open on the LAN, key required from outside, proxy-aware. All use a global on/off switch (or always on).

What this means for hugpy #

hugpy-wrapper 0.1.51 (released today) already does, by design: 1 (measured facts, sql/012 doctrine), 2 (facts persist in its store and are read back), 3 (evict-to-fit plan), 4 (sizing / variants pick quant, ctx, layers, MoE split), 5 (one planner for llama.cpp, transformers, vision, ASR, TTS, image, video), 6 (call_log rows are the inputs of the next decision), 8 (FITEVICT_REQUIRE_KEY=outside, trusted proxies). Gap 7 is hugpy-core's job (pull /v1/telemetry, push settings) — not built yet.

So the void is exactly the combination the wrapper is built around; the nearest neighbours each cover one slice: llama-swap (the front door shape), LocalAI (modality breadth + a fleet), GPUStack (fleet placement by estimate), llama.cpp --fit (single-model fitting).

Worth checking or borrowing (follow-ups, not decisions):