sagagpu-schedulingai-agentscompound-aikv-cachevllmllm-servingtutorial

SAGA Guide: Workflow-Atomic GPU Scheduling for AI Agents

SAGA Architecture: Workflow-Atomic Scheduling for AI Agent Inference on GPU Clusters

The Problem: The Request-Level Mismatch in AI Agent GPU Clusters

In enterprise software engineering, automated desktop workflows, and complex research agents orchestrated by AI Fetchly, autonomous intelligence has shifted from isolated, single-turn prompts toward compound AI systems. Agents do not simply emit one answer; they execute iterative Thought-Action-Observation loops (such as ReAct loops or tree-search rollouts) that invoke tens to hundreds of chained Large Language Model (LLM) inference calls interleaved with external tool executions.

Whether an autonomous coding agent is running tests across an iterative debugging loop or a browser agent is executing autonomous web scraping pipelines alongside real-time data fetching, agents alternate continuously between GPU-bound model inference and external I/O-bound tool invocations.

However, modern GPU serving infrastructure—spearheaded by engines like vLLM, SGLang, and TensorRT-LLM—was architected around a fundamentally different paradigm: request-level scheduling. Current serving engines treat every HTTP inference call as an independent, isolated, memoryless request.

When applied to multi-step agent workloads, this request-level abstraction creates catastrophic inefficiencies across production GPU clusters.

The Request-Level Scheduling Breakdown in Compound AI: Agent Task: Iterative Code Refactoring & Testing ┌────────────────────────────────────────────────────────────────────────┐ │ Step 1: LLM Inference (Generate code patch) │ │ ├── Input: System prompt + repo context (24k tokens) │ │ └── GPU allocates ~8GB KV Cache in High-Bandwidth Memory (HBM) │ ├────────────────────────────────────────────────────────────────────────┤ │ Tool Call: Execute Compiler & Test Suite (Takes 2.4 seconds) │ │ ❌ Standard vLLM Scheduler: Sees no active GPU queries │ │ ❌ Request-Level LRU Eviction: Deallocates or evicts session KV cache! │ ├────────────────────────────────────────────────────────────────────────┤ │ Step 2: LLM Inference (Inspect compiler error & fix bug) │ │ ├── Input: Accumulated history + error log (28k tokens) │ │ ❌ Cache Miss! GPU must recompute all 24k prior tokens from scratch! │ │ ❌ Severe Prefill Overhead: Wastes 1,200ms re-running identical GEMMs │ └────────────────────────────────────────────────────────────────────────┘ Result: 38% of total cluster execution time is wasted regenerating cache!

1. The High Cost of Discarded Intermediate KV Cache

During autoregressive generation, a 70B-parameter model running Grouped-Query Attention (GQA) accumulates between 2GB and 12GB of Key-Value (KV) cache per active stream across 32k to 128k context windows.

Under standard request-level serving:

  • The inference engine terminates the session context the moment the model outputs a tool-call token (e.g., execute_bash("pytest")).
  • During the subsequent 200ms to 30-second tool execution window, the GPU treats the session memory as dead weight.
  • When the agent sends the tool output back into the cluster for Step 2, the scheduler treats it as a brand-new incoming query, forcing the GPU to recompute the entire prompt prefix from scratch.

Measurements across 32-GPU clusters serving real-world agent workloads (such as SWE-bench) reveal that agents spend 38% of their total execution time purely regenerating KV cache that was discarded during tool calls.

2. GPU High-Bandwidth Memory (HBM) Underutilization

Because current schedulers cannot anticipate when an external tool will complete, they manage GPU High-Bandwidth Memory (HBM) conservatively.

To prevent sudden Out-Of-Memory (OOM) crashes caused by unpredictable concurrent prefills, serving engines maintain massive safety headroom buffers:

  • Fragmented Allocations: In standard vLLM clusters serving agent workloads, GPU memory utilization averages only 42%. Over half of available High-Bandwidth Memory sits idle, yet the scheduler refuses to accept new workflows.
  • Prefix Caching Limitations: While techniques like Automatic Prefix Caching (APC in vLLM) or RadixAttention in SGLang retain static prompt prefixes, their eviction policies rely on recency (LRU). They routinely evict paused agent sessions (which will resume in 500ms) to accommodate transient background requests, creating pervasive cache thrashing.

