HOME GITR3KT ← All reports

The problem, plainly

You run a big model on your own computer. You ask it something that needs a long answer. It starts writing — and halfway through, it runs out of GPU memory. The whole answer dies.

You waited minutes. You get nothing at all — no partial answer, no saved work, just a dead generation. That dead generation is the problem this system solves.

Final document · 26 October 2026

VRAM Spillover:
the generation
that didn’t die.

A small program that sits in front of the model you already run. When memory fills up mid-answer, it quietly moves the live answer to a smaller model — and the answer finishes, through the same connection, instead of dying.

Public repo: GrizzlyBiscuit/vram-spillover Apache-2.0Live on :8090 → :8081Proven on 2× Intel Arc A770
620/621

Tokens delivered across a handoff in the battery repeats — with zero disconnects.

0.9747

Real VRAM pressure when the watcher fired in the Oct 21 proof run.

0.44–2.72s

Cost of the handoff itself — warm vs. cold re-prefill. The only pause the client feels.

0

Engine patches or forks. It works in front of stock servers, unmodified.

The fix: change the model, mid-answer

Every other system found in the research does part of this. None does all five parts together. That combination — not any single trick — is the claim.

01

Sits outside the engine

A proxy in front of stock OpenAI-compatible servers (llama-server). Backend-agnostic, no fork.

02

Watches real pressure

A watcher monitors measured VRAM per card while a generation is running — not guesses, not error codes.

03

Acts mid-stream

When pressure crosses the line during a streaming answer, it intervenes then — not on the next request.

04

Hands off to a smaller model

The live generation moves from the large primary to a smaller fallback on another server.

05

Replays the prefix, holds the stream

Prompt + tokens already emitted are replayed into the fallback, and the client’s original stream stays open as one continuous generation.

Verdict from the uniqueness research: no exact match was found. This is a genuinely novel combination of well-established parts — not a novel primitive. Confidence is moderate-high for “no shipped exact match in public sources,” not absolute. The open checks are listed under Honest limits.

Step 1 of 4

A normal generation, on the big model

The client asks through the proxy on :8090. The primary model on :8081 streams tokens back. Nothing unusual — and the watcher is already measuring VRAM on every card, the whole time.

Clientone stream, held open Spillover proxy:8090 · chat only Primary — large model:8081 · 35B pair, dual A770 Fallback — smaller model:8080 · receives the replay Watcher0.95 / 0.85 · ×3 Fail-open guardproxy dies → traffic flows

Live deployment: three systemd user units — watcher, proxy, fail-open guard. Deliberate split: the proxy handles chat routes only; the decision path (/v1/systemone) stays on :8080 direct, because the proxy speaks chat routes only and routing decisions through it would 404.

Measured proof — not estimates

The handoff has been proven three times over: the Oct 21 proof run, the Oct 24 battery repeats, and a live test through :8090 on Oct 26. Every number below is from those runs.

RunWhat happenedKey numbersResult
Proof run
21 Oct
Watcher fired at real pressure; handoff mid-stream; client connection held to completion.fired 0.9747 · handoff at 49 tokens · 249-token completion · 254 msEXIT 0 · FINISH LENGTH
Repeat 1
24 Oct battery
Cold-cache handoff. Fallback generated the bulk of the answer after the switch.handoff 67 · fallback 553 · total 620 · re-prefill 2.724 s cold · fallback 32.9 tok/s · overall 24.0 tok/s in 25.8 sSTREAM HELD
Repeat 2
24 Oct battery
Same run, warm cache — the re-prefill cost collapses.handoff 68 · total 621 · re-prefill 0.444 s warmSTREAM HELD
Control
direct :8081
No proxy in the path — the baseline the handoff runs are measured against.657 chunks · finish stop · 34.0 sBASELINE
Static run
safe settings
100 tokens direct on :8081; VRAM flat before and after.100 tokens · 5.297 s · finish length · 31,336 MiB flatPASS
Gate verdictsSpillover rows checked against the memory gate.30.60 GiB ≥ 30.4 GiB · control N/APASS

The finding that reframed the problem: VRAM doesn’t creep — it jumps

