Your GPUs are the most expensive thing in the building, and most of the time they are doing nothing. A GPU serving one request at a time can sit around 5% busy, waiting to move data, while it bills at the full rate. You are paying for silence.
You made the call to self-host the model. (If you are still weighing that call, see Before You Buy the GPUs.) The GPUs are yours now, and in the demo one request comes back in a second and everyone is happy. Then real traffic arrives, and the same fleet is somehow both slow and ruinously expensive, because the hardware is barely working.
Fast means every user gets an answer within the time you promised them, the target engineers call a service-level objective, or SLO. Cheap means the GPUs stay busy. Doing both at once is the whole job, and it is a systems problem, not a model one.
What we built
It is a single system, not a bag of separate tricks: a serving stack that sits between your users and the model and keeps the GPUs busy without making anyone wait too long. Three parts:
- an engine that packs many requests onto each GPU,
- a set of levers that push more work through without making users wait longer than promised, and
- an autoscaler that adds and removes GPUs as traffic moves, so you never pay for idle ones.
Nothing here changes the model. It changes how hard the hardware works.
The one chain that sets the bill
Everything traces to a single chain. Cost per token depends on how busy the GPU is (its utilization). How busy it is depends on the batch size, how many requests you pack onto it at once. And the batch size is capped by your latency budget, how long you will make a user wait.
Pack more requests onto a GPU and it works harder, so each token gets cheaper, by a lot: a busy GPU can be roughly 100x cheaper per token than an idle one. But the bigger the batch, the longer each user waits. So you cannot just crank it up. Throughput, the number of requests you serve per second, is the wrong target on its own, because throughput that makes everyone wait too long is useless to you. The number that matters is goodput: the requests per second that are still fast enough to keep your SLO, the speed you promised users. It is the throughput you can actually use, and it is the line the charts below are drawn against.
Keeping the GPU busy
The engine is the foundation. vLLM and SGLang both pack requests together with continuous batching: instead of waiting for a whole batch to finish, the scheduler slips a new request in the instant an old one frees a slot, so the GPU never idles between requests. (Pick SGLang if your requests tend to share a long, identical opening, the same instructions or reference documents pasted in front of every question, and vLLM as the general default. The engine is the least interesting choice in the stack.)
The harder problem is that one big new prompt can stall everyone else’s token generation. Chunked prefill fixes it: the prompt is fed in small slices interleaved with ongoing work, so nobody stalls. It is now the default in both engines, and in the Sarathi research it raised serving capacity 2.6x on a single-GPU Mistral-7B and up to 5.6x on a much larger model spread across several GPUs, all within the latency budget.
Batch size is the master knob, and the whole art is finding the largest batch that still clears your SLO.
Pushing the frontier
Once the GPU is busy, you push more work through it, and the right lever depends on the bottleneck, not the hype:
- Short on memory? Quantization. Store the model’s numbers in a smaller, coarser format. In FP8 (eight bits per number instead of the usual sixteen) that roughly halves the memory, and on the slow part of generating text roughly doubles throughput, for under 2% quality loss; it is the 2026 default. Drop to INT4 (four bits, smaller still but rougher) only when you must fit a bigger model on a smaller card.
- Slow token by token? Speculative decoding. A small, fast draft model guesses the next few tokens and the big model checks them all in one pass; when the guess is right you get 2 to 3x the speed with identical output. It shines on code and structured text, less on open-ended writing.
- Bigger than one GPU? Parallelism. Split the model across several GPUs, inside one machine over the fast links between cards (called NVLink), or across separate machines when it will not fit in one.
- Phases fighting each other? Disaggregation. Reading the prompt and writing the answer stress a GPU differently and get in each other’s way when they share one. Splitting them onto separate pools of GPUs, now standard via NVIDIA Dynamo, served up to 7.4x more requests at the same speed target in the DistServe research.
- Recomputing the same context? KV caching. As the model reads a prompt it builds a working memory of it; reuse that for a shared opening instead of rebuilding it every time. We cover that layer on its own in our caching case study; here it is one lever among many.
Running it without burning money
None of this matters if the GPUs sit idle between traffic peaks. Scaling to zero saves money but hits the cold-start trap: spinning up a fresh GPU pod and loading a large model into memory can take minutes, during which the first user waits and the meter still runs.
So you keep a small warm pool always ready, and slice underused GPUs with MIG (multi-instance GPU) so one card serves several small jobs instead of one at 5%. The autoscaler watches queue depth and latency, not CPU, and adds capacity before the SLO breaks, not after.
When it is worth building
Honesty first: this stack only pays if the GPUs stay busy. Below roughly half-utilization, or with spiky, low-volume traffic, a hosted API is cheaper and simpler, the same conclusion as Before You Buy the GPUs.
Build this when your traffic is steady and large enough that the utilization you win covers the engineering, and when control over the model, the data, or the latency is worth owning.
Outcome
The result is measured, not promised. The GPUs run busy at a fixed latency SLO, so cost per token falls as load rises instead of climbing with it, and the number that matters, cost per million tokens at that SLO, sits on a dashboard rather than in a hope.
The model never changes. The hardware around it just stops idling.
This is a reference build. The stack, and the goodput tuning underneath it, is work we can do with you.