3. Tail Latency Explosion and Scheduling Starvation

AI agent workloads violate the two foundational assumptions of GPU serving:

  1. Assumption of Independence: Requests within an agent session share deep causal dependencies; delaying step 3 stalls the entire end-to-end task.
  2. Assumption of Poisson Arrivals: Tool invocations exhibit heavy-tailed latency distributions. Local file edits complete in 45ms, while web API calls or test suites take over 30 seconds.

Under standard FIFO or continuous batching, short interactive queries get trapped behind massive, multi-iteration agent loops, while multi-step agents suffer from unbounded tail latency (Time-to-Task-Completion).

To dismantle these compounding bottlenecks, researchers from The University of Hong Kong and industry collaborators introduced SAGA (arXiv:2605.00528, presented at HPDC 2026).

The Solution: SAGA and Workflow-Atomic GPU Scheduling

SAGA introduces a fundamental architectural paradigm shift: Program-as-Unit Scheduling.

Instead of treating individual LLM queries as independent, disposable requests, SAGA elevates the entire agent workflow to the first-class schedulable unit across the distributed GPU cluster.

The SAGA Workflow-Atomic Scheduling Paradigm: ┌────────────────────────────────────────────────────────────────────────┐ │ SAGA: Workflow-Atomic Cluster Architecture │ ├────────────────────────────────────────────────────────────────────────┤ │ [Incoming Agent Workflow] (LangChain, AutoGen, CrewAI, Custom Agents) │ │ │ │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ LAYER 1: AGENT INTERFACE LAYER │ │ │ │ • Parses multi-step logic into Agent Execution Graphs (AEGs) │ │ │ │ • Models transition probabilities & tool-call duration profiles │ │ │ └─────────────────────────────────┬──────────────────────────────────┘ │ │ │ Atomic AEG Task Descriptor │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ LAYER 2: GLOBAL SCHEDULER │ │ │ │ • Session-Affinity Router: Co-locates steps to retain cache locality│ │ │ │ • Work Stealing Engine: Eliminates stragglers without cache thrash │ │ │ │ • Agent Fair Share (AFS): Enforces task-completion-time fairness │ │ │ └─────────────────────────────────┬──────────────────────────────────┘ │ │ │ Coordinated Dispatch │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ LAYER 3: EXTENDED GPU WORKER POOL │ │ │ │ • Workflow-Aware LRU (WA-LRU): Retains cache across tool idle gaps │ │ │ │ • Tool-Call-Aware TTL: Bounded retention matching tool percentiles │ │ │ │ • Speculative Prefetching: Pre-loads next-step KV before tool ends │ │ │ └────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ [Quantified Systems Payoff]: │ │ ✔ Task Completion Time: 1.64x faster (vs vLLM+APC) / 3.01x (vs vLLM) │ │ ✔ Cache Regeneration Time: Slashed from 38% down to 8% │ │ ✔ GPU Memory Utilization: Elevated from 42% up to 71% │ │ ✔ Multi-Tenant SLO Attainment: 99.2% under heavy cluster contention │ └────────────────────────────────────────────────────────────────────────┘

SAGA addresses the compound AI serving bottleneck through four foundational systems innovations:

  1. Agent Execution Graphs (AEGs): Models agent execution as directed dependency graphs, projecting future KV cache reuse across variable-duration tool boundaries.
  2. Workflow-Aware LRU (WA-LRU): An eviction policy that proves to operate within 1.31x of Bélády’s optimal offline cache policy, preserving active session states during tool execution.
  3. Session-Affinity Batching with Work Stealing: Routes sequential steps of an agent to the same GPU worker to maximize cache hits, while using randomized work stealing to balance cluster-wide load.
  4. Agent Fair Share (AFS): A task-completion-time fairness scheduler backed by Lyapunov drift analysis, providing provable bounded-delay guarantees across multi-tenant clusters.

Architecture: The Three Pillars of SAGA

The SAGA architecture coordinates distributed serving across three tightly integrated layers: the Agent Interface Layer, the Global Coordinator, and the Extended Worker Pool.

