Starphix
Agentic Engineering / Sources
The Lab / Sources / Agentic Engineering / ModelArchitectures/Inference-Optimization.md

Inference Optimization

vLLM, SGLang, TensorRT-LLM, speculative decoding, quantization, and serving at scale.


Inference Engines Comparison

Engine Backend Strengths Best For
vLLM CUDA, PagedAttention High throughput, easy API, OpenAI-compatible Production LLM serving
SGLang CUDA, RadixAttention Structured output, complex control flow, fast Agent workflows, constrained decoding
TensorRT-LLM TensorRT, FP8, plugins Maximum NVIDIA GPU perf, FP8 Max throughput on H100/H200
llama.cpp GGUF, CPU/Apple Silicon Edge, CPU, quantized Local, edge, mobile
TGI (Text Generation Inference) PyTorch, FlashAttention OpenAI-compatible, streaming, watermarking HuggingFace ecosystem
MNN/FastLLM Mobile/embedded Lightweight, no deps Mobile, embedded

vLLM Deep Dive

PagedAttention (Key Innovation)

Traditional: Contiguous KV cache → fragmentation, OOM
PagedAttention: KV cache in fixed-size blocks (pages)
              Logical blocks → Physical blocks (like OS virtual memory)

Core Features

from vllm import LLM, SamplingParams

llm = LLM(
    model="meta-llama/Meta-Llama-3.1-8B-Instruct",
    tensor_parallel_size=2,        # Multi-GPU
    gpu_memory_utilization=0.9,    # KV cache budget
    max_model_len=8192,            # Context window
    dtype="bfloat16",              # BF16 for H100
    quantization="awq",            # AWQ quantization
    enforce_eager=False,           # CUDA graphs
    max_num_seqs=256,              # Max concurrent
    max_num_batched_tokens=8192,   # Batch size
    enable_prefix_caching=True,    # Share prefix KV
    disable_log_stats=False
)

# OpenAI-compatible API
from vllm.entrypoints.openai import api_server
# Run: python -m vllm.entrypoints.openai.api_server --model ...

Sampling Parameters

params = SamplingParams(
    temperature=0.7,
    top_p=0.9,
    top_k=50,
    max_tokens=2048,
    stop=["</s>", "<|eot_id|>"],
    presence_penalty=0.0,
    frequency_penalty=0.0,
    repetition_penalty=1.0,
    # Structured output
    guided_decoding=GuidedDecodingParams(
        json=MySchema.model_json_schema()
    ),
    # Beam search
    use_beam_search=False,
    best_of=1,
    # Logprobs
    logprobs=5,
    prompt_logprobs=0
)

Advanced Features

# Prefix Caching (share KV for common prefixes)
llm = LLM(..., enable_prefix_caching=True)

# Chunked Prefill (long context)
llm = LLM(..., enable_chunked_prefill=True, max_num_batched_tokens=8192)

# LoRA Support
llm = LLM(..., enable_lora=True, max_lora_rank=64, max_loras=16)
# Runtime: llm.generate(prompt, lora_request=LoRARequest("adapter", 1, "path"))

# Speculative Decoding
llm = LLM(..., speculative_model="draft-model", num_speculative_tokens=5)

# Multi-LoRA
outputs = llm.generate(
    prompts,
    lora_request=LoRARequest("sql_adapter", 1, "./sql_lora")
)

SGLang (Structured Generation Language)

RadixAttention (Prefix Sharing)

Radix Tree of KV Cache:
                    Root
                   / | \
                  A  B  C
                 /|   |
                D E   F
Shared prefixes = shared KV cache = memory + speed

Structured Output

import sglang as sgl

@sgl.function
def structured_agent(s, query):
    s += "Analyze: " + query

    # Structured output with Pydantic
    class Analysis(sgl.StructuredOutput):
        issue_type: Literal["bug", "feature", "question"]
        severity: Literal["low", "medium", "high", "critical"]
        component: str
        suggested_fix: str

    s += sgl.gen("analysis", Analysis, temperature=0.3)
    return s

