EfficientAgent: What Makes KV Cache Offloading Work for Concurrent Agents?
Organizations: The Hong Kong University of Science and Technology · Huawei Technologies Ltd. · The University of Hong Kong · Sun Yat-sen University
Abstract
LLM agents resend their whole conversation on every turn, and most of it was already processed on the previous turn. Serving systems avoid recomputing it by caching its key-value (KV) state and, when GPU memory runs out, by offloading that state to host memory. For agents, offloading gives inconsistent results: on the same coding-agent workload it speeds up one deployment, slows down another, and changes nothing on a third, even where loading a token back is several times cheaper than recomputing it. The reason is that cached state must survive until it is used again. While one agent waits for its tool, the server processes the contexts of all other agents, so an agent's prefix is reused only if the host tier holds the reusable context of the whole agent pool, which we call the reuse working set. A smaller tier keeps writing state that is evicted before anyone reads it. We present EfficientAgent, which sizes and manages the host tier by this working set. A stack-distance model estimates the working set from agent histories to size the host tier; its predictions, made before the experiments, located the capacity at which offloading starts to pay. When the tier is too small, a runtime policy stops writing large refills of evicted context and keeps extending prefixes that are still cached; when the tier is large enough, it writes everything. On SWE-bench Verified coding agents, a host tier sized to the estimated working set cuts recomputed prompt tokens by 93% and end-to-end time by 39%. With a small fixed tier, the policy cuts recomputation by 35%; with a large tier, it avoids the 4.3-fold increase caused by always filtering writes. Across three GPU types and two models, offloading pays off when the GPU has little compute per byte of host bandwidth and the host tier holds the working set. Code is available at https://github.com/KunmingSHAO/efficientagent_release.
Figures & tables
| GPU | BF16 TFLOPS | Host link (GB/s) | Memory (GB) | FLOP/byte | Offload/recompute |
|---|---|---|---|---|---|
| RTX 3090 | 71 | PCIe Gen4, 32 | 24 | 2.2K | 0.91 ; dense 0.92 |
| H20 | 148 | PCIe Gen5, 64 | 96 | 2.3K | 0.60 (tier working set) |
| H800 | 989.5 | PCIe Gen5, 64 | 80 | 15.5K | 1.08–1.87; dense 1.23 |
Appendix figures & tables12 assets
Supplementary material from the paper’s appendix.
Appendix
| Setting | Value |
|---|---|
| Model / precision | Qwen3-Coder-30B-A3B-Instruct / BF16 |
| Maximum model context | 262,144 tokens |
| Running-request cap | 16 ( max_num_seqs ) |
| Scheduler token budget | 8,192; chunked prefill enabled |
| GPU prefix caching | Enabled |
| Active pool | 16; 8 in the concurrency comparison |
| Configuration | CPU GiB | Time (min) | Prefill M | Retrieved M | Stored M | Preempt. | |
| Recompute | 16 | 0 | 211.69 | 89.66 | 0 | 0 | 2,190 |
| Recompute, repeat | 16 | 0 | 205.98 | 89.82 | 0 | 0 | 2,203 |
| Offload | 16 | 5 | 208.91 | 76.74 | 12.57 | 81.69 | 1,808 |
| Offload | 16 | 10 | 161.06 | 23.53 | 65.20 | 22.42 | 437 |
| Offload | 16 | 20 | 128.05 | 5.28 | 82.77 | 4.06 | 46 |
| Offload | 16 | 40 | 124.01 | 5.27 | 82.43 | 4.06 | 52 |
| Host GiB | Predicted prefill | Measured prefill | Predicted restore | Measured restore |
|---|---|---|---|---|
| 10 | 27.64–31.20 | 23.53 | 55.28–58.88 | 65.20 |
| 20 | 5.19–5.78 | 5.28 | 80.84–81.36 | 82.77 |
| 80 | 5.19–5.31 | 5.29 | 81.31–81.36 | 82.89 |
| Host GiB | Predicted prefill | Measured prefill | Predicted restore | Measured restore |
|---|---|---|---|---|
| 0 | 41.87–60.80 | 41.48 | 0 | 0 |
| 3 | 29.59–52.01 | 28.99 | 7.51–12.28 | 13.01 |
| 4.5 | 18.84–31.73 | 17.11 | 22.25–29.36 | 13.22 |
| Qwen3-Coder-30B-A3B-Instruct | Qwen2.5-Coder-32B-Instruct | |||||
| TP ranks | Heads/rank | KiB/rank | Aggregate KiB | Heads/rank | KiB/rank | Aggregate KiB |
| 1 | 4 | 96 | 96 | 8 | 256 | 256 |
| 2 | 2 | 48 | 96 | 4 | 128 | 256 |
| 4 | 1 | 24 | 96 | 2 | 64 | 256 |
| 8 | 1 | 24 | 192 | 1 | 32 | 256 |
| Parameter | Value |
|---|---|
| Cache occupancy threshold | 0.95 |
| Task activity and eviction window | 60 seconds |
| Prompt-length window | Last 256 first prefix lookups |
| Telemetry report interval | 1 second |
| Scheduler report-read interval | 0.5 seconds |
| Maximum age of a fresh report | 5 seconds |
| Hardware | Model | Recompute | Offload | Ratio |
|---|---|---|---|---|
| Workflow wall-clock | ||||
| RTX 3090 | MoE | 407 min | 369 min | 0.91 |
| RTX 3090 | Dense | 443 min | 406 min | 0.92 |
| H20 | MoE | 20.58 h | 20.80 h | 1.01 |
| Engine window | ||||
| H800 | MoE | 62 min | 73 min | 1.18 |
| Hardware | Without prefix caching | With prefix caching | Speedup |
|---|---|---|---|
| RTX 3090 | 13 h 35 min | 1 h 13 min | 11.1 |
| H800 | 1 h 58 min | 54 min | 2.19 |
| Recompute | Offload | ||||
|---|---|---|---|---|---|
| Hardware | GPU KV usage | Total | Total | GPU | External |
| RTX 3090 | 80% | 62.9 | 79.4 | 62.7 | 16.6 |
| 80–90% | 34.7 | 43.7 | 16.9 | 26.7 | |
| 90–95% | 34.4 | 44.0 | 17.1 | 27.2 | |
| 95–100% | 33.8 | 44.3 | 17.3 | 25.9 | |
| H800 | 80% | 65.7 | 98.4 | 97.5 | 0.2 |
| GPU memory fraction | Wall-clock (min) | Prefix hit rate |
| .65 | 407 | 44.6% |
| .70 | 333 | 53.5% |
| .75 | 245 | 58.6% |
| .80 | 114 | 79.7% |
| .85 | 78 | 96.2% |
| .95 | 73 | 98.1% |
| Regime | Evidence | Action |
|---|---|---|
| High FLOP per host-link byte | Offload/recompute 1.08–1.87 (H800) | Favor GPU prefix caching |
| Low FLOP per byte, | 0.60 (H20, 20 GiB); 0.91 (RTX 3090) | Offload; admit every write if |
| Makespan at 5 GiB | Conditioned admission or larger tier | |
| Context editing | Early edits rekey all later chunks | Judge edits by cache-stable length |
| Condenser | GPU KV utilization | Prefix-hit rate |
|---|---|---|
| None (NoOp) | 52.85% | 96.50% |
| Recent-event truncation | 25.57% | 60.85% |
| Observation masking | 29.15% | 50.80% |
| LLM summarization | 41.12% | 92.15% |