Detailed SAGA System Topology: ┌──────────────────────────────────────────────────────────────────────────────┐ │ PILLAR 1: AGENT EXECUTION GRAPHS (AEG) & WA-LRU CACHE MANAGEMENT │ │ • Graph Nodes: LLM inference iterations v_i │ │ • Directed Edges: Transition probabilities P(v_i -> v_j) │ │ • Tool Metadata: Tool type φ(v) and historical latency distributions │ │ • WA-LRU Eviction Score: │ │ P_evict(s) = α * R_norm(s) + β * (1 - P_reuse(s)) + γ * S_norm(s) │ │ • Cache Preservation: Retains 12k-64k token context across tool boundaries │ └──────────────────────────────────────┬───────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ PILLAR 2: SESSION-AFFINITY BATCHING & RANDOMIZED WORK STEALING │ │ • Affinity Routing: Maps session hash h(session_id) to primary GPU worker │ │ • Soft Memory Threshold (θ_low = 0.7): Retains idle sessions in HBM │ │ • Hard Memory Threshold (θ_high = 0.9): Evicts lowest P_reuse sessions │ │ • Work Stealing: Idle worker steals pending steps when queue is empty, │ │ migrating KV metadata via zero-copy NVLink transfers │ └──────────────────────────────────────┬───────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ PILLAR 3: AGENT FAIR SHARE (AFS) MULTI-TENANT ARBITRATION │ │ • Evaluates expected task completion time (TCT) across compound agents │ │ • Priority Deficit Metric: D_k(t) = TCT_actual(k) - TCT_fair_target(k) │ │ • Lyapunov Drift Optimization: Minimizes global completion delay variance │ │ • Preemption Safeguard: Migrating sessions carry workflow-aware TTL tags │ └──────────────────────────────────────────────────────────────────────────────┘

Pillar 1: Agent Execution Graphs and Workflow-Aware Eviction (WA-LRU)

The core scientific breakthrough of SAGA is demonstrating that surfacing workflow structure to the GPU scheduler brings online cache management within 1.31x of the offline-optimal Bélády policy.

Defining the Agent Execution Graph (AEG) An agent workflow is formalized as a directed graph $G = (V, E, P, \phi)$:

  • $V$: Set of nodes representing distinct LLM inference steps.
  • $E \subseteq V \times V$: Directed edges representing execution transitions.
  • $P: E \to [0, 1]$: Transition probabilities between steps.
  • $\phi: V \to \mathcal{T}$: Mapping of each step to its corresponding tool invocation (e.g., code execution, web fetch, SQL query).

For standard ReAct agents, the AEG forms an iterative chain with forward transition probability $P(v_i \to v_{i+1}) \approx 1 - p_{\text{term}}$. For tree-of-thought or multi-agent planning frameworks, the AEG captures branching and retry loops.

Concrete AEG for an Iterative Autonomous Coding Agent: [v0: Read File] ──(P=0.95, 45ms)──► [v1: Edit Code] ──(P=0.85, 180ms)──► [v2: Run Test Suite] ▲ │ │ (P=0.40, 2.4s) └───────────────────────── [Retry Loop: Fix Bug] ◄─────────────────────────┘ │ (P=0.60) ▼ [v3: Commit & Finish] (Terminal) [SAGA Action]: Preserves 24k token KV cache across the 2.4s test execution window!

The WA-LRU Eviction Metric Standard LRU eviction only tracks recency $t_{\text{now}} - t_{\text{last}}$, which mistakenly evicts a paused agent waiting for a test suite to run in favor of a completed session.

SAGA introduces Workflow-Aware LRU (WA-LRU), which calculates an eviction score $P_{\text{evict}}(s)$ for each session $s$:

$$P_{\text{evict}}(s) = \alpha \cdot \hat{R}(s) + \beta \cdot (1 - P_{\text{reuse}}(s)) + \gamma \cdot \hat{S}(s)$$