# Run
runtime = sgl.Runtime(model_path="meta-llama/Meta-Llama-3.1-8B-Instruct")
result = structured_agent.run("User reports login failure")
print(result["analysis"])  # Parsed Pydantic object

Complex Control Flow

@sgl.function
def multi_step_reasoning(s, problem):
    # Step 1: Plan
    s += "Plan: " + sgl.gen("plan", max_tokens=512)

    # Step 2: Execute each step
    for i in range(5):
        s += f"Step {i+1}: " + sgl.gen(f"step_{i}", max_tokens=256, stop="\n\n")

        # Conditional continuation
        if "DONE" in s[f"step_{i}"]:
            break

    # Step 3: Synthesize
    s += "Final Answer: " + sgl.gen("answer", max_tokens=512)
    return s

Parallel & Batch

# Automatic batching
@sgl.function
def batch_agent(s, queries: list[str]):
    fork = s.fork(len(queries))
    for i, q in enumerate(queries):
        fork[i] += "Answer: " + q
        fork[i] += sgl.gen("answer", max_tokens=256)
    return fork.join("answers")

# Automatic continuous batching
runtime = sgl.Runtime(..., chunked_prefill_size=2048)

TensorRT-LLM

FP8 Quantization (H100/H200)

# Convert to FP8
python examples/quantization/quantize.py \
    --model_dir /path/to/model \
    --output_dir /path/to/fp8_model \
    --dtype fp8 \
    --calib_size 512

Plugin System

// Custom kernels for:
// - FlashAttention
// - Fused MLP (SwiGLU)
// - RMSNorm + Residual
// - RoPE
// - Speculative decoding
// - Medusa heads

Inflight Batching

# Continuous batching with iteration-level scheduling
# Max throughput at high concurrency

Deployment

# Triton Inference Server
tritonserver --model-repository=/models \
    --model-control-mode=explicit \
    --load-model=llama3_8b_fp8

Speculative Decoding

Draft + Target

# Small draft model → Large target model
# Draft generates k tokens → Target verifies in parallel

async def speculative_generate(draft_model, target_model, prompt, k=5):
    tokens = prompt
    while len(tokens) < max_tokens:
        # Draft generates k tokens
        draft_tokens = await draft_model.generate(tokens, max_tokens=k)

        # Target scores all k+1 positions in parallel
        target_logits = await target_model.score(tokens + draft_tokens)

        # Verify each token
        accepted = []
        for i, (draft_logit, target_logit) in enumerate(zip(draft_logits, target_logits)):
            if accept_token(draft_logit, target_logit):
                accepted.append(draft_tokens[i])
            else:
                break

        tokens.extend(accepted)

        if len(accepted) < k:
            # Resample from target at rejection point
            next_token = sample(target_logits[len(accepted)])
            tokens.append(next_token)

    return tokens

Draft Model Options

Draft Model Speedup Quality Loss
Smaller same architecture 2-3x Minimal
Medusa heads 2-3x Minimal
EAGLE (draft from target) 2-4x Minimal
NGram/Simple 1.5-2x Higher
Self-speculative 1.5x None

Medusa / EAGLE

# Medusa: Additional heads on target model for drafting
class MedusaModel(nn.Module):
    def __init__(self, base_model, num_heads=5):
        self.base = base_model
        self.medusa_heads = nn.ModuleList([
            nn.Linear(d_model, vocab_size) for _ in range(num_heads)
        ])

    def forward(self, x):
        base_logits = self.base(x).logits
        medusa_logits = [h(x) for h in self.medusa_heads]
        return base_logits, medusa_logits

# EAGLE: Draft from target's own hidden states
# More accurate drafting, less quality loss

Quantization for Inference

Post-Training Quantization (PTQ)

# GPTQ (Layer-wise)
from auto_gptq import AutoGPTQForCausalLM

model = AutoGPTQForCausalLM.from_quantized(
    "TheBloke/Llama-3-8B-GPTQ",
    device="cuda:0",
    use_triton=False
)

# AWQ (Activation-aware)
from awq import AutoAWQForCausalLM

