Routing specific models to a different LLM endpoint
By default every LLM call Poindexter makes goes to one endpoint — theapi_base in the LiteLLM provider config (your Ollama instance). The
model_api_base_overrides map lets you route specific models somewhere
else, per model, without touching code:
api_base. An empty
or absent map is a no-op — if you run everything on one GPU against one
Ollama, you can ignore this page entirely; nothing about Poindexter
requires a second endpoint.
When you’d use it
- Pin an eviction-prone model to a second GPU. With multiple hot models sharing one Ollama, a big writer reload can evict a QA-rail model mid-pipeline; the cold reload then times out and the rail skips. Running a second Ollama instance pinned to another GPU (see recipe below) and routing just that model to it removes the eviction path. This is how the reference deployment runs its vision-QA model.
- Borrow VRAM from another machine. Point a model at any Ollama you
can reach — an old gaming PC on the LAN, a box over Tailscale:
{"ollama/qwen3-vl:30b": "http://192.168.1.50:11434"}. - Offload a small model to a CPU-only instance so it never competes for GPU memory at all.
Behavior details
- Keys match the resolved model name. Bare names get the default
prefix first (
qwen3-vl:30b→ollama/qwen3-vl:30b), so key your map with the prefix and both spellings match. - The value may be a dict or a JSON string (app_settings TEXT rows
arrive as strings). Invalid JSON or a wrong type is logged and
ignored — dispatch falls back to the default
api_base, never fails. - The paid-endpoint policy applies to the effective endpoint. An
override pointing at a cloud host (e.g.
https://api.openai.com/v1) is refused unless the paid gate is open — an override can’t smuggle a paid endpoint past the local-only default. Open the gate by settingplugin.llm_provider.litellm.allow_paid_base_urltotrue(withpoindexter settings set); the dispatcher folds that flat row into the provider config, so you don’t hand-edit the nested JSON blob. - Both streaming and non-streaming calls honor the map. All LLM traffic flows through the LiteLLM provider, so the map covers every pipeline stage, QA rail, and job.
Recipe: a second Ollama pinned to a specific GPU
Ollama has no per-model GPU affinity — one instance schedules across every GPU it can see. Hard placement means a second instance that can only see the target GPU. On Windows (scripts/ollama-vision-gpu1.ps1
is the reference implementation, registered as a scheduled task by
scripts/background-services.ps1):
:11435 and warm it once
(curl :11435/api/generate with a one-word prompt). With
OLLAMA_KEEP_ALIVE=-1 it stays resident; the primary instance cannot
evict it because it’s a separate server process.
Gotchas (each of these cost us a debugging round)
OLLAMA_VULKAN=falseis load-bearing. Ollama 0.31+ enables a Vulkan backend by default whose GPU enumeration ignoresCUDA_VISIBLE_DEVICES. Without this, the scheduler still sees your other GPU asVulkan0and will happily place the model there — usually on whichever card has more free VRAM, which is exactly the card you were trying to avoid.- Pin by GPU UUID, not bare index. The UUID form
(
GPU-xxxxxxxx-...) confines reliably and survives enumeration-order changes across driver updates. - Scheduled tasks / services don’t inherit your user environment.
If your models directory or tuning flags live in user-level env vars
(
OLLAMA_MODELS,OLLAMA_FLASH_ATTENTION, …), the wrapper script must read them from the registry explicitly or the instance falls back to defaults and reports every model as missing. - Loopback bind is enough for Docker. Docker Desktop proxies
host.docker.internalto the host loopback, so127.0.0.1:11435is reachable from the worker container with no firewall exposure. - Verify placement with the serve log, not
nvidia-smideltas. The instance’sinference compute/selecting single GPUlog lines are ground truth for which device a model landed on; WDDM memory readouts lag and mislead, especially with other GPU consumers active. - A logon-only trigger doesn’t come back from a clean exit.
background-services.ps1registers this (and every background service) with both anAtLogOntrigger and a repeating 5-min trigger (poindexter#860) specifically because Windows’ ownRestartCount/RestartIntervalonly fires on a nonzero exit code — ifollama.exe serveexits 0 (observed during a host crash/reboot sequence), the task just goes quiet and, on a box that stays logged in for days, doesn’t come back until the next interactive logon. That left the vision instance dead for 24h+ and starved theqa.visionQA rail (advisory-only, so it didn’t block publishing, but it also wasn’t running — see GlitchTip issue #877). If you ever see connection refusals to:11435with sub-10ms latency (an instant refusal, not a slow/contended timeout), checktasklist | grep ollamafor a missing second process before assuming GPU contention.
Verifying a routed model end-to-end
curl <override-base>/api/versionfrom inside the worker container (docker exec poindexter-worker curl http://host.docker.internal:11435/api/version).- Dispatch the routed model through the pipeline (or wait for its next
natural call) and confirm the default instance never loads it
(
ollama psagainst the default base stays clean). - If you pinned it to a GPU, watch that GPU’s utilization spike during the call.