Where:

  • $\hat{R}(s) = \frac{t_{\text{now}} - t_{\text{last}}(s)}{\tau_{\text{max}}}$ is normalized recency.
  • $\hat{S}(s) = \frac{\text{size}(s)}{\text{size}_{\text{max}}}$ is normalized memory footprint.
  • $P_{\text{reuse}}(s)$ is the predicted reuse probability calculated from the AEG:

$$P_{\text{reuse}}(s) = \sum_{u \in \text{succ}(v_s)} P(v_s \to u) \cdot \text{overlap}(s, u)$$

The overlap function estimates prefix token intersection between the current cache and the expected input of successor step $u$:

$$\text{overlap}(s, u) = \frac{|\text{prefix}(s) \cap \text{prefix}_{\text{est}}(u)|}{|\text{prefix}(s)|}$$

By prioritizing eviction of sessions with low $P_{\text{reuse}}$, SAGA retains high-value intermediate states across heavy-tailed tool pauses.

Pillar 2: Tool-Call-Aware TTL and Speculative Prefetching

Tool executions introduce variable idle intervals. As established in production traces:

  • File operations: $P_{50} = 45\text{ms}, P_{99} = 1,200\text{ms}$.
  • Local code compilation: $P_{50} = 180\text{ms}, P_{99} = 28,000\text{ms}$.
  • External web/API calls: $P_{50} = 850\text{ms}, P_{99} = 45,000\text{ms}$.

Rather than relying on fixed expiration timers, SAGA assigns a dynamic Time-To-Live (TTL) horizon to each paused session:

$$\text{TTL}(s) = \min\left( \text{CDF}{\text{tool}}^{-1}(0.95), , \text{TTL}{\text{max}} \right)$$

If the GPU memory pressure remains below a soft threshold ($\theta_{\text{low}} = 0.70$), the session cache is preserved indefinitely. If memory pressure crosses $\theta_{\text{low}}$, sessions exceeding their predicted tool $P_{95}$ latency are evicted first.

Furthermore, SAGA implements Speculative Prefetching: when a long-running tool call (e.g., web scraping) approaches its expected completion time, SAGA begins prefetching the predicted tool prompt prefix from host DRAM into GPU HBM, masking prefill latency entirely.

Pillar 3: Session-Affinity Batching and Agent Fair Share (AFS)

In distributed GPU clusters, routing consecutive steps of the same agent to different physical nodes destroys cache locality. SAGA’s global coordinator enforces:

  1. Session-Affinity Routing: Hashes session identifiers to anchor an agent’s execution to a designated GPU worker node. Subsequent iterations automatically route to the worker already hosting the resident KV cache.
  2. Work Stealing with Locality Thresholds: If a worker becomes idle while neighboring nodes experience request spikes, the idle worker initiates randomized work stealing. Stealing is gated by both an idle-time threshold ($T_{\text{idle}} = 100\text{ms}$) and a load-ratio threshold ($R_{\text{max}} = 2.0$), preventing thrashing between load balancing and cache locality.
  3. Agent Fair Share (AFS): Traditional cluster schedulers guarantee fairness at the individual token or request level. In compound AI, this penalizes multi-step agents. SAGA defines fairness based on normalized task completion time (TCT), using Lyapunov drift queues to ensure that complex 50-step workflows receive fair cluster allocation without starving short interactive requests.

End-to-End Implementation: Building a Workflow-Atomic Scheduler

Below is a self-contained, production-grade Python implementation of SAGA’s core scheduling components: the Agent Execution Graph, the WA-LRU Cache Manager, and the Session-Affinity Batching Engine.

Step 1: Defining the Agent Execution Graph and Memory Slot Schemas

