From One-Character Bug to 10× Data Pipeline: The EAGLE-3 Speculative Decoding Odyssey
Introduction
In the world of large language model deployment, the gap between a working prototype and a production-ready system is rarely measured in single breakthroughs. More often, it is measured in the quiet, grinding work of debugging, benchmarking, and data scaling — punctuated by moments of discovery that reveal how much was wrong all along. This is the story of one such journey: a multi-week effort to deploy EAGLE-3 speculative decoding for the Kimi-K2.5 language model across eight NVIDIA RTX PRO 6000 Blackwell GPUs.
Segment 27 of this opencode coding session captures a remarkable arc. It opens with the resolution of a devastating one-character bug that had rendered weeks of work completely useless. It continues through a sobering benchmark that showed the fix was working — but not well enough. And it culminates in a massive 10× data scaling campaign, launching ten parallel agents to assemble a 100,000-sample training pipeline, only to discover that three of the ten datasets had silently produced zero usable records.
This article traces that arc, examining the reasoning, assumptions, and engineering decisions that shaped each phase. It draws lessons for anyone building complex ML systems — about the fragility of configuration, the value of systematic debugging, the primacy of data quality, and the importance of building visibility into long-running pipelines.
Part I: The One-Character Bug
The Silent Failure
The EAGLE-3 speculative decoding system had been built with extraordinary care. A custom draft model was trained on 10,000 samples of hidden states extracted from Kimi-K2.5, a 1-trillion-parameter Mixture-of-Experts model. The training metrics looked excellent — 74.5% step-0 accuracy, loss converging cleanly by epoch 3 ([msg 3597]). Yet when deployed on the SGLang inference server, the draft model achieved an acceptance rate indistinguishable from random chance. Every token it proposed was rejected by the target model. The system was running slower than the non-speculative baseline, not faster.
This is the kind of failure that drives engineers to despair. No crashes, no error messages, no warnings — just silently wrong behavior that manifests as poor performance. The assistant had spent days chasing false leads: token mapping issues, weight key naming conventions, vocabulary alignment problems. Each fix brought the acceptance rate from zero to... still essentially zero ([msg 3597]).
The Rosetta Stone
The turning point came when the assistant paused the iterative debugging loop to produce a comprehensive status document — message 3597, a sprawling 3,000+ word synthesis of everything learned across days of work. This document served as a shared mental model between the assistant and the human user, capturing hardware specifications, software versions, model architecture details, code paths, and a prioritized action plan [1].
The document's centerpiece was the discovery that the draft model was receiving hidden states of shape [batch, 7168] instead of the expected [batch, 21504]. The EAGLE-3 architecture requires the target model to capture hidden states from three intermediate layers (layers 2, 30, and 58), concatenate them into a 21504-dimensional vector, and pass that to the draft model's fusion layer (fc). Instead, only the final layer's 7168-dimensional state was being passed. The fc layer, which projects 21504-dim inputs down to 7168-dim, was silently bypassed because the condition hidden_states.shape[-1] != embeds.shape[-1] evaluated to 7168 != 7168 — which is False ([msg 3597], [1]).
Tracing the Code Path
The assistant's systematic investigation traced the entire data flow from the eagle worker to the draft model, reading files in parallel across multiple rounds. The critical breakthrough came when the assistant examined the spec_info.py file, which defines the SpeculativeAlgorithm enum. Here, the truth was revealed: EAGLE and EAGLE3 are two separate enum members, and is_eagle3() is implemented as return self == SpeculativeAlgorithm.EAGLE3 — a strict equality check that EAGLE does not satisfy ([msg 3604], [1]).
The server logs confirmed the diagnosis. The server had been started with --speculative-algorithm EAGLE, not --speculative-algorithm EAGLE3. There were no messages about eagle3_layers_to_capture in the logs, confirming that the setup code was never executed. The fix was a single character: adding the digit "3" to the flag ([msg 3604]).
Why the Bug Was So Hard to Find
The bug's elusiveness stemmed from several factors. First, the two flags are semantically similar — EAGLE-3 is a version of EAGLE. A developer might reasonably assume that EAGLE is the correct general flag and that EAGLE-3-specific behavior would be auto-detected from the draft model's config. Indeed, the draft model's config.json contained "use_aux_hidden_state": true and the layer IDs, which should have been sufficient. But the code does not infer the algorithm from the config; it strictly follows the command-line flag ([msg 3604]).
Second, the failure was silent. The server started successfully, loaded both models, and began processing requests. No crashes, no error messages, no warnings about missing hidden states. The draft model simply received wrong-shaped inputs and produced useless predictions — a degradation that manifested as zero acceptance rather than a loud failure ([msg 3597]).
Third, multiple bugs masked each other. Earlier, the assistant had discovered a weight key naming mismatch (speculators saves layers.0.* but SGLang expects midlayer.*). Fixing that bug improved weight loading but didn't fix acceptance rates, leading the assistant to chase other potential causes. The hidden state bug was the real issue all along [1].
Part II: The Sobering Benchmark
The Fix Works — But Not Well Enough
After correcting the flag and restarting the server, the hidden states arrived at the correct 21504-dimensional shape, and the draft model's predictions began being accepted at a meaningful rate — approximately 2.1 tokens per speculation step. The assistant then embarked on a systematic benchmarking campaign, testing configurations with and without CUDA graphs, varying draft token counts (5 vs. 16), and different speculation step depths.
The results, consolidated in message 3652, were sobering ([msg 3652]):
| Config | tok/s | Accept Len | Notes | |--------|:-----:|:----------:|-------| | SGLang baseline (no spec) | 90.0 | — | Best non-speculative | | EAGLE3, CUDA graph, 5 draft | 82.3 | 2.1 | Best EAGLE3 config | | EAGLE3, CUDA graph, 16 draft | 74.9 | 2.2 | | | EAGLE3, no CUDA graph, 5 draft | 53.2 | 2.1 | | | AQ-MedAI drafter | 50.5 | 1.9 | Worse (wrong model) |
The best EAGLE-3 configuration achieved 82.3 tok/s — still ~9% slower than the 90 tok/s non-speculative baseline. The acceptance length of ~2.1 was insufficient to overcome the overhead of running the draft model alongside the target model. To break even, the system needed an accept_len of ~2.5; to achieve a real speedup, it needed 3.0+ ([msg 3652]).
The Diagnosis: Data Scarcity
The assistant's analysis identified the bottleneck with clarity. The EAGLE-3 paper had trained on approximately 530,000 samples; SpecForge (SGLang's official EAGLE trainer) used 320,000 samples. The team's draft model had been trained on only 10,000 samples — a rounding error by comparison ([msg 3652]). The paper's scaling curves showed a clear relationship between training data volume and acceptance rate, and the current model was on the steep part of the curve where additional data would have the most impact.
The assistant laid out four options: train on more data (the strongest lever per the paper's scaling curve), switch back to the 90 tok/s baseline for production, try longer training on the existing 10K data (marginal gains expected), or keep the server running for further experimentation ([msg 3652]).
Part III: The Pivot to Scale
The User's Decisive Directive
The user's response in message 3653 cut through the ambiguity with surgical precision ([msg 3653]):
"Start 10 agents to look for more matching agentic-coding-related datasets from which we'll generate a kimi k2.5 dataset. We'll aim for 10x size."
This was not a question or a request for analysis — it was a directive. The user chose the data scaling path and amplified it: not merely "more data" but a 10× scale-up, and not generic data but "agentic-coding-related" datasets targeting the exact production use case. The instruction to use "10 agents" authorized a massive parallel search operation covering as many dataset categories as possible in a single round ([msg 3653]).
The Great Dataset Hunt
Message 3654 operationalized this directive through a carefully orchestrated ten-agent parallel search ([msg 3654]). Each agent was dispatched via the task tool, spawning an independent subagent session that searched HuggingFace for datasets in a specific category:
- Coding instruction datasets —
nvidia/OpenCodeInstruct,ise-uiuc/Magicoder-Evol-Instruct-110K - Agentic/tool-use datasets —
nebius/SWE-agent-trajectories(80K rows),SWE-Factory/DeepSWE-Agent-Kimi-K2-Trajectories-2.8K - Reasoning/math datasets —
open-thoughts/OpenThoughts-114k,open-r1/Mixture-of-Thoughts - General chat/instruction datasets —
ShareGPT_Vicuna_unfiltered,HuggingFaceH4/ultrachat_200k - EAGLE-3/SpecForge training data — researching what the papers actually used
- Code review/debugging datasets
- Long-form writing/analysis datasets
- DeepSeek/Kimi specific datasets
- Multi-language coding datasets
- Large synthetic instruction sets —
BAAI/Infinity-Instruct(7.45M samples) This taxonomy reveals a sophisticated understanding of what makes good training data for a speculative decoding draft model. The categories cover the full spectrum of relevant data types, from agentic coding trajectories to general chat conversations, ensuring diversity while maintaining focus on the production use case ([msg 3654]).
Synthesizing the Findings
Message 3655 synthesized the ten agents' reports into a concrete plan ([msg 3655]). The proposed dataset mix targeted approximately 100,000 samples with a deliberate weighting strategy:
- Agentic coding (~22.8K samples): SWE-agent trajectories, DeepSWE-Agent-Kimi-K2-Trajectories, glaive-function-calling
- Code instruction (~25K samples): OpenCodeInstruct, Magicoder-Evol-Instruct
- Reasoning (~25K samples): Mixture-of-Thoughts, OpenThoughts-114k
- General chat (~25K samples): UltraChat, ShareGPT The inclusion of
SWE-Factory/DeepSWE-Agent-Kimi-K2-Trajectories-2.8Kwas particularly shrewd — these trajectories were generated by Kimi-K2 itself, meaning the token distribution closely matches what the target model produces. These samples could be used as-is without response regeneration ([msg 3655]).
The Critical Design Decision: Response Regeneration
Perhaps the most important analytical insight in the assistant's plan was the recognition that most datasets would be used only for their prompts, not their responses. The draft model must learn to predict Kimi-K2.5's token distribution, not GPT-4's or DeepSeek's. Therefore, the responses from the original datasets had to be discarded and regenerated by running inference on Kimi-K2.5 itself ([msg 3655]).
This decision transformed the problem from a simple data collection exercise into a massive inference pipeline. Every prompt in the 100K dataset needed to be fed through the target model, and the hidden states from those forward passes needed to be captured. The assistant calculated the resource requirements: at ~92GB per 1,000 samples, the 100K corpus would produce ~9.2TB of hidden state data — far exceeding the previously available 1.8TB on the /data partition ([msg 3655]).
The user's response resolved this constraint with a single sentence: "Disk resized to 11T now" ([msg 3657]). This removed the primary infrastructure bottleneck, making the entire plan feasible.
Part IV: Building the Pipeline
The Unified Prep Script
Message 3663 marked the transition from planning to code ([msg 3663]). The assistant wrote a unified dataset preparation script (prep_all.py) that each parallel agent would use. The script's architecture reflected a binary classification of the ten datasets:
- Kimi-native datasets (already containing Kimi-K2.5 responses): tokenize directly and output
tokenized_data.jsonl - Prompt-only datasets (requiring response generation): extract prompts and output
prompts.jsonlfor the inference pipeline This design decision — one script with one function per dataset, rather than ten separate scripts — enabled the parallel launch that followed. Each subagent could call the same module with a different dataset name argument, sharing common infrastructure for HuggingFace authentication, JSON handling, and file I/O ([msg 3663]).
Killing the Server, Starting the Pipeline
Message 3666 captured the moment of transition ([msg 3666]). The assistant issued a deliberate bash command over SSH:
ssh root@10.1.230.174 'pkill -f "sglang.launch_server" 2>/dev/null; sleep 2; pkill -9 -f python3 2>/dev/null; sleep 3; fuser -k /dev/nvidia* 2>/dev/null; echo "Server killed"'
This five-step pipeline — graceful termination, wait, nuclear force-kill, wait, GPU resource release — killed the EAGLE-3 speculative server to make way for the baseline inference server needed for response generation. The command's brutality reflected a priority on reliability over gentleness: when you need a clean slate, you reach for a sledgehammer, not a scalpel ([msg 3666]).
The Parallel Launch
Message 3667 saw the assistant create output directories and launch all ten dataset preparation jobs in parallel ([msg 3667]). Each job ran as a subagent via the task tool, processing one dataset independently. The Kimi-native datasets were tokenized directly; the prompt-only datasets were formatted for the inference pipeline.
Simultaneously, the assistant started the baseline SGLang inference server at message 3670, reasoning that it could overlap server startup with dataset preparation to minimize wall-clock time ([msg 3670]). The server launch command encoded weeks of accumulated debugging knowledge: specific NCCL environment variables tuned for the Blackwell GPU architecture (NCCL_PROTO=LL, NCCL_ALGO=Ring, NCCL_P2P_LEVEL=SYS), tensor parallelism across all 8 GPUs (--tp-size 8), and flags like --disable-custom-all-reduce that had been necessary to work around SM120 compatibility issues [2]. This was not a naive server start — it was the culmination of extensive performance tuning from earlier segments.
Part V: The Silent Failures
Three Datasets, Zero Records
When the assistant checked progress at message 3671, the results were alarming ([msg 3671]). While several datasets had completed successfully (A2, B1, B3, B6, B7), three critical datasets had produced exactly zero usable records. The failures were:
- A1 (DeepSWE-Kimi): 0 records, 2,809 skipped. The dataset contained multi-turn agent trajectories with 84 messages alternating between system, user, and assistant roles, but the prep script's tokenization logic assumed the last message would always be an assistant turn. In these agentic trajectories, the final message could be a tool result or system message ([msg 3672]).
- B5 (OpenThoughts): 0 prompts extracted. The code checked for
from == "human"in the conversation format, but the dataset usedfrom == "user". A single string comparison mismatch that silently swallowed 114,000 reasoning traces ([msg 3672]). - B8 (SWE-agent trajectories): 0 prompts. The dataset used a
trajectoryfield withrole/text/system_promptkeys instead of the expectedmessagesorconversationsformat. The structure was completely different from what the prep script anticipated ([msg 3675]). Each failure was completely silent — the script reported "0 records" without raising an exception, making it easy to miss without careful log inspection. The assistant caught them only because it actively checked the logs after launch ([msg 3671]). This pattern of silent failure is a recurring theme in data pipeline engineering: when extraction logic doesn't match the data schema, it produces empty output without error, and the failure is only discovered when someone inspects the counts.
The Fixes: Three Edits, One Script
The assistant applied three targeted edits to prep_all.py in rapid succession. For A1, the fix required a fundamental rethinking of the tokenization strategy. Instead of searching for a single assistant response at the end of the conversation, the code was changed to tokenize the full multi-turn conversation and mark all non-system content as trainable. Since all assistant responses in the dataset were generated by Kimi-K2.5, every assistant turn was a valid sample of the target model's output distribution ([msg 3677]). This was a significant strategic pivot that maximized the utility of each multi-turn conversation.
For B5, the fix was a one-line change: replacing "human" with "user" in the condition that identifies user messages. This is the kind of trivial bug that can derail an entire pipeline — a single string mismatch causing 114,000 samples to be silently dropped.
For B8, the fix required adding a handler for the trajectory format. The assistant had to navigate the nested structure, skipping the initial system turn (which had text: None) and finding the first user turn with actual text content to use as the inference prompt.
Each edit was applied with the edit tool, and each produced LSP errors about unresolved imports — correctly dismissed by the assistant as local environment issues since the datasets and transformers packages weren't installed on the host machine, only on the remote container where the script would run. This dismissal reveals a critical operational judgment: the ability to distinguish real errors from environmental noise is perhaps the most valuable skill an AI assistant can demonstrate in complex development workflows [2].
After applying all three fixes, the assistant copied the updated script to the remote server via SCP and re-launched the three failed datasets. The SCP command — a single line of bash — represented the culmination of a debugging process that had involved subagent tasks, data format inspection, three separate code edits, and a deep understanding of the training pipeline.
Part VI: The Inference Pipeline
83,288 Prompts and a 55-Hour Wait
With the dataset preparation issues resolved, the assistant turned to the inference pipeline. The plan was ambitious: feed all 83,288 prompts through the baseline SGLang server running Kimi-K2.5, generating responses that match the target model's token distribution. At approximately 830 tok/s throughput, the assistant estimated this would take 24–55 hours depending on average response length [2].
The inference runner script (run_inference.py) was designed with resume support — if the server crashed or the process was interrupted, it could pick up from where it left off ([msg 3698]). The assistant partitioned the datasets into two categories: short prompts (B1–B7, concurrency 150, max_tokens 10,240) and long prompts (B8 SWE-agent trajectories, concurrency 32, max_tokens 16,384). This partitioning reflected an understanding of the different characteristics of these datasets — long-context agentic trajectories require lower concurrency to avoid OOM due to KV-cache memory pressure ([msg 3698]).
The inference pipeline was launched at message 3701 after a careful sequence of preparations ([msg 3701]). The assistant first ensured the server was healthy by running a health check, then SCP'd the inference runner script to the container, and finally launched the pipeline with --partition all. The launch message shows the pipeline beginning to process B1_glaive, with the assistant noting that the full pipeline would take approximately 23 hours based on the current throughput.
Monitoring the Long Run
Throughout the inference run, the assistant maintained a monitoring cadence, checking progress at regular intervals. At message 3703, the assistant checked the inference log and found that 10,000 prompts had been processed in approximately 2.5 hours — a rate of about 1.1 requests per second. At this rate, the full 83,288 prompts would take approximately 23 hours, within the earlier estimate. However, as the run progressed, the average completion length grew from ~217 tokens to ~788 tokens, reducing the request rate to 0.7 req/s and extending the estimated completion time to 55 hours [2].
This variability in response length is a fundamental challenge in inference pipelines for autoregressive models. The Kimi-K2.5 model generates reasoning traces with extended thinking blocks, and the length of these blocks is unpredictable. The assistant's initial estimate of 24 hours was based on short completions, but as the model generated longer reasoning chains, the throughput dropped and the timeline stretched.
The Monitor Script
As the inference pipeline ran, the assistant recognized the need for better monitoring. At message 3708, the assistant wrote a progress monitor script that could be run on the remote server to check inference status without SSHing in and reading logs manually ([msg 3708]). The script checked the number of completed prompts, calculated the throughput, and estimated the remaining time.
The monitor script itself required debugging — the first version had a bug where the tail command was looking for the wrong pattern in the log file. The assistant iterated through several versions, testing each one, before arriving at a working solution. This debugging microcosm reveals the assistant's systematic approach: write a script, test it, observe the failure, diagnose the root cause, fix it, and test again.
The final monitor script provided real-time visibility into the inference pipeline's progress, allowing the assistant and user to track the 55-hour run without constant manual checks. This is a small but essential piece of infrastructure — without it, the pipeline would be a black box, and failures could go undetected for hours.
Part VII: The Status Summary
Consolidation and Reflection
At message 3706, the assistant produced a comprehensive status summary that serves as the capstone of this segment's work ([msg 3706]). The message consolidates everything that had been accomplished:
- The EAGLE-3 flag bug was fixed —
--speculative-algorithm EAGLE3(notEAGLE) is required to enable aux hidden state capture from layers [2, 30, 58]. - The benchmark results were documented — Best EAGLE3 config achieves 82.3 tok/s (CUDA graphs + 5 draft tokens) vs 90 tok/s baseline. Still ~9% slower, but the draft model is actually working now with accept_len ~2.1.
- Ten datasets totaling 88,088 samples were prepared — 4,800 tokenized Kimi-native samples and 83,288 prompts needing inference.
- The inference pipeline was running — Processing all 83K prompts through the baseline SGLang server at ~830 tok/s throughput, with resume support. The status summary is notable for its honesty. It doesn't hide the fact that EAGLE-3 is currently slower than the baseline. It doesn't pretend the bug was trivial to find. It presents the situation as it is, with clear numbers and a clear path forward: merge all tokenized data after inference completes, apply the hidden state extraction patch, train the new EAGLE-3 drafter on ~88K samples, and deploy with the correct flag ([msg 3706]). The message also reveals a systems-thinking mindset. The assistant tracks multiple parallel workstreams — bug fixing, benchmarking, data prep, inference, plan documentation — and understands their dependencies. The status summary is not just a list of completed tasks but a dependency graph showing which pieces must finish before others can begin.
Lessons and Reflections
The Fragility of Configuration
The EAGLE-3 hidden state concatenation bug is a cautionary tale about the dangers of configuration ambiguity. The difference between EAGLE and EAGLE3 is a single character — the digit "3" — yet it rendered weeks of work useless. The bug was invisible at startup, produced no errors, and manifested only as degraded performance that could be attributed to many other causes ([msg 3604], [1]).
For the SGLang project, this suggests a need for better validation. The server could check whether the draft model's config requires EAGLE-3 features and warn if the flag is wrong. It could also auto-detect the algorithm from the draft model's architecture. The bare except clause on line 365 of model_runner.py is particularly dangerous — it silently swallows any errors during draft config reading, making misconfiguration invisible ([msg 3597]).
The Value of Systematic Debugging
The assistant's approach to debugging the EAGLE-3 deployment was methodical: formulate a hypothesis, test it, evaluate the result, and iterate. When the d2t mapping hypothesis failed, the assistant moved on to weight key names. When that fix didn't help, the assistant added debug instrumentation to the draft model's forward pass — a classic technique that finally revealed the hidden state dimension mismatch [1].
The comprehensive status document (message 3597) was a pivotal artifact. It synchronized the assistant and user on the same mental model, documented all discoveries and red herrings, and provided a prioritized action plan. This kind of meta-cognitive pause — stepping back from the iterative loop to consolidate knowledge — is essential for complex debugging.
Data Scaling as the Primary Lever
The pivot from debugging to data scaling reflects a fundamental principle of machine learning engineering: when your model is underperforming, look at the data first. The assistant could have continued tweaking speculation parameters, trying different tree structures, or adjusting learning rates. Instead, it correctly identified that the primary bottleneck was training data volume and addressed it at the root ([msg 3652], [msg 3653]).
The ten-agent parallel search architecture is a model for how to approach data collection at scale. Rather than manually searching for datasets one at a time, the assistant leveraged the task tool to spawn independent agents that explored different categories simultaneously. This approach could be generalized to any data collection task where the search space is large and the categories are independent ([msg 3654]).
The Fragility of Data Format Assumptions
The assistant's prep_all.py script made reasonable assumptions about data formats based on common HuggingFace conventions. Yet three out of ten datasets violated those assumptions — a 30% failure rate. Each dataset had its own idiosyncratic schema: multi-turn agent trajectories, non-standard role labels, nested trajectory structures. The assistant's systematic debugging approach — inspect the actual format, compare against expectations, apply targeted fixes — is a model for handling this heterogeneity at scale ([msg 3671], [msg 3672], [msg 3675]).
The Importance of Silent Failure Detection
All three dataset format bugs were completely silent — the script produced zero records without raising an exception. Without the assistant's active log inspection, these failures could have gone undetected until much later in the pipeline, when the merged dataset would have been missing critical samples. This pattern of silent failure is a recurring theme in data pipeline engineering: when extraction logic doesn't match the data schema, it produces empty output without error, and the failure is only discovered when someone inspects the counts ([msg 3671]).
The Art of Ignoring Noise
The assistant's dismissal of LSP errors as local environment issues reveals a critical operational skill: distinguishing real errors from environmental noise. In any complex development environment, there are dozens of potential error sources — LSP diagnostics, compiler warnings, runtime exceptions, log messages. An effective engineer must learn to triage these signals and focus on what matters [2].
Conclusion
Segment 27 of this opencode coding session captures a complete arc of ML engineering work: from the discovery of a devastating one-character bug, through systematic debugging and benchmarking, to a decisive pivot toward data scaling, and finally to the construction of a massive parallel pipeline for 10× dataset expansion. The journey is a testament to the value of methodical debugging, honest measurement, and strategic pivoting.
The hidden state concatenation bug is fixed. The benchmark numbers are known. The 100K-sample training pipeline is launched. Whether the bet on data scaling pays off — whether 100,000 samples will push the acceptance rate past the break-even point — remains to be seen. But the strategy is sound, the execution is thorough, and the foundation is laid. In the end, that is what engineering progress looks like: not a single breakthrough, but the quiet, grinding work of understanding what's broken, measuring what's possible, and building the data you need to make it work.
The inference pipeline is running. The datasets are being prepared. The hidden state extraction and training phases await. The question that hangs over all of this work is whether the 10× scale-up will deliver the acceptance rate improvements that the EAGLE-3 paper promises. The answer will determine whether speculative decoding becomes a practical acceleration technique for Kimi-K2.5, or whether it remains a promising idea that cannot deliver in practice. For now, the assistant has done everything within its power: fixed the bugs, prepared the data, launched the pipeline, and built the monitoring. The rest is a waiting game — 55 hours of inference, followed by training, followed by the final benchmark that will tell the story.
References
[1] "From a One-Character Bug to a 10× Data Pipeline: The EAGLE-3 Speculative Decoding Odyssey" — Chunk article covering messages 3597–3667 of segment 27
[2] "From Bug to Benchmark to Scale-Up: The EAGLE-3 Data Pipeline Odyssey" — Chunk article covering messages 3668–3716 of segment 27