Measured KV growth: 0.000000 GB per 1k tokens — 195 tokens, 186 watcher samples, dead flat at 31,336 MiB. The KV cache is preallocated at load, so pressure doesn’t arrive token by token. It arrives as a step jump when another instance loads — the sidecar loading added +5,041 MiB at peak. A watcher built for a slow creep would miss the thing that actually kills generations.

31,336 MiBtokens → flat during generation — slope 0.000000 +5,041 MiB — sidecar loads

The whole path — including the false start

This wasn’t a straight line. The first “success” was fake, and the document keeps it in — because catching it is what made the later proof mean anything.

The problem

Before Oct —Long answers died and delivered nothing

Long generations on the 35B model pair died on VRAM exhaustion — RemoteDisconnected-class crashes. A long run would simply end. The goal from the start was narrow: save the generation, not make the model fit.

6 Oct
False positive

6 Oct —The handoff that wasn’t

The proxy logged a handoff — but zero post-switch characters reached the client. Root cause: a Python iterator binding bug — for line in resp kept draining the original stream even after resp was rebound to the fallback. Fix: an explicit iterator rebuilt after handoff, plus stricter pass criteria — no error, a handoff, resumed streaming, tokens from more than one model, post-switch characters > 0.

7 Oct
Smoke test passed

7 Oct —739 characters actually arrived

After the fix, 739 characters arrived from the fallback after the switch — tokens genuinely reaching the client post-handoff. The full proof was then redirected to the correct dual-GPU configuration instead of a single-card setup.

21 Oct
Proof landed

21 Oct —The ratified proof run

Watcher fired at 0.9747, handoff at 49 tokens, 249-token completion, exit 0, connection held. Honest footnote: an evidence record built earlier that same day was marked “proof PENDING” at build time — the proof landing later that night superseded that marking. The label was stale, not the result.

22 Oct

22 Oct —Dead ends cleared

The SGLang / EAGLE-4 spike was killed (SGLang XPU unusable on the A770s). A Nemotron download was scrapped. The d1-3B decision lane went live — separately, on its own path.

24 Oct
Battery complete

24 Oct —All 7 audit gaps closed

The repeats (67→620, 68→621), the control run, the gate verdicts, per-card gate semantics, and the boundary finding: the proxy replays the entire stream with no cap, so the fallback’s 8,192-token context truncates replays of very long primary contexts.

25 Oct

25 Oct —The claim was cut down to what was proven

The publish pack was rescoped off a “70B-class” headline to the proven claim only. A wrap-up one-pager shipped. No inflated headline survived contact with the evidence.

26 Oct
Full send — live & public

26 Oct —Deployed, published, and checked for uniqueness

Live deployment proven (3 units, fail-open guard, a live chat completion through :8090 returning the 35B model), all 9 measurement cells filled, and the public repo published — initial commit 0e7fbaf plus corrections commit 35cdc4d fixing the proof table, the primary-line wording, and LICENSE detection (verified against the remote: ls-remote = 35cdc4d…). The uniqueness deep research completed the same night — next section.

Why it matters worth a damn

Four reasons, in order of how much they’d matter to anyone else running models at home.

1

The alternative is not a slower answer. It’s no answer.

Before this, a long generation under VRAM pressure died and delivered nothing — minutes of compute, zero output. Now it finishes, on a smaller model, through the same connection. It kills a whole crash class, not a percentage of one.

2

It works with the server you already run

No engine fork, no patch to llama.cpp, vLLM, or anything else. It sits in front of stock servers — so it’s portable, upgradable, and doesn’t die the next time the engine releases.

3

It only degrades work that would otherwise die

The trigger is measured VRAM, not a guess or a schedule. The proxy intervenes only when the alternative is death — it never downgrades a generation that would have survived.

4

The degradation is honest and bounded

Quality drops to the smaller model and says so. The pause costs 0.44–2.72 s. Very long contexts hit the fallback’s context cap. No silent corruption, no fake continuity, no pretending the model never changed.

Compared to everyone close

Deep research across proxies, inference engines, migration systems, routers, and serving stacks (sources opened 26 Oct 2026). Ranked strongest “someone already did this” first. Every candidate has a piece of it. Each card names the one feature that still separates it. Search or filter to interrogate the field.

Rank 1 · Closest cousinPROXY

RAMP — Resource-Aware Model Proxy