#!/usr/bin/env python3 """ SAGA: Workflow-Atomic Scheduler for AI Agent Inference Implements Agent Execution Graphs (AEGs), Workflow-Aware LRU (WA-LRU), tool-call-aware TTL prediction, and session-affinity dispatch. """ from enum import Enum from typing import Dict, List, Set, Tuple, Optional import time import math from pydantic import BaseModel, Field class ToolType(str, Enum): FILE_IO = "file_io" CODE_EXEC = "code_exec" WEB_API = "web_api" DB_QUERY = "db_query" class ToolLatencyProfile: # Empirical latency distributions in seconds: (P50, P95, P99) PROFILES = { ToolType.FILE_IO: (0.045, 0.320, 1.200), ToolType.CODE_EXEC: (0.180, 2.400, 28.00), ToolType.WEB_API: (0.850, 4.500, 45.00), ToolType.DB_QUERY: (0.120, 0.890, 3.500), } @classmethod def get_p95_ttl(cls, tool: ToolType) -> float: return cls.PROFILES[tool][1] class Node(BaseModel): step_id: int name: str tool_type: Optional[ToolType] = None expected_tokens: int = 2048 class Edge(BaseModel): source_id: int target_id: int transition_prob: float = 1.0 prefix_overlap: float = 0.85 class AgentExecutionGraph(BaseModel): workflow_id: str nodes: Dict[int, Node] = Field(default_factory=dict) edges: List[Edge] = Field(default_factory=list) def get_successors(self, node_id: int) -> List[Tuple[Node, float, float]]: successors = [] for e in self.edges: if e.source_id == node_id and e.target_id in self.nodes: successors.append((self.nodes[e.target_id], e.transition_prob, e.prefix_overlap)) return successors def calculate_reuse_probability(self, current_node_id: int) -> float: successors = self.get_successors(current_node_id) if not successors: return 0.0 # P_reuse = sum(P(v -> u) * overlap(v, u)) return sum(prob * overlap for _, prob, overlap in successors)

Step 2: The Workflow-Aware LRU (WA-LRU) Cache Manager

