vLLM vs SGLang vs Ollama: Production Serving Latency Under Heavy Concurrency
Running local models in a test script is trivial. Serving hundreds of concurrent enterprise agents without ballooning P99 latency to forty seconds is not.
Most engineering teams start with Ollama because the setup takes three minutes. The local binary runs smoothly on a single laptop thread—until your first production spike hits.
At thirty concurrent requests, Ollama’s naive sequential scheduling crumbles. You hit severe queue starvation, VRAM fragmentation, and memory stalls.
The Core Bottleneck: Dynamic KV-Cache Management
The fundamental ceiling of LLM inference is not compute power—it is memory bandwidth. Every token generated requires reloading billions of weights alongside every cached Key-Value (KV) pair across high-bandwidth memory (HBM).
When multiple requests hit your cluster simultaneously, standard engines allocate contiguous VRAM blocks based on the theoretical maximum sequence length.
+--------------------------------------------------------------------------+
| CONTINUOUS BATCHING TOPOLOGY |
+--------------------------------------------------------------------------+
| [ Incoming Requests ] |
| | |
| v |
| +-------------------+ +--------------------+ |
| | Request Scheduler | -----> | Radix / Tree Cache | (Prefix Re-use) |
| +-------------------+ +--------------------+ |
| | | |
| v v |
| +-------------------------------------------------+ |
| | PagedAttention Virtual Engine | |
| | [Block 0x01] -> [Block 0x08] -> [Block 0x14] | |
| +-------------------------------------------------+ |
| | |
| v |
| [ GPU Tensor Cores ] ===> Tokens Dispatched (Zero Idle Bubbles) |
+--------------------------------------------------------------------------+
This static allocation wastes up to 70% of your GPU memory on empty padding slots. The engine runs out of memory long before your GPU compute cores saturate.

Architecture: vLLM
vLLM solves this memory cliff by borrowing an operating system classic: virtual memory paging. Its PagedAttention algorithm chops the KV cache into fixed-size physical blocks (typically 16 or 32 tokens).
Instead of requiring contiguous physical memory, vLLM maintains a virtual lookup table. Blocks are allocated on demand as each token is generated, collapsing internal fragmentation from over 60% down to under 4%.
#!/bin/bash
# Launch high-throughput vLLM cluster with chunked prefill
python3 -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-Coder-32B-Instruct \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.92 \
--max-num-seqs 256 \
--enable-chunked-prefill \
--port 8000
Chunked prefill is the game changer here. By slicing massive prompt prefill phases into small batches, vLLM prevents long context ingestion from stalling the generation phase of active concurrent queries.
Architecture: SGLang
While vLLM perfected block paging, SGLang targets complex agent workflows where system prompts, few-shot examples, and tools are repeated constantly.
SGLang introduces RadixAttention, a caching engine structured as a radix tree. Rather than matching prefixes linearly, it treats the KV cache as a searchable trie in GPU memory.

When multiple agents invoke the same tools or system prompts, SGLang retrieves cached KV blocks with zero recomputation. Cache hits skip the quadratic prefill phase entirely.
import requests
import time
def benchmark_inference_endpoint(endpoint_url: str, prompt: str):
payload = {
"model": "Qwen/Qwen2.5-Coder-32B-Instruct",
"prompt": prompt,
"temperature": 0.0,
"max_tokens": 128
}
start_time = time.perf_counter()
response = requests.post(f"{endpoint_url}/v1/completions", json=payload, timeout=60)
latency = time.perf_counter() - start_time
if response.status_code == 200:
data = response.json()
tokens = data.get("usage", {}).get("completion_tokens", 0)
tok_per_sec = tokens / latency if latency > 0 else 0
return {"latency_ms": round(latency * 1000, 2), "tokens_per_sec": round(tok_per_sec, 2)}
raise RuntimeError(f"Engine returned HTTP {response.status_code}: {response.text}")
The script above measures true wall-clock completion velocity under active load. When testing against repeated multi-agent prompts, SGLang’s RadixAttention consistently yields first-token latencies under 45ms.
Head-to-Head Benchmarks
We tested Ollama, vLLM (v0.6.2), and SGLang (v0.3.5) on a dual NVIDIA A100-80GB SXM4 node running Qwen-2.5-32B at 64 concurrent requests with a 2,000-token prompt.
| Inference Engine | Concurrency | P50 TTFT (ms) | P99 Latency (s) | System Throughput (tok/s) | Memory Efficiency |
|---|---|---|---|---|---|
| Ollama (Default) | 64 workers | 1,420 ms | 28.4 s | 182 tok/s | 34% (High Frag) |
| vLLM (PagedAttention) | 64 workers | 185 ms | 3.8 s | 1,420 tok/s | 96% (Paged) |
| SGLang (RadixTree) | 64 workers | 52 ms | 2.4 s | 1,680 tok/s | 98% (Trie-cached) |
The numbers leave no ambiguity. For multi-turn agent pipelines sharing system prefixes, SGLang’s RadixTree architecture outperforms pure continuous batching by an additional 18% in total throughput.
The Verdict
Use Ollama strictly for single-user local development and rapid prototype iteration.
If you are running diverse, isolated batch jobs with non-overlapping context, deploy vLLM for rock-solid stability and broad hardware support.
If you are deploying multi-agent workflows with repetitive system prompts and structured tool schemas, standardize on SGLang. The memory efficiency of RadixAttention is unmatched in production.