OpenAI-compatible proxy in front of llama.cpp / Ollama. Watches RAM, VRAM (via nvidia-smi) and disk, and moves the loaded model up/down a quality ladder (e.g. 7B → 3B) under pressure, with ~2 s warm swaps.

The one gap — timing: swaps happen between requests only. In its own docs: “in-flight generations are drained first (up to drain_timeout_s), and incoming requests wait on the swap gate.” No mid-stream interruption, no prefix replay, no rescue of a generation already in flight. The gap between RAMP and Spillover is exactly the mid-stream switch.
Proxy-level ✓Real VRAM trigger ✓Mid-stream ✗Smaller model ✓Prefix replay ✗

Source: pypi.org/project/ramp-llm/0.2.1

Rank 2 · Migration familyMIGRATION

ServerlessLLM / SpotServe / Pallas

Live migration of running inference. ServerlessLLM migrates only tokens and recomputes KV at the destination; SpotServe preserves request state across spot preemption; Pallas prefills a stable prefix at the target while streaming suffix KV blocks, then resumes decoding. The closest technical analogue to prefix replay.

The one gap — same model, wrong trigger: migration is for locality, spot preemption, or cellular handover — never VRAM pressure, never a downgrade to a smaller model. And it’s engine/system-integrated, not a stock proxy.
Proxy-level ✗VRAM trigger ✗Mid-stream ✓Smaller model ✗Prefix recompute ✓

Sources: ServerlessLLM (arXiv) · SpotServe (arXiv) · Pallas (arXiv) · MorphCloud-LLM

Rank 3 · Gateway fallbacksPROXY

LiteLLM Proxy fallbacks

Proxy-level fallback chains: after retries and cooldowns, a failed model group fails over to another model group — including a smaller one — with separate context-window and content-policy fallbacks. The client need not implement retry.

The one gap — trigger & continuation: triggered by provider errors (429 / 5xx / timeout), not measured VRAM. Per its own error docs, a failure after streaming has begun cannot change the already-200 status — the gateway emits the error as a final SSE event. A streaming retry is only safe before the first token. No documented prefix replay holding one stream.
Proxy-level ✓VRAM trigger ✗Mid-stream ✗Smaller model ✓Prefix replay ✗

Sources: docs.litellm.ai/docs/proxy/reliability · error reference

Rank 4 · Engine preemptionENGINE

vLLM preemption (+ SGLang / TensorRT-LLM / llama.cpp)

When KV-cache space runs out mid-generation, vLLM preempts requests, frees their KV blocks, and recomputes them (V1 default RECOMPUTE) when space returns. SGLang evicts radix-tree leaves; TensorRT-LLM admits-only-if-completable or evicts to maximise batching; llama.cpp’s analogue is load-time fit and context shift.

The one gap — no model change, ever: engine-integrated, same model, no proxy, no downgrade. The request survives by waiting and recomputing on the model that was already too big for the moment.
Proxy-level ✗Host VRAM trigger ✗Mid-generation ✓Smaller model ✗Prefix replay ✗

Source: docs.vllm.ai — optimisation

Rank 5 · VRAM-aware routingPROXY

NeuralBroker

OpenAI-compatible routing daemon: serves local runtimes first, then “spills to cloud providers only when VRAM pressure or policy requires it.” Alongside RAMP, the only other candidate with real VRAM pressure as a trigger.

The one gap — timing & direction: pre-generation routing of new requests, outward to the cloud — not a mid-stream switch to a smaller local model, with no evidence of prefix replay or a held in-flight stream.
Proxy-level ✓Real VRAM trigger ✓Mid-stream ✗Smaller local model ✗Prefix replay ✗

Source: pypi.org/project/neuralbrok/0.4.0

Also-rans · Each missing moreROUTERS & SERVING

RouteLLM, FrugalGPT, llama-swap, Mooncake / LMCache, llm-d

RouteLLM picks one model per query before generation, on predicted quality/cost. FrugalGPT cascades post-generation, escalating cheap → strong — the opposite direction. llama-swap swaps on requested model name or idleness, never resource state. Mooncake / LMCache and disaggregated prefill/decode transfer KV at a phase boundary, same model. llm-d / KServe pick a replica pre-generation; their KV “spills” down tiers (HBM → DRAM → SSD), same model.

Common gap: every one decides before generation starts, after it ends, or without ever changing the model.

