The Verdict on Speculative Decoding: When a Clever Optimization Becomes a Liability
Introduction
In the high-stakes world of large language model inference, every token per second counts. Engineers invest weeks building custom draft models, tuning CUDA graphs, and wrestling with NCCL all-reduce configurations—all in pursuit of that elusive speedup. But sometimes, the most important result is a negative one. Message <msg id=5588> in this opencode session is that rare artifact: a definitive, well-documented conclusion that a sophisticated optimization (EAGLE-3 speculative decoding) is strictly worse than the naive baseline for throughput-oriented workloads. This message serves as the capstone of an intensive investigation spanning multiple sessions, distilling hours of benchmarking, debugging, and failed engineering attempts into a clear, actionable summary.
The message is a session summary written by the AI assistant after completing a comprehensive parallel throughput comparison between an EAGLE-3 speculative decoding server and a baseline (no speculation) server, both running the Kimi K2.5 model across 8 RTX PRO 6000 Blackwell GPUs. It documents not only the quantitative results but also the qualitative lessons learned from a failed attempt to implement dynamic speculation disable—a feature that would have automatically switched between speculative and non-speculative modes based on server load.
The Message in Full
All done. Here's a summary of what we accomplished in this session:
>
---
>
## Session Summary
>
### Completed
>
1. Baseline parallel benchmark (encyclopedic prompts) — Ran C=1,2,5,10,30,70,100,250. Baseline peaks at 773 tok/s at C=100 vs EAGLE-3's 341 tok/s — baseline is 2.3x better at saturation.
>
2. Updated benchmark prompts — Replaced encyclopedic prompts with coding/agentic tasks (code gen, debugging, SWE, system design) matching the EAGLE-3 drafter's training data distribution.
>
3. EAGLE-3 parallel benchmark (coding prompts) — C=1: 80.9 tok/s, saturates at 354 tok/s (C≥70). Slight improvement over encyclopedic prompts (+4% at C=1).
>
4. Baseline parallel benchmark (coding prompts) — C=1: 92.7 tok/s, saturates at 773 tok/s (C=100). Identical to encyclopedic prompts (no speculation = no prompt sensitivity).
>
5. Dynamic speculation disable attempt — Implemented patches for bothEAGLEWorkerV2(overlap) andEAGLEWorker(non-overlap). Discovered that the non-overlap path (which our config uses) deeply couples batch state management with the speculative pipeline —out_cache_locis pre-allocated for draft token dimensions, CUDA graph shapes expect speculative layouts. Deferred for now.
>
6. All results documented in eagle-fast-verify.md.
>
### Key Finding
>
Baseline wins at every concurrency level for throughput. The gap narrows from 15% at C=1 to 2x+ at C≥30. EAGLE-3's value is strictly in per-request latency at low concurrency (single-stream: 96 tok/s vs 93 tok/s baseline). For throughput workloads, baseline is strictly superior.
>
### Current Server State - Baseline server is running on port 30000 (no speculation).
>
### What Could Come Next - Train a better drafter (higher acceptance → bigger EAGLE-3 advantage at low C) - Test reduced speculation configs (fewer steps/topk) at medium concurrency - Dynamic switching via a load balancer (two server instances) rather than in-process switching - Investigate SGLang's spec_v2 overlap path (may have cleaner separation for dynamic disable)
Context: The Road to This Verdict
To understand why this message was written, we must trace the arc of the investigation that preceded it. The assistant had been working for multiple sessions to deploy and optimize the GLM-5-NVFP4 model (later switched to Kimi K2.5) using SGLang with EAGLE-3 speculative decoding. Earlier in segment 36, the assistant had achieved a breakthrough: by upgrading to CUDA 13, patching SGLang for SM120 support, and enabling FlashInfer allreduce fusion with Torch symmetric memory, EAGLE-3 speculative decoding had been transformed from a net-negative 54.1 tok/s to a net-positive 96.1 tok/s. This was a victory—EAGLE-3 was finally beating the baseline in single-stream latency.
But the user wanted to know how these gains held up under real-world load. The session documented in segment 37 (which contains message <msg id=5588>) was designed to answer that question systematically. The assistant ran parallel throughput benchmarks across concurrency levels from 1 to 250, first with the old encyclopedic prompts and then with new coding/agentic prompts that better matched the EAGLE-3 drafter's training distribution. The results were unambiguous: the baseline server saturated at 773 tok/s, while EAGLE-3 topped out at 354 tok/s—a 2.3x gap.
The message <msg id=5588> was written to deliver this finding to the user in a concise, actionable format, while also documenting the failed attempt at dynamic speculation disable that consumed the middle portion of the session.
Why This Message Was Written: The Reasoning and Motivation
The assistant's primary motivation in writing <msg id=5588> was to synthesize a complex, multi-hour investigation into a coherent narrative. The session had involved:
- Restoring the eagle_worker.py to a clean state (undoing the failed dynamic disable patch)
- Starting an EAGLE-3 server with the standard configuration
- Running parallel benchmarks at 8 concurrency levels with 30 requests each
- Killing the EAGLE-3 server and starting a baseline server
- Running the same benchmarks on the baseline
- Updating the documentation file
eagle-fast-verify.mdEach of these steps produced its own output—bash command results, benchmark tables, error traces. But the user needed a unified picture. The assistant recognized that the raw data, while valuable, did not tell the story on its own. The message<msg id=5588>was the narrative glue that connected the numbers to their meaning. There was also a strategic motivation. The assistant had just spent considerable effort attempting to implement dynamic speculation disable—a feature that would automatically switch between EAGLE-3 and baseline modes based on server load—and had failed. The failure was not due to a simple bug but to a fundamental architectural coupling in the SGLang codebase: the non-overlap EAGLEWorker path (which their configuration used) deeply intertwined batch state management with the speculative pipeline. Theout_cache_loctensor was pre-allocated for draft token dimensions, CUDA graph shapes expected speculative layouts, and the entire decode setup was handled inside the EAGLE worker rather than in the standardprepare_for_decodepath. By framing this as a "deferred" item rather than a "failed" one, the message preserved the possibility of future work while acknowledging the current limitations.## How Decisions Were Made The message<msg id=5588>is unusual in that it reports on decisions that were made during the session rather than making new decisions itself. The key decision points were: The decision to update benchmark prompts. Earlier in the session, the assistant realized that the encyclopedic prompts used in previous benchmarks (covering topics like the history of the Roman Empire and the water cycle) might not be representative of the EAGLE-3 drafter's training distribution. The drafter had been fine-tuned on coding and agentic tasks—code generation, debugging, software engineering, system design. By updating the prompts to match this distribution, the assistant ensured a fairer comparison. The result was a modest +4% improvement at C=1 (80.9 tok/s vs 77.5 tok/s), confirming that prompt distribution mattered but did not change the overall conclusion. The decision to abandon dynamic speculation disable on the v1 path. This was the most consequential decision of the session. The assistant had written a patch that attempted to clearspec_infoandspec_algorithmon the batch when concurrency exceeded a threshold, causing the scheduler to fall back to normal decode. But the first test at C=10 crashed with a tensor size mismatch:RuntimeError: The size of tensor a (160) must match the size of tensor b (2). The assistant traced this toout_cache_locbeing pre-allocated for 160 cache slots (10 requests × 16 draft tokens) while the normal decode path expected 2 slots (2 surviving requests after batching). The root cause was that in the EAGLE path,prepare_for_decodereturns early without allocatingout_cache_loc—that allocation happens later inside the EAGLE worker's_draft_preprocess_decode. The assistant's fallback code was trying to run a normal decode forward pass with anout_cache_locthat was still sized for speculative decode. After exploring several alternatives—reducingspeculative_num_stepsto 0, using theforward_target_extendpath, replicating the entire normal decode setup—the assistant made a pragmatic decision: defer dynamic switching and focus on documenting the static comparison. This was the right call. The dynamic switching feature would have been nice to have, but the fundamental insight (baseline wins at all concurrency levels for throughput) was already clear and actionable without it. The decision to document results ineagle-fast-verify.md. Rather than just presenting the results verbally, the assistant updated a persistent documentation file that had been built up over multiple sessions. This ensured the findings would survive beyond the conversation and could be referenced later.
Assumptions Made by the User and Agent
Several assumptions underpin the message <msg id=5588>:
The user assumed that EAGLE-3 might outperform the baseline at moderate concurrency levels. This assumption was implicit in the request to run parallel benchmarks. The user had invested significant effort in training the EAGLE-3 drafter (100k steps of synthetic data) and tuning the server configuration. The expectation was likely that EAGLE-3 would show a crossover point where its per-request latency advantage translated into a throughput advantage at some concurrency level. The message definitively disproves this assumption.
The assistant assumed that dynamic speculation disable was architecturally feasible. This assumption was challenged and ultimately refuted by the engineering work. The assistant's initial patch approach—clearing spec_info and spec_algorithm on the batch—seemed reasonable given the code structure. It took actual runtime failures and detailed code analysis (reading schedule_batch.py line by line) to reveal the depth of the coupling. The assumption was not unreasonable—many speculative decoding systems do support dynamic disable—but it turned out to be incorrect for this particular codebase and configuration.
Both parties assumed that coding/agentic prompts would significantly change the EAGLE-3 results. This assumption was partially validated (the +4% improvement at C=1 was real) but the magnitude was smaller than expected. The drafter's training data distribution mattered less than the fundamental throughput bottleneck.
The assistant assumed that the benchmark methodology was sound. The parallel benchmark tool sent 30 requests per concurrency level, each generating 512 tokens, with a warmup phase. The results were consistent across runs, suggesting the methodology was reliable.
Mistakes and Incorrect Assumptions
The most significant mistake was the attempt to implement dynamic speculation disable on the v1 (non-overlap) path without first understanding the full state management implications. The assistant jumped into writing patches based on a surface-level understanding of the code, only to discover after several rounds of debugging that the EAGLE worker's state coupling was far deeper than anticipated. This consumed roughly half the session's tool calls (from <msg id=5560> through <msg id=5573>) and ultimately produced no working code.
However, this "mistake" was also a learning opportunity. The debugging process revealed exactly how SGLang's EAGLE worker manages batch state—how prepare_for_decode returns early for speculative batches, how out_cache_loc is allocated inside _draft_preprocess_decode, and how the normal decode path differs. This knowledge is valuable for any future attempt at dynamic switching, whether in-process or via a load balancer.
A subtler error was the initial assumption that the benchmark prompts didn't matter. The earlier benchmarks (from segment 36) had used encyclopedic prompts, and the assistant had been comparing those results against the baseline without considering prompt distribution. The realization that this might bias the comparison led to the prompt update, which was a methodological improvement even if the quantitative impact was modest.
Input Knowledge Required to Understand This Message
To fully grasp <msg id=5588>, the reader needs:
Knowledge of speculative decoding. EAGLE-3 is a speculative decoding algorithm where a small draft model generates candidate tokens that the target model verifies in parallel. The key parameters are speculative-num-steps (how many draft steps to take), speculative-eagle-topk (how many candidates to consider at each step), and speculative-num-draft-tokens (the total tree size). The message references these concepts implicitly when discussing "reduced speculation configs."
Knowledge of the hardware topology. The server has 8 RTX PRO 6000 Blackwell GPUs connected via PCIe Gen5. This is critical context because PCIe communication overhead was a major bottleneck throughout the optimization effort. The 773 tok/s baseline saturation figure is specific to this hardware configuration.
Knowledge of the previous optimization work. The message references "96.1 tok/s with EAGLE-3" as the single-stream result from the previous session. Without knowing that earlier result, the reader might not understand why 80.9 tok/s (with coding prompts) represents a regression—it's because the earlier benchmark used different prompts and a slightly different server configuration.
Knowledge of SGLang's architecture. The distinction between EAGLEWorker (v1, non-overlap) and EAGLEWorkerV2 (spec_v2, overlap) is crucial for understanding the dynamic disable discussion. The v1 path handles decode setup internally, making it hard to intercept. The v2 path has cleaner separation but requires topk=1, which reduces the draft tree from 16 tokens to 3 tokens.
Output Knowledge Created by This Message
The message <msg id=5588> creates several pieces of lasting knowledge:
The definitive throughput comparison between EAGLE-3 and baseline for this hardware and model. The numbers—773 tok/s baseline vs 354 tok/s EAGLE-3 at saturation, 92.7 tok/s vs 80.9 tok/s at C=1—are now documented and can be referenced in future discussions. This saves anyone else working with similar hardware from having to rediscover these results.
The insight that prompt distribution has minimal impact on the comparison. The +4% improvement from switching to coding prompts is useful data for anyone designing benchmark methodologies for speculative decoding.
The architectural knowledge about SGLang's EAGLE worker state coupling. The message documents that out_cache_loc is pre-allocated for draft token dimensions and that CUDA graph shapes expect speculative layouts, making dynamic disable non-trivial. This is a concrete finding that could inform codebase improvements.
A prioritized list of next steps. The "What Could Come Next" section provides a roadmap: train a better drafter, test reduced speculation configs, use a load balancer for dynamic switching, investigate the spec_v2 path. This turns the negative result into a positive direction for future work.
The Thinking Process Visible in the Reasoning
While the message <msg id=5588> itself is a polished summary, the reasoning that produced it is visible in the surrounding messages. In <msg id=5573>, we see the assistant working through the dynamic disable problem in real time:
"OK, now I understand the full picture. The normal decode path: 1. Allocatesout_cache_locfor 1 token per request 2. Incrementsdecode_batch_idx,kv_committed_len,kv_allocated_lenper request 3. Incrementsseq_lensby 1 4. Setsinput_ids = output_ids(previous output tokens)
>
My fallback needs to replicate this. But it's complex and error-prone. Let me take a completely different approach..."
This is classic debugging reasoning: first understand the expected behavior, then diagnose the mismatch, then evaluate alternatives. The assistant cycles through three approaches—replicating the normal decode setup, reducing speculative steps to zero, using the extend path—before arriving at the pragmatic conclusion to defer the feature.
The reasoning also shows a healthy skepticism about the dynamic switching approach itself:
"Let me take a step back and think about what's actually most valuable. The key insight from the benchmarks is: - Single/low concurrency: EAGLE-3 gives ~80-84 tok/s per request - High concurrency (baseline): ~780 tok/s total throughput - The dynamic switching is a nice-to-have but the fundamental insight is already clear"
This meta-cognitive step—stepping back from the immediate engineering problem to ask "what is actually valuable here?"—is what separates productive investigation from wheel-spinning. The assistant recognized that the dynamic switching feature, while interesting, was not necessary to answer the user's core question about EAGLE-3's throughput characteristics.
Conclusion
Message <msg id=5588> is a masterclass in delivering bad news constructively. It takes a result that might be disappointing—EAGLE-3, after weeks of optimization, is strictly worse than the baseline for throughput—and presents it as actionable knowledge rather than failure. The message acknowledges the effort invested, documents what was learned, and provides a clear path forward.
The broader lesson is about the importance of measuring the right thing. EAGLE-3's single-stream latency advantage (96 tok/s vs 93 tok/s) was real and had been celebrated in the previous session. But under load, that advantage evaporated and reversed. The parallel throughput benchmark revealed the hidden cost of speculative decoding: the draft model consumes GPU compute and memory bandwidth that could otherwise serve more concurrent requests. For a throughput-oriented deployment, the naive baseline is not just simpler—it's better.
This is the kind of finding that only emerges from systematic, multi-dimensional benchmarking. A single-stream test would have told a different story. A test with only low concurrency would have missed the crossover. By testing across a wide range of concurrency levels (1 to 250), the assistant produced a complete picture that supports confident decision-making.
The message also demonstrates the value of documenting failures. The dynamic speculation disable attempt did not produce working code, but the knowledge gained—about out_cache_loc allocation, about the EAGLE worker's internal state management, about the differences between v1 and v2 paths—is now captured for future reference. In engineering, a well-documented dead end is often more valuable than a working solution whose rationale is unclear.