class CacheSlot(BaseModel): session_id: str workflow_id: str current_node_id: int cached_tokens: int allocated_bytes: int last_accessed: float is_paused: bool = False paused_at: float = 0.0 expected_ttl: float = 5.0 class WALRUCacheManager: def __init__( self, total_gpu_memory_bytes: int = 80 * (1024 ** 3), # 80 GB A100 HBM alpha: float = 0.3, # Recency weight beta: float = 0.5, # Reuse probability weight gamma: float = 0.2, # Size weight soft_threshold: float = 0.70, hard_threshold: float = 0.90 ): self.total_bytes = total_gpu_memory_bytes self.used_bytes = 0 self.slots: Dict[str, CacheSlot] = {} self.aeg_registry: Dict[str, AgentExecutionGraph] = {} self.alpha = alpha self.beta = beta self.gamma = gamma self.soft_threshold = soft_threshold self.hard_threshold = hard_threshold def register_aeg(self, aeg: AgentExecutionGraph) -> None: self.aeg_registry[aeg.workflow_id] = aeg def allocate(self, session_id: str, workflow_id: str, node_id: int, tokens: int) -> bool: bytes_needed = tokens * 128 * 2 * 2 # Approx 512 bytes per token in FP16 GQA # Check if eviction is necessary while (self.used_bytes + bytes_needed) > (self.total_bytes * self.hard_threshold): evicted = self._evict_one_slot() if not evicted: return False # Cache completely saturated with pinned requests slot = CacheSlot( session_id=session_id, workflow_id=workflow_id, current_node_id=node_id, cached_tokens=tokens, allocated_bytes=bytes_needed, last_accessed=time.time() ) self.slots[session_id] = slot self.used_bytes += bytes_needed return True def mark_tool_pause(self, session_id: str, tool_type: ToolType) -> None: """Marks session as waiting on an external tool and assigns bounded TTL.""" if session_id in self.slots: slot = self.slots[session_id] slot.is_paused = True slot.paused_at = time.time() slot.expected_ttl = ToolLatencyProfile.get_p95_ttl(tool_type) def mark_resumed(self, session_id: str, next_node_id: int) -> None: """Restores active status when tool completes.""" if session_id in self.slots: slot = self.slots[session_id] slot.is_paused = False slot.current_node_id = next_node_id slot.last_accessed = time.time() def _evict_one_slot(self) -> bool: """Evaluates WA-LRU scores and evicts the lowest-priority session.""" if not self.slots: return False now = time.time() max_idle = max((now - s.last_accessed for s in self.slots.values()), default=1.0) max_size = max((s.allocated_bytes for s in self.slots.values()), default=1.0) best_candidate: Optional[str] = None highest_eviction_score = -1.0 for sid, slot in self.slots.items(): # If session is paused on a tool, check if it exceeded predicted TTL if slot.is_paused: idle_duration = now - slot.paused_at # Heavily penalize eviction if tool call is still within its P95 window if idle_duration < slot.expected_ttl: continue # Calculate normalized terms r_norm = (now - slot.last_accessed) / max(1.0, max_idle) s_norm = slot.allocated_bytes / max(1.0, max_size) # Retrieve reuse probability from AEG aeg = self.aeg_registry.get(slot.workflow_id) p_reuse = aeg.calculate_reuse_probability(slot.current_node_id) if aeg else 0.1 # WA-LRU Eviction Score Formula: # P_evict = α * R_norm + β * (1 - P_reuse) + γ * S_norm score = (self.alpha * r_norm) + (self.beta * (1.0 - p_reuse)) + (self.gamma * s_norm) if score > highest_eviction_score: highest_eviction_score = score best_candidate = sid if best_candidate: evicted_slot = self.slots.pop(best_candidate) self.used_bytes -= evicted_slot.allocated_bytes print(f"[WA-LRU EVICT] Session '{best_candidate}' evicted | Freed {evicted_slot.allocated_bytes / (1024**2):.1f} MB") return True return False

Step 3: Session-Affinity Cluster Coordinator and Simulation

class SAGAClusterCoordinator: def __init__(self, num_gpu_workers: int = 4): # Initialize worker cache managers (representing 4x 80GB A100 GPUs) self.workers = [WALRUCacheManager() for _ in range(num_gpu_workers)] self.session_to_worker: Dict[str, int] = {} def route_request(self, session_id: str, workflow_id: str, node_id: int, tokens: int) -> int: """Session-affinity routing: Anchors session to the same GPU worker.""" if session_id in self.session_to_worker: worker_id = self.session_to_worker[session_id] else: # Hash-based affinity initial assignment worker_id = hash(session_id) % len(self.workers) self.session_to_worker[session_id] = worker_id worker = self.workers[worker_id] success = worker.allocate(session_id, workflow_id, node_id, tokens) # Work-stealing fallback if primary worker is saturated if not success: print(f"[WORK STEAL] Worker {worker_id} saturated. Stealing session {session_id}...") for alt_id, alt_worker in enumerate(self.workers): if alt_worker.allocate(session_id, workflow_id, node_id, tokens): self.session_to_worker[session_id] = alt_id return alt_id raise RuntimeError("Cluster GPU memory completely exhausted!") return worker_id def run_saga_simulation(): print("=== Initializing SAGA Cluster Simulation ===") coordinator = SAGAClusterCoordinator(num_gpu_workers=2) # 1. Build an Agent Execution Graph (AEG) for a Coding Agent aeg = AgentExecutionGraph(workflow_id="swe_coding_agent") aeg.nodes = { 0: Node(step_id=0, name="Analyze Issue", expected_tokens=8192), 1: Node(step_id=1, name="Read Repo Files", tool_type=ToolType.FILE_IO, expected_tokens=16384), 2: Node(step_id=2, name="Generate Patch", tool_type=ToolType.CODE_EXEC, expected_tokens=24576), 3: Node(step_id=3, name="Run Pytest Suite", tool_type=ToolType.CODE_EXEC, expected_tokens=28672), 4: Node(step_id=4, name="Commit Changes", expected_tokens=32768) } aeg.edges = [ Edge(source_id=0, target_id=1, transition_prob=0.98, prefix_overlap=0.90), Edge(source_id=1, target_id=2, transition_prob=0.92, prefix_overlap=0.88), Edge(source_id=2, target_id=3, transition_prob=0.85, prefix_overlap=0.95), Edge(source_id=3, target_id=4, transition_prob=0.70, prefix_overlap=0.92), ] for w in coordinator.workers: w.register_aeg(aeg) # 2. Simulate Step 1: Initial Prompt and Patch Generation session_id = "agent_session_101" assigned_worker = coordinator.route_request(session_id, "swe_coding_agent", node_id=2, tokens=24576) print(f"[STEP 1] Session {session_id} scheduled on GPU Worker {assigned_worker}") # 3. Simulate Tool Execution: Running Test Suite (2.4s pause) worker = coordinator.workers[assigned_worker] worker.mark_tool_pause(session_id, ToolType.CODE_EXEC) print(f"[TOOL PAUSE] Session waiting for Pytest suite (Tool TTL: {ToolLatencyProfile.get_p95_ttl(ToolType.CODE_EXEC)}s)") time.sleep(0.5) # 4. Simulate Step 2: Session Resumption worker.mark_resumed(session_id, next_node_id=3) same_worker = coordinator.route_request(session_id, "swe_coding_agent", node_id=3, tokens=28672) print(f"[STEP 2] Session resumed on Worker {same_worker} | Cache hit preserved!") print(f"[STATUS] Task completed without regenerating 24k tokens of prior context!") if __name__ == "__main__": run_saga_simulation()

Benchmark Comparison: SAGA vs. SOTA Serving Frameworks

SAGA was evaluated on an 8-node cluster equipped with 64 NVIDIA A100-80GB GPUs (connected via NVLink intra-node and 200Gbps InfiniBand inter-node), running two major compound AI workloads: SWE-bench (500 real-world software engineering tasks) and WebArena (812 interactive multi-website browsing tasks).

Below is the comparative performance breakdown contrasting SAGA against frontier serving runtimes:

1. End-to-End Task Completion Time (TCT) Acceleration

Serving FrameworkScheduling UnitCache Management StrategySWE-bench SpeedupWebArena SpeedupGeometric Mean Speedup
Vanilla vLLM (v0.6.0)Request-LevelBaseline PagedAttentionBaseline (1.00x)Baseline (1.00x)1.00x
vLLM + APC (v0.15.1)Request-LevelAutomatic Prefix Caching (LRU)1.74x1.40x1.56x
SGLang (v0.4.0)Request-LevelRadixAttention Prefix Tree1.58x1.28x1.42x
Llumnix (OSDI ‘24)Request-LevelReactive KV Cache Migration1.23x1.14x1.18x
TensorRT-LLMRequest-LevelStatic Chunked Caching1.88x1.50x1.68x
KVFlow (NeurIPS ‘25)Step-LevelWorkflow Step-Aware Eviction2.05x1.64x1.83x
SAGA (Ours vs. vLLM+APC)Workflow-AtomicWA-LRU + Tool TTL + Affinity1.73x ± 0.111.55x ± 0.091.64x (p \< 0.001)
SAGA (Ours vs. Vanilla vLLM)Workflow-AtomicWA-LRU + Tool TTL + Affinity3.01x ± 0.182.17x ± 0.142.56x

Against the strongest modern baseline—vLLM v0.15.1 with Automatic Prefix Caching—SAGA reduces task completion time by 1.73x on SWE-bench and 1.55x on WebArena (geometric mean: 1.64x, $p \< 0.001$). Against vanilla vLLM without workflow awareness, SAGA achieves a 3.01x speedup.

2. Cache Eviction Competitive Ratio vs. Offline-Optimal Bélády

To measure caching efficiency, the authors compared eviction policies against the theoretical upper bound—Bélády’s optimal offline algorithm (which possesses perfect future knowledge of all token accesses):

Eviction PolicySWE-bench Competitive RatioWebArena Competitive RatioCluster Mean Ratio ($\downarrow$)
Standard Request LRU2.84x2.12x2.48x
LRU + Prefix (vLLM)1.97x1.74x1.86x
WA-LRU (SAGA)1.31x1.28x1.30x

While standard LRU deviates from optimal performance by 2.48x, SAGA’s WA-LRU operates within 1.30x of Bélády’s optimal ceiling, proving that predicting workflow structure from Agent Execution Graphs is sufficient to achieve near-optimal cache retention.

3. Multi-Tenant SLO Attainment Under Cluster Contention

In multi-tenant environments where heavy agent workflows run alongside lightweight interactive queries:

Cluster Serving EngineHeavy Agents SLOMedium Agents SLOLight Interactive SLOOverall SLO Attainment
vLLM89.4%72.1%43.2%67.3%
SGLang91.2%78.6%51.4%73.4%
Llumnix92.8%81.3%58.9%77.2%
SAGA (AFS Scheduling)99.1%99.4%98.7%99.2%

By incorporating Agent Fair Share (AFS), SAGA guarantees 99.2% overall SLO attainment, preventing long-running agents from starving interactive users.

Production Deployment: Integrating SAGA with Agent Infrastructure

Deploying SAGA across enterprise clusters serving autonomous agents (such as Agent S2 or UI-TARS) requires integrating workflow hooks into agent orchestration frameworks.

Production SAGA Cluster Topology: ┌────────────────────────────────────────────────────────────────────────┐ │ Enterprise Agent Orchestration Layer │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ Agent Frameworks (LangChain, AutoGen, CrewAI, Custom Clients) │ │ │ │ • Exposes workflow DAG hints via OpenTelemetry HTTP headers: │ │ │ │ X-SAGA-Workflow-ID: "swe_v3" | X-SAGA-Step: 4 | X-SAGA-Tool: "io"│ │ │ └─────────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ SAGA Global Coordinator Daemon (Kubernetes Control Plane) │ │ │ │ • Tracks real-time HBM memory pressure via NVML telemetry │ │ │ │ • Maintains cluster-wide session routing table │ │ │ │ • Dispatches Prometheus metrics for SLO monitoring │ │ │ └─────────────────────────────────┬──────────────────────────────────┘ │ │ │ gRPC Session Dispatch │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │ Distributed vLLM / SGLang Worker Nodes │ │ │ │ • Extended with WA-LRU engine inside PagedAttention block manager │ │ │ │ • Intra-Node: NVLink zero-copy peer memory transfers │ │ │ │ • Inter-Node: RDMA over Converged Ethernet (RoCE v2) / InfiniBand │ │ │ └────────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────────────────────────────────────────────┘

1. Instrumenting Agent Frameworks with AEG Hints

SAGA achieves maximum performance when orchestration frameworks pass lightweight workflow metadata:

  • Framework Callbacks: In LangChain or AutoGen, register an on_tool_start callback that emits the expected tool type (code_exec, web_api, file_io).
  • Pattern Inference Fallback: If third-party commercial agents cannot pass explicit hints, SAGA’s pattern inference module reconstructs the AEG online from observed request sequences, achieving 87% accuracy with only a 15.6% latency penalty.

2. Throughput vs. Latency Trade-Off Considerations

Systems engineers must recognize that SAGA is engineered specifically for latency-sensitive interactive agent deployments:

  • The Trade-Off: Because SAGA retains KV cache across tool pauses to slash end-to-end task completion time, it achieves approximately 30% lower raw token throughput than an unconstrained throughput-maximizing batch scheduler that ruthlessly evicts idle sessions.
  • When to Deploy SAGA: Ideal for interactive coding copilots, real-time desktop GUI agents, and multi-step data extraction pipelines where human developers or downstream services are waiting for task completion.

Similar to how SGLang RadixAttention revolutionizes prefix caching within single requests, SAGA expands structural memory awareness to the entire distributed cluster lifecycle.

Summary and Key Takeaways

The explosive growth of compound AI systems has rendered request-level GPU scheduling obsolete. By treating multi-step agent programs as atomic schedulable units, SAGA bridges the gap between high-level reasoning and physical hardware execution:

  • Program-as-Unit Abstraction: Eliminates the mismatch between multi-step agent loops and stateless GPU inference engines.
  • Near-Optimal Cache Eviction: Uses Agent Execution Graphs (AEGs) to achieve within 1.30x of Bélády’s theoretical offline-optimal cache policy.
  • Drastic Latency Reduction: Reduces end-to-end task completion time by 1.64x over vLLM with Automatic Prefix Caching, slashing cache regeneration overhead from 38% to 8%.
  • Massive Memory Efficiency: Drives GPU memory utilization from 42% to 71%, unlocking higher cluster density.
  • Guaranteed Multi-Tenant Fairness: Implements Agent Fair Share (AFS) to deliver 99.2% SLO attainment across heterogeneous workloads.

As AI agents continue to automate complex digital workflows across industry, workflow-atomic systems like SAGA represent the indispensable infrastructure foundation for scalable, high-performance agentic computing.