Sources: RouteLLM (arXiv) · Mooncake (arXiv) · LMCache docs · llm-d / KServe · llama-swap overview

SystemProxy-levelVRAM triggerMid-streamSmaller modelPrefix replay + held stream
VRAM Spillover (this)YesYesYesYesYes — all five
RAMPYesYesNo — between requestsYesNo
ServerlessLLM familyNo — systemNo — locality / preemptionYesNo — same modelToken / prefix recompute
LiteLLMYesNo — provider errorsNo — pre-first-token safePossibleNo — SSE error
vLLM preemptionNo — engineNo — KV accountingYesNo — same modelNo — recompute & wait
NeuralBrokerYesYesNo — pre-generationNo — cloudNo

On the name: nothing branded “vram-spillover” as a product or paper was found — no GitHub repo, PyPI or npm package owns it for this concept. But “VRAM spillover” is a common generic phrase for a model overflowing into system RAM at a 10–50× slowdown (Spheron, Servnet), and driver-level projects like emuV use “spill” the same way. That’s a naming-confusion risk — readers will first think “layers spilling to RAM” — not a prior-art bar.

Not counted as a match: a single-author “self-healing routing” blog (dev.to) claims a router “re-sends the request, and resumes streaming” after a provider drops a stream. Trigger is provider failure, not VRAM; “re-sends” reads as restart-from-scratch, not prefix replay; and it’s a blog claim, not product documentation. Closest claim of mid-stream switching found — still not the concept.

Honest limits & open questions

What this doesn’t do, and what the research couldn’t settle. Both lists ship with the claim — the claim is stronger for carrying them.

Quality drops after the handoff

Post-handoff output is the smaller model’s output. That’s the trade, stated plainly — the sceptical reader’s first prediction, and it’s true.

Very long replays hit a cap

The proxy replays the entire stream with no cap; the fallback’s 8,192-token context truncates replays of very long primary contexts.

The fallback must be warm

Re-prefill costs 0.444 s warm vs. 2.724 s cold. Acceptable latency depends on the fallback already being loaded.

Proven on one hardware stack

2× Intel Arc A770 (SYCL) only. The design is backend-agnostic; the proof, so far, is not multi-hardware.

Could not verify: LiteLLM stitching

Whether any current LiteLLM version stitches a new stream after a mid-stream break, in any configuration, couldn’t be settled from docs alone. No evidence was found that it does so on VRAM pressure with prefix replay. A code-level check of a pinned version would settle it.

Could not verify: the “Voltron” citation

RAMP’s page describes a “Voltron” that scales precision mid-stream. The arXiv Voltron found (2607.07046) is about elastic multi-device execution instead. Do not cite Voltron as mid-stream prior art on RAMP’s say-so.

Open: exhaustive GitHub & registry checks

Web-index search is not an exhaustive GitHub code/Discussion search (llama.cpp Discussions are poorly indexed — searches there surfaced only load-time OOM items like issue 28964 and downstream spill reports like hermes-agent 106895, neither a mid-generation fallback proposal). An exact-name PyPI/npm/GitHub registry check for “vram-spillover” is cheap and still open, as is an exhaustive sweep of hosted gateways (OpenRouter, Portkey, etc.). A private or unindexed repo could still exist.

The defensible claim, in one sentence

“A backend-agnostic proxy that, on measured per-card VRAM pressure during a live stream, replays prompt + emitted tokens into a smaller model on another stock server and stitches the two streams into one client-visible generation.” None of the searched systems claims that sentence.

What this project demonstrates

For a reader evaluating the work, not just the system:

Systems design without forking the stack

A production failure was solved at the proxy layer, in front of unmodified servers — portable by construction, with a fail-open guard so the fix itself can never become the outage.

Measurement discipline

The first “success” was a false positive and was caught by the evidence, not by optimism: pass criteria were tightened, the bug was root-caused to an iterator binding, and every headline number in this document traces to a named run.

Honest scoping

An inflated “70B-class” headline was cut to the proven claim; limits and unverified questions ship inside the document; and the novelty claim was stress-tested against the closest prior art before it was made.

Shipped, not prototyped

Live under systemd with a battery-proven configuration, proven end-to-end three times, and published open-source (Apache-2.0) with bench results and corrections applied in public.