model = AutoAWQForCausalLM.from_quantized(
    "TheBloke/Llama-3-8B-AWQ",
    device="cuda:0"
)

Quantization Configs

# vLLM quantization
llm = LLM(
    model="TheBloke/Llama-3-8B-AWQ",
    quantization="awq",
    dtype="half"
)

# TensorRT-LLM FP8
# Best on H100/H200

# llama.cpp GGUF (CPU/Apple Silicon)
# q4_k_m: Best quality/size
# q8_0: Near FP16 quality

KV Cache Optimization

Prefix Caching

# vLLM: Automatic prefix caching
llm = LLM(..., enable_prefix_caching=True)

# Manual: Share KV for system prompt + few-shot
system_prompt = "You are a helpful assistant..."
few_shot = "Example 1...\nExample 2..."

# Both requests share KV for prefix
request1 = system_prompt + few_shot + "Query 1"
request2 = system_prompt + few_shot + "Query 2"

KV Cache Compression

# Quantization
# INT8 KV cache: 2x memory savings
llm = LLM(..., kv_cache_dtype="int8")

# Sliding Window
llm = LLM(..., sliding_window=4096)  # Only keep last 4k tokens

# Offloading (CPU offload)
llm = LLM(..., cpu_offload_gb=10)  # Offload 10GB to CPU RAM

Attention Optimizations

# FlashAttention-2 (H100)
# FlashAttention-3 (H100/H200, FP8)

# PagedAttention (vLLM) - already covered
# FlashDecoding (long context)
# RingAttention (multi-GPU context parallel)

Continuous Batching / Inflight Batching

# vLLM: Automatic
# SGLang: Automatic
# TensorRT-LLM: Inflight batching

# Key: Iteration-level scheduling
# New requests join queue, completed exit
# No padding waste, max GPU utilization

# Config
llm = LLM(
    max_num_seqs=256,           # Max concurrent
    max_num_batched_tokens=8192, # Token budget per iteration
    scheduling_policy="fcfs"     # fcfs, priority
)

Serving Patterns

OpenAI-Compatible API

# vLLM, SGLang, TGI all support
from openai import AsyncOpenAI

client = AsyncOpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")

# Chat
response = await client.chat.completions.create(
    model="meta-llama/Meta-Llama-3.1-8B-Instruct",
    messages=[{"role": "user", "content": "Hello"}],
    stream=True
)

# Completions
response = await client.completions.create(
    model="meta-llama/Meta-Llama-3.1-8B-Instruct",
    prompt="Once upon a time",
    max_tokens=100
)

Load Balancing

# Multiple replicas + load balancer
# vLLM: Data parallel (tensor_parallel_size) + multiple replicas

# Kubernetes
# Deployment: replicas=4, each with tensor_parallel_size=2
# Service: LoadBalancer
# Metrics: vLLM exposes /metrics for Prometheus

Monitoring & Metrics

Key Metrics

Metric Target
TTFT (Time to First Token) < 100ms (p99)
TPOT (Time per Output Token) < 50ms
Throughput Tokens/sec/GPU
GPU Utilization > 80%
KV Cache Hit Rate > 50% (with prefix caching)
Queue Time < 1s (p99)
Error Rate < 0.1%

Prometheus Metrics (vLLM)

# Exposed at /metrics
vllm:num_requests_running
vllm:num_requests_waiting
vllm:gpu_cache_usage_perc
vllm:iteration_tokens_total
vllm:request_latency_seconds


Sources: vLLM docs (vllm.ai), SGLang docs (sglang.ai), TensorRT-LLM docs, "PagedAttention" (Kwon et al.), "FlashAttention" (Dao et al.), "GPTQ" (Frantar et al.), "AWQ" (Lin et al.), "Medusa" (Cai et al.), "EAGLE" (Li et al.), "Speculative Decoding" (Leviathan et al.), TGI docs, llama.cpp, TensorRT-LLM benchmarks, NVIDIA H100 FP8 guides.

From the Agentic Engineering research vault · CC BY 4.0 · all notes · raw markdown