<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kristiyan Stoyanov</title>
    <description>The latest articles on DEV Community by Kristiyan Stoyanov (@kstoyanovai).</description>
    <link>https://dev.to/kstoyanovai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3999391%2F0b4a4fb8-c2b4-4fed-9c31-c14e371ede9c.jpeg</url>
      <title>DEV Community: Kristiyan Stoyanov</title>
      <link>https://dev.to/kstoyanovai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kstoyanovai"/>
    <language>en</language>
    <item>
      <title>Speculative Decoding on Local Hardware: Benchmarking N-Gram, MTP, EAGLE3, and DFlash on the NVIDIA DGX Spark</title>
      <dc:creator>Kristiyan Stoyanov</dc:creator>
      <pubDate>Sat, 18 Jul 2026 18:20:03 +0000</pubDate>
      <link>https://dev.to/kstoyanovai/speculative-decoding-on-local-hardware-benchmarking-n-gram-mtp-eagle3-and-dflash-on-the-nvidia-2kec</link>
      <guid>https://dev.to/kstoyanovai/speculative-decoding-on-local-hardware-benchmarking-n-gram-mtp-eagle3-and-dflash-on-the-nvidia-2kec</guid>
      <description>&lt;h1&gt;
  
  
  Speculative Decoding on Local Hardware: Benchmarking N-Gram, MTP, EAGLE3, and DFlash on the NVIDIA DGX Spark
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; We benchmark four speculative decoding methods — N-Gram, MTP, EAGLE3, and DFlash — running &lt;code&gt;Qwen3.5-122B-A10B-hybrid-int4-fp8&lt;/code&gt; on a single NVIDIA DGX Spark (GB10, SM121). MTP-2 delivered the best balance of throughput and stability (~49 tok/s avg, ~51 tok/s peak). DFlash achieved the highest individual peaks (~78 tok/s) but with significant variance. Configurations shared.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Speculative Decoding Matters for Local AI
&lt;/h2&gt;

&lt;p&gt;Squeezing every token per second out of expensive local hardware is not just a nice-to-have — on machines like the DGX Spark where you've invested in a system to run frontier-scale models locally, inference throughput directly translates to latency in agentic pipelines, coding assistants, and multi-turn conversations.&lt;/p&gt;

&lt;p&gt;Speculative decoding is one of the few optimization techniques that can deliver meaningful speedups &lt;strong&gt;without any change to output quality&lt;/strong&gt;. Because the target model's final verification step guarantees mathematically identical output distributions to standard autoregressive decoding, there is zero quality trade-off.&lt;/p&gt;




&lt;h2&gt;
  
  
  LLM Inference: The Memory-Bandwidth Bottleneck
&lt;/h2&gt;

&lt;p&gt;Before diving into speculative decoding mechanics, it's worth understanding &lt;em&gt;why&lt;/em&gt; LLM inference is slow in the first place.&lt;/p&gt;

&lt;p&gt;Every time an LLM generates a single token, the GPU must load the full model weight matrix from VRAM into compute units. For a 120B+ parameter model, this means moving tens of gigabytes of data — often for just a handful of floating-point operations per weight. This makes inference fundamentally &lt;strong&gt;memory-bandwidth bound&lt;/strong&gt;, not compute-bound. The GPU's tensor cores sit largely idle while the memory bus does the heavy lifting.&lt;/p&gt;

&lt;p&gt;Each inference step consists of two distinct phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prefill (Prompt Processing):&lt;/strong&gt; The input prompt tokens are processed in parallel. This phase is compute-bound and relatively fast, even for long contexts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decode (Generation):&lt;/strong&gt; The model generates one token at a time, autoregressively. Each step requires a full forward pass through the model, loading all weights from memory. This is the slow phase — and it scales linearly with output length.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff9322s88l2xfs82hv3bq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff9322s88l2xfs82hv3bq.png" alt=" " width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the DGX Spark with the &lt;code&gt;Qwen3.5-122B-A10B-hybrid-int4-fp8&lt;/code&gt; checkpoint, the unoptimized baseline sits around &lt;strong&gt;36–37 tok/s&lt;/strong&gt; generation throughput. That's the number we're trying to beat.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Speculative Decoding Works
&lt;/h2&gt;

&lt;p&gt;The core idea is to break the serial token-by-token bottleneck. A small, fast &lt;strong&gt;draft model&lt;/strong&gt; proposes a sequence of &lt;code&gt;K&lt;/code&gt; candidate tokens in rapid succession. The large &lt;strong&gt;target model&lt;/strong&gt; then verifies all &lt;code&gt;K&lt;/code&gt; tokens in a &lt;strong&gt;single forward pass&lt;/strong&gt; — because verification (running the full model over a known input) is significantly cheaper than independent generation.&lt;/p&gt;

&lt;p&gt;The effective speedup depends on two competing factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Draft speed:&lt;/strong&gt; How fast the draft model can propose tokens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acceptance rate (α):&lt;/strong&gt; What fraction of draft tokens the target model accepts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A very cheap but low-quality drafter (low α) will generate tokens faster than the target can accept, wasting compute. A very accurate drafter that nearly matches the target model will have a high α but won't be meaningfully faster to run. The sweet spot is a &lt;strong&gt;lightweight drafter that accurately mimics the target model's distribution&lt;/strong&gt; for the task at hand.&lt;/p&gt;

&lt;p&gt;The expected number of tokens produced per target-model forward pass is:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7zvlbdgn1bch8nw3kzqz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7zvlbdgn1bch8nw3kzqz.png" alt=" " width="584" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;where &lt;code&gt;α&lt;/code&gt; is the per-token acceptance rate and &lt;code&gt;K&lt;/code&gt; is the number of speculative tokens. This means even modest acceptance rates (e.g., 0.8) with &lt;code&gt;K=2&lt;/code&gt; yield ~2.4 tokens per target pass — a meaningful multiplier.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Test Setup
&lt;/h2&gt;

&lt;p&gt;All tests were run on a single &lt;strong&gt;NVIDIA DGX Spark (GB10, SM121, 128 GB unified memory)&lt;/strong&gt; with the following base setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; &lt;code&gt;Qwen3.5-122B-A10B-hybrid-int4-fp8&lt;/code&gt; (Intel AutoRound INT4 MoE experts + FP8 dense shared expert layers)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inference engine:&lt;/strong&gt; vLLM 0.19.1 compiled for SM121&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attention backend:&lt;/strong&gt; FlashInfer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MTP weights patch:&lt;/strong&gt; Required for the Intel AutoRound checkpoint (see below)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hybrid checkpoint is worth noting: the MoE expert weights are quantized to INT4 (via Intel's AutoRound), while the dense shared expert layers use FP8 from the official Qwen FP8 checkpoint. This hybrid approach avoids the accuracy penalty of INT4-quantizing high-utilization attention layers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/albond/DGX_Spark_Qwen3.5-122B-A10B-AR-INT4#step-1-build-hybrid-checkpoint-optional-9" rel="noopener noreferrer"&gt;Albond Recipe for Hybrid Checkpoint&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 1: N-Gram Speculative Decoding
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; N-Gram matching is the simplest possible speculative decoding approach — and the most instructive for understanding the acceptance rate dynamic. It uses no learned model at all. Instead, it scans the &lt;strong&gt;current context window&lt;/strong&gt; for recurring token n-grams and proposes continuations based on frequency co-occurrence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speculative configuration in vLLM:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ngram"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"num_speculative_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prompt_lookup_num_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;prompt_lookup_num_tokens&lt;/code&gt; controls how many tokens form the lookup key. The algorithm finds all positions in the context where the last &lt;code&gt;N&lt;/code&gt; tokens appeared before and proposes what came after them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it fails for open-ended generation:&lt;/strong&gt; N-gram matching works well when the output is highly repetitive relative to the input (e.g., the model is echoing back parts of the prompt, or doing summarization). For free-form generation, the context has no meaningful prefix matches, so the acceptance rate drops sharply.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; vllm-qwen35 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--gpus&lt;/span&gt; all &lt;span class="nt"&gt;--net&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host &lt;span class="nt"&gt;--ipc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /home/krisitown/AI/models:/models &lt;span class="se"&gt;\&lt;/span&gt;
  vllm-qwen35-v2 &lt;span class="se"&gt;\&lt;/span&gt;
  serve /models/qwen35-122b-hybrid-int4fp8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--served-model-name&lt;/span&gt; qwen/qwen3.5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-model-len&lt;/span&gt; 196608 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-num-batched-tokens&lt;/span&gt; 32768 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--gpu-memory-utilization&lt;/span&gt; 0.88 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt; 8000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--load-format&lt;/span&gt; fastsafetensors &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attention-backend&lt;/span&gt; FLASHINFER &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--enable-chunked-prefill&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--enable-auto-tool-choice&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tool-call-parser&lt;/span&gt; qwen3_coder &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--generation-config&lt;/span&gt; auto &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--override-generation-config&lt;/span&gt; &lt;span class="s1"&gt;'{"temperature": 0.7, "top_p": 0.8, "top_k": 20, "presence_penalty": 0.0, "repetition_penalty": 1.0}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--speculative-config&lt;/span&gt; &lt;span class="s1"&gt;'{"method":"ngram","num_speculative_tokens":4,"prompt_lookup_min":2,"prompt_lookup_max":4}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb4t3dga7qqycomedhasl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb4t3dga7qqycomedhasl.png" alt=" " width="799" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; ~24–30 tok/s — &lt;strong&gt;below the 36–37 tok/s baseline&lt;/strong&gt;. The overhead of proposing tokens that get rejected outweighs any gain. N-Gram speculative decoding is only practical in highly repetitive/retrieval-heavy workloads.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 2: MTP (Multi-Token Prediction)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; MTP is a fundamentally different approach. Rather than using a separate external draft model, MTP leverages a &lt;strong&gt;lightweight head that was trained jointly with the target model&lt;/strong&gt; and ships as part of its checkpoint. Because the MTP head has been optimized to match the target model's own output distribution — sharing its internal representations — acceptance rates are dramatically higher than any external drafter.&lt;/p&gt;

&lt;p&gt;The MTP head adds extra transformer layers at the end of the main model that are trained with an auxiliary loss to predict the &lt;em&gt;next&lt;/em&gt; token in the sequence, using the intermediate hidden states of the main model. During inference, these layers run as a cheap drafting pass that reuses the KV cache already computed by the main model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The MTP weights patch for Intel AutoRound:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Intel AutoRound INT4 checkpoint for Qwen3.5-122B ships the MTP weights in &lt;code&gt;model_extra_tensors.safetensors&lt;/code&gt; (785 tensors, ~4.8 GB BF16) but &lt;strong&gt;does not register them in &lt;code&gt;model.safetensors.index.json&lt;/code&gt;&lt;/strong&gt;. vLLM reads the index to discover weights, so it never loads the MTP head unless you patch the index manually. The recipe at &lt;a href="https://github.com/albond/DGX_Spark_Qwen3.5-122B-A10B-AR-INT4" rel="noopener noreferrer"&gt;albond/DGX_Spark_Qwen3.5-122B-A10B-AR-INT4&lt;/a&gt; includes a script that registers all 785 tensor mappings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python patches/02-mtp-speculative/add-mtp-weights.py &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INTEL_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--target&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MODEL_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this patch, adding &lt;code&gt;--speculative-config&lt;/code&gt; will silently have no effect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vLLM configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vllm serve /models/qwen35-122b-hybrid-int4fp8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attention-backend&lt;/span&gt; FLASHINFER &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--speculative-config&lt;/span&gt; &lt;span class="s1"&gt;'{"method":"mtp","num_speculative_tokens":2}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ MTP requires &lt;code&gt;--attention-backend FLASHINFER&lt;/code&gt;. The PyTorch backend does not support MTP in vLLM ≤0.19.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy20ibebx86ljt7nzbl28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy20ibebx86ljt7nzbl28.png" alt=" " width="799" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fif688gj7h70ort3564vf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fif688gj7h70ort3564vf.png" alt=" " width="799" height="33"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tuning &lt;code&gt;num_speculative_tokens&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The number of speculative tokens is the key tuning parameter. Testing with 1, 2, and 4 tokens revealed a clear pattern:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;num_speculative_tokens&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Avg tok/s&lt;/th&gt;
&lt;th&gt;Peak tok/s&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0 (baseline)&lt;/td&gt;
&lt;td&gt;~36–37&lt;/td&gt;
&lt;td&gt;~38&lt;/td&gt;
&lt;td&gt;No speculative decoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;~44–45&lt;/td&gt;
&lt;td&gt;~46&lt;/td&gt;
&lt;td&gt;Solid improvement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;~48–49&lt;/td&gt;
&lt;td&gt;~51&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Best balance&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;~34–35&lt;/td&gt;
&lt;td&gt;~38&lt;/td&gt;
&lt;td&gt;Acceptance rate drops, worse than baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The degradation at &lt;code&gt;num_speculative_tokens=4&lt;/code&gt; is expected. Each additional speculative token compounds the error: if the MTP head diverges from the target model at position &lt;code&gt;i&lt;/code&gt;, all subsequent positions &lt;code&gt;i+1 ... K&lt;/code&gt; are already wrong, so the overhead of generating and then discarding them hurts throughput. The acceptance rate at position 4 was measured in the low 50s%, meaning roughly half of fourth-position tokens were rejected — and the overhead of running the head + verification + token correction exceeded the benefit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; MTP-2 delivers ~49 tok/s average, ~51 tok/s peak — approximately &lt;strong&gt;+32% over baseline&lt;/strong&gt; with stable, consistent throughput.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 3: EAGLE3
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; EAGLE3 is the third iteration of the EAGLE family of speculative decoding drafters. Unlike MTP, the EAGLE drafter is a &lt;strong&gt;separately trained model&lt;/strong&gt; — but it compensates for this by conditioning on the target model's &lt;strong&gt;internal hidden states&lt;/strong&gt;, not just the output token embeddings.&lt;/p&gt;

&lt;p&gt;The intuition is: if the draft model has access to the target model's intermediate representations at the current position, it already "knows" most of what the target was going to compute before producing the next token. This dramatically improves acceptance rates compared to a purely external drafter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EAGLE3 architectural changes from EAGLE1/2:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Multi-layer hidden state inputs:&lt;/strong&gt; The drafter consumes hidden states from multiple layers of the target model (not just the final layer). Earlier layers carry richer semantic information that the final layer collapses into a logit distribution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Removal of next-feature prediction loss:&lt;/strong&gt; EAGLE-2 trained the drafter to predict both the next token &lt;em&gt;and&lt;/em&gt; the next hidden state. EAGLE3 drops the hidden state prediction auxiliary loss, freeing model capacity for the actual goal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inference-aligned training data augmentation:&lt;/strong&gt; During training, the drafter is exposed to its own autoregressive rollouts (not ground-truth hidden states), reducing the distribution shift between training and inference.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Practical constraint:&lt;/strong&gt; EAGLE3 heads are model-specific and must be trained for a particular target model checkpoint. For this test, no EAGLE3 head was available for the 122B MoE model, so the test was conducted on a separate &lt;strong&gt;Qwen3-30B-A3B&lt;/strong&gt; baseline (~33 tok/s without speculative decoding) using an EAGLE3 head pulled from Hugging Face.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vLLM configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eagle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"model-name/eagle3-head"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"num_speculative_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Results on Qwen3-30B-A3B:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;num_speculative_tokens&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Avg tok/s&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0 (baseline)&lt;/td&gt;
&lt;td&gt;~33&lt;/td&gt;
&lt;td&gt;Qwen3-30B-A3B baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;~38–40&lt;/td&gt;
&lt;td&gt;~+20% improvement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;~15–17&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Severe degradation&lt;/strong&gt; (8-11% acceptance rate)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;num_speculative_tokens=12&lt;/code&gt; result is instructive. Even though the EAGLE3 drafter was running at 85–86 tok/s draft speed, an acceptance rate of 8–11% means the target model was rejecting the vast majority of drafts. The net result was roughly &lt;strong&gt;halved&lt;/strong&gt; generation throughput compared to baseline.&lt;/p&gt;

&lt;p&gt;This is the fundamental constraint of autoregressive drafters: each additional speculative token must be generated &lt;em&gt;sequentially&lt;/em&gt; by the drafter. Drafting 12 tokens takes 12 forward passes through the draft model, and if most are rejected, you've spent significant time generating tokens the target will discard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; EAGLE3 with &lt;code&gt;num_speculative_tokens=1&lt;/code&gt; delivered a ~+20% improvement on the 30B-A3B model. The method scales poorly with higher speculative token counts unless the acceptance rate is very high (&amp;gt;85%).&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 4: DFlash (Block Diffusion Speculative Decoding)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Concept:&lt;/strong&gt; DFlash is the most architecturally novel method in this comparison, and addresses the core limitation of autoregressive drafters: the serial bottleneck. Instead of generating draft tokens one at a time, DFlash uses a &lt;strong&gt;lightweight block diffusion model&lt;/strong&gt; that generates a block of up to 16 tokens &lt;strong&gt;in a single forward pass&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The method draws inspiration from image generation diffusion models. In image diffusion, all pixels are generated in parallel via iterative denoising. DFlash adapts this concept to token generation: the drafter generates an entire block of masked tokens simultaneously, denoised in a single step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The target model processes the prompt and extracts &lt;strong&gt;hidden context features&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;These features are injected directly into the &lt;strong&gt;KV cache&lt;/strong&gt; of the draft diffusion block&lt;/li&gt;
&lt;li&gt;The diffusion head generates K tokens in one forward pass, conditioned on the target model's deep representations&lt;/li&gt;
&lt;li&gt;The target model verifies the proposed block with a single forward pass&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key difference from EAGLE3: because the block is generated in parallel, the &lt;strong&gt;marginal cost of generating additional speculative tokens approaches zero&lt;/strong&gt;. Generating 16 tokens takes roughly the same time as generating 4. This means DFlash can use far higher speculative token counts without the exponential cost increase that punishes autoregressive drafters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance ceiling:&lt;/strong&gt; Published benchmarks from the original DFlash paper (Chen et al., arXiv:2602.06036) show over 6x lossless acceleration on Qwen3 models, delivering up to 2.5x higher speedup than EAGLE3 on reasoning-heavy tasks. On coding benchmarks, acceptance lengths of 6–7 tokens per step were reported — double what EAGLE3 achieves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vLLM configuration (DFlash):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vllm serve /models/qwen35-122b-hybrid-int4fp8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attention-backend&lt;/span&gt; FLASHINFER &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--speculative-config&lt;/span&gt; &lt;span class="s1"&gt;'{
    "method": "dflash",
    "model": "z-lab/Qwen3.5-122B-DFlash",
    "num_speculative_tokens": 16
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The DFlash head for the Qwen3.5-122B model was created by ZLab and is available on Hugging Face. Setup requires following a specific GitHub recipe (link in video description).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8asoeoa4rkuj48pd9djb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8asoeoa4rkuj48pd9djb.png" alt=" " width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observed behavior:&lt;/strong&gt; DFlash showed high throughput variance. When the acceptance rate was strong (high-structure output like code), peak throughput hit &lt;strong&gt;~78 tok/s&lt;/strong&gt; — significantly exceeding MTP-2. However, for general-purpose prompts, throughput fell to ~30–33 tok/s average, with peaks to ~50 tok/s.&lt;/p&gt;

&lt;p&gt;The variance is explained by DFlash's acceptance semantics. Unlike autoregressive drafters where individual token rejections are isolated, DFlash accepts a &lt;strong&gt;prefix&lt;/strong&gt; of the diffusion block. If the target model accepts tokens 1–3 but rejects token 4, tokens 5–16 are discarded entirely even if they would have been accepted. This means low acceptance rate at any position in the block wastes the entire remaining draft. When the task is highly structured (code, JSON, math), the acceptance rate is consistently high across positions, and DFlash dominates. For open-ended generation, variance is high.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; DFlash achieved the highest peak throughput (~78 tok/s) but also the highest variance. Average throughput for general prompts was lower than MTP-2. For structured-output tasks (coding agents, JSON generation), DFlash is compelling. It is also a relatively new method and actively improving.&lt;/p&gt;




&lt;h2&gt;
  
  
  Results Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Avg tok/s&lt;/th&gt;
&lt;th&gt;Peak tok/s&lt;/th&gt;
&lt;th&gt;Acceptance Rate&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;None (baseline)&lt;/td&gt;
&lt;td&gt;Qwen3.5-122B&lt;/td&gt;
&lt;td&gt;~36–37&lt;/td&gt;
&lt;td&gt;~38&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N-Gram&lt;/td&gt;
&lt;td&gt;Qwen3.5-122B&lt;/td&gt;
&lt;td&gt;~28–30&lt;/td&gt;
&lt;td&gt;~31&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;td&gt;Worse than baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MTP-1&lt;/td&gt;
&lt;td&gt;Qwen3.5-122B&lt;/td&gt;
&lt;td&gt;~44–45&lt;/td&gt;
&lt;td&gt;~47&lt;/td&gt;
&lt;td&gt;Mid-to-high 80s%&lt;/td&gt;
&lt;td&gt;Solid improvement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MTP-2&lt;/td&gt;
&lt;td&gt;Qwen3.5-122B&lt;/td&gt;
&lt;td&gt;~48–49&lt;/td&gt;
&lt;td&gt;~51&lt;/td&gt;
&lt;td&gt;~80%+&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Best consistency&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MTP-4&lt;/td&gt;
&lt;td&gt;Qwen3.5-122B&lt;/td&gt;
&lt;td&gt;~34–35&lt;/td&gt;
&lt;td&gt;~38&lt;/td&gt;
&lt;td&gt;Drops significantly&lt;/td&gt;
&lt;td&gt;Worse than MTP-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;None (baseline)&lt;/td&gt;
&lt;td&gt;Qwen3-30B-A3B&lt;/td&gt;
&lt;td&gt;~33&lt;/td&gt;
&lt;td&gt;~40&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Separate model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EAGLE3 (1 token)&lt;/td&gt;
&lt;td&gt;Qwen3-30B-A3B&lt;/td&gt;
&lt;td&gt;~38–39&lt;/td&gt;
&lt;td&gt;~41&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;~20% improvement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DFlash&lt;/td&gt;
&lt;td&gt;Qwen3.5-122B&lt;/td&gt;
&lt;td&gt;~48–50 avg*&lt;/td&gt;
&lt;td&gt;~78&lt;/td&gt;
&lt;td&gt;Variable&lt;/td&gt;
&lt;td&gt;High peaks, high variance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*DFlash average varies significantly by task type (structured vs. open-ended).&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Guidance: Choosing the Right Method
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use MTP&lt;/strong&gt; if your model ships with a native MTP head (Qwen3.5, DeepSeek V3, Gemma 4). It is the lowest-friction option — no separate model download, no architecture mismatch risk, and acceptance rates are consistently high because the head was jointly trained. &lt;code&gt;num_speculative_tokens=2&lt;/code&gt; is a strong default for most Qwen3.5 deployments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use EAGLE3&lt;/strong&gt; if no MTP head is available and a well-matched EAGLE3 drafter exists for your target model on Hugging Face. Keep &lt;code&gt;num_speculative_tokens&lt;/code&gt; conservatively at 1–4; beyond that, acceptance rates drop sharply for most tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use DFlash&lt;/strong&gt; for structured-output workloads: code generation, function calling, JSON mode, math. The parallel drafting architecture gives DFlash a fundamental advantage when the output has strong syntactic structure and acceptance rates across the block are consistently high. Avoid it for open-ended chat where variance makes latency unpredictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoid N-Gram&lt;/strong&gt; for general inference. It is primarily useful as a pedagogical example or in specialized summarization/extraction pipelines where output closely mirrors input.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speculative decoding is lossless.&lt;/strong&gt; Output quality is mathematically identical to standard autoregressive decoding. The only variable is throughput.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acceptance rate is everything.&lt;/strong&gt; More speculative tokens are not always better. The acceptance rate at each position compounds — even a single bad position in an autoregressive chain invalidates all subsequent drafts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DFlash's parallel drafting breaks the serial constraint.&lt;/strong&gt; By generating blocks in a single forward pass, DFlash eliminates the per-token cost overhead that limits autoregressive drafters at high &lt;code&gt;K&lt;/code&gt;. This is the architectural reason its peak throughput is so high.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task type matters.&lt;/strong&gt; Structured output (code, JSON, math) consistently benefits more from speculative decoding than open-ended generation, because the conditional distribution is sharper and easier for any drafter to model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware matters.&lt;/strong&gt; These numbers are specific to the DGX Spark GB10 (SM121, 128 GB unified memory). Results on H100, A100, or consumer GPUs will differ due to memory bandwidth, compute, and kernel optimization differences.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want more detail, here is a YT video I did, going through the tests:   &lt;iframe src="https://www.youtube.com/embed/jCUHWeXehnI"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/albond/DGX_Spark_Qwen3.5-122B-A10B-AR-INT4" rel="noopener noreferrer"&gt;albond/DGX_Spark_Qwen3.5-122B-A10B-AR-INT4&lt;/a&gt; — Hybrid checkpoint + MTP patch recipe&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://arxiv.org/abs/2602.06036" rel="noopener noreferrer"&gt;DFlash paper: arXiv:2602.06036&lt;/a&gt; — Block Diffusion for Flash Speculative Decoding&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/z-lab" rel="noopener noreferrer"&gt;ZLab DFlash models on Hugging Face&lt;/a&gt; — DFlash heads for Qwen3 models&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.vllm.ai/en/latest/features/speculative_decoding/" rel="noopener noreferrer"&gt;vLLM Speculative Decoding docs&lt;/a&gt; — Configuration reference&lt;/li&gt;
&lt;li&gt;&lt;a href="https://publish.obsidian.md/shri/Appendix/Inference+Acceleration/EAGLE-3" rel="noopener noreferrer"&gt;EAGLE3 architecture reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>benchmark</category>
      <category>agents</category>
    </item>
    <item>
      <title>The AI agent habit that was quietly wasting my time and tokens</title>
      <dc:creator>Kristiyan Stoyanov</dc:creator>
      <pubDate>Tue, 23 Jun 2026 20:39:55 +0000</pubDate>
      <link>https://dev.to/kstoyanovai/the-ai-agent-habit-that-was-quietly-wasting-my-time-and-tokens-2jmi</link>
      <guid>https://dev.to/kstoyanovai/the-ai-agent-habit-that-was-quietly-wasting-my-time-and-tokens-2jmi</guid>
      <description>&lt;h1&gt;
  
  
  The AI Agent Habit That Was Quietly Wasting My Time and Tokens
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Tags: ai, localai, machinelearning, productivity, agents&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I realized I had been using AI agents in a way that looked smart but was actually pretty wasteful.&lt;/p&gt;

&lt;p&gt;The pattern was simple: I would ask the agent for something useful, it would go off and figure it out, and eventually I would get an answer. The problem is that if you keep asking the agent to rediscover the same process over and over, you are paying for repeated reasoning, repeated tool usage, and repeated trial and error. That means more tokens, more latency, and more opportunities for the agent to fumble.&lt;/p&gt;

&lt;p&gt;What finally clicked for me was this: use LLM inference for decisions, not for repetition.&lt;/p&gt;

&lt;p&gt;If a task has already been figured out once, I do not want the model burning context and tool calls to solve it again every time. I want the model to recognize the task, use a reliable tool, and move on.&lt;/p&gt;

&lt;p&gt;That is the pattern I have been using with Hermes, and it has made my local agent setup much more useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup I Am Running
&lt;/h2&gt;

&lt;p&gt;Right now I am running Hermes on a DGX Spark. In the video, I show the machine with 128 GB of unified memory, and at that moment I had about 1 GB free because I had a quantized Qwen 3.5 model loaded locally.&lt;/p&gt;

&lt;p&gt;Hermes is my current agent framework of choice. I have tried other options, but Hermes has been easy to install and easy to live with. One thing I especially like is that it supports Telegram through a gateway, so I can talk to my agent from my phone instead of only from a terminal window.&lt;/p&gt;

&lt;p&gt;On the tool side, the ones that matter most for this workflow are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web search and scraping&lt;/li&gt;
&lt;li&gt;Terminal access&lt;/li&gt;
&lt;li&gt;File operations&lt;/li&gt;
&lt;li&gt;Code execution&lt;/li&gt;
&lt;li&gt;Sub-agent delegation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For web search, I am using Tavily. In the video, I mention the free tier gives about 1,000 requests per month, which is enough for experimentation but still limited enough that I notice when an agent wastes calls.&lt;/p&gt;

&lt;p&gt;That matters, because this whole post is really about reducing unnecessary tool usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wasteful Version
&lt;/h2&gt;

&lt;p&gt;I started with a normal prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is the weather going to be like in Sofia this weekend? Help me plan some activities based on it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is exactly the kind of thing I would send to an agent from Telegram while I am on the move.&lt;/p&gt;

&lt;p&gt;Hermes did eventually answer, but watching the trace was the important part. It did a web search, then a web extract, then checked time and date, then stumbled a bit, then searched again after not getting what it wanted the first time. In the video, I call out the real cost: this simple request filled about 20k tokens of context.&lt;/p&gt;

&lt;p&gt;And that is the issue.&lt;/p&gt;

&lt;p&gt;The answer was fine. The process was not.&lt;/p&gt;

&lt;p&gt;If I ask for weather and activity suggestions regularly, I do not want the model improvising a mini research project every single time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Better Version: Research Once, Automate Once, Reuse Forever
&lt;/h2&gt;

&lt;p&gt;Instead of asking the agent the end question again, I switched to building a capability.&lt;/p&gt;

&lt;p&gt;First, I asked Hermes to research free weather APIs that did not need a key and were easy to automate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Research free and open APIs that give you weather forecasts. Look for APIs that do not need an API key and can be easily automated with a Python script. Do not write the script yet. Let me choose the API first.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes went off, searched around, and came back with several options, including Open-Meteo, WeatherAPI, and met.no. It recommended Open-Meteo, and that was good enough for me.&lt;/p&gt;

&lt;p&gt;So I moved to the next step and told it to build something concrete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's use Open-Meteo. I want you to spawn an open code sub-agent and create a directory. Inside of that directory the sub-agent must implement an Open-Meteo API client wrapped by a CLI. Use Python. Make sure it uses real data. Use mocks only for unit tests. Report back when ready.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That “use real data, mocks only for unit tests” line is one I use a lot. If the agent can run against reality, it can verify its own work much better.&lt;/p&gt;

&lt;p&gt;Hermes delegated the task to a coding-focused sub-agent, created the project, and implemented the CLI.&lt;/p&gt;

&lt;p&gt;Then came the part that matters most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Never Trust the Agent
&lt;/h2&gt;

&lt;p&gt;When the agent said the project was complete, I did not just accept it.&lt;/p&gt;

&lt;p&gt;I tested it with a real request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Now let's test it with the real API. I want you to use the script to give me the weather forecast for Berlin.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the rule I keep coming back to: never trust your agent.&lt;/p&gt;

&lt;p&gt;Read the code. Run the script. Verify the output. Make sure it is using the real API. Make sure it is not doing anything unexpected. Only after that should it move from “experiment” to “capability.”&lt;/p&gt;

&lt;p&gt;In the demo, the script returned a 7-day Berlin forecast in about 0.4 seconds. That is the moment where the whole pattern becomes obvious. The slow, token-heavy part was discovering how to do the task. Once that is solved, the best move is to package it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning a One-Off Script into a Permanent Skill
&lt;/h2&gt;

&lt;p&gt;Once the weather CLI worked, I asked Hermes to wrap it as a reusable skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Now let's create a skill for you that wraps around this CLI script and uses it whenever I ask you about the weather in future sessions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes created the skill using its skill management flow, and that became part of its permanent skill set.&lt;/p&gt;

&lt;p&gt;Then I started a completely new session.&lt;/p&gt;

&lt;p&gt;That is the real test, because a fresh session has fresh context. No hidden memory from the earlier chat. No cheating.&lt;/p&gt;

&lt;p&gt;I asked the same question again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is the weather going to be like in Sofia this weekend? Help me plan some activities based on it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time Hermes checked its skills, found the weather skill, executed the script, and gave me a clean answer with activity suggestions.&lt;/p&gt;

&lt;p&gt;The difference was huge.&lt;/p&gt;

&lt;p&gt;The first time, it burned through web searches, including two Tavily searches, and spent a lot of tokens figuring out how to answer. The second time, it reduced the whole thing to essentially one tool call to the script I had already verified.&lt;/p&gt;

&lt;p&gt;That is the pattern in one line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Explore once. Automate once. Wrap it as a skill. Reuse forever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  This Gets More Interesting Than Weather
&lt;/h2&gt;

&lt;p&gt;Weather is a toy example, but it is useful because the waste is easy to see.&lt;/p&gt;

&lt;p&gt;The more interesting example from the video is one I built from my phone over Telegram. I use my agent pretty often for stock-related questions, so I had it create a stock analyzer script that fetches stock or index data from an open API.&lt;/p&gt;

&lt;p&gt;Same pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a stock analyzer Python script that fetches stock or index data from a popular and open API. Use real data. Use mocks only for unit tests.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it finished, I verified it with a real run for Microsoft one year back. The output included about 250 trading days of data, the latest price, some moving averages, technical indicators, and a short interpretation.&lt;/p&gt;

&lt;p&gt;Then I turned that into a skill too.&lt;/p&gt;

&lt;p&gt;In a brand-new session, I asked a vague question about the USO ETF. I did not mention the script. I did not explain the workflow again. Hermes picked the stock analyzer skill on its own and returned a useful summary with current data.&lt;/p&gt;

&lt;p&gt;That is where this starts to feel less like chatting with a model and more like growing a personal assistant over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security Rule I Want to Keep
&lt;/h2&gt;

&lt;p&gt;The core safety idea here is simple: verify before you automate.&lt;/p&gt;

&lt;p&gt;If an agent writes a script, read it. If it claims something works, test it. If it needs access to real systems, expose only the operations you actually want it to perform.&lt;/p&gt;

&lt;p&gt;For anything sensitive, I would keep the agent on the narrowest possible rails. In practice, that means preferring read-only capabilities where possible, using small purpose-built tools instead of broad access, and only promoting a workflow into a permanent skill after I have seen it behave correctly.&lt;/p&gt;

&lt;p&gt;The more capable the agent gets, the more important this becomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;What I like most about this pattern is that it compounds.&lt;/p&gt;

&lt;p&gt;Every time I notice a repeated agent task, I have a choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep paying for the agent to rediscover the solution.&lt;/li&gt;
&lt;li&gt;Or turn the solution into a reusable capability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over time, that changes the shape of the whole setup.&lt;/p&gt;

&lt;p&gt;I stop treating the model like a universal improviser and start treating it like a coordinator that knows when to call reliable tools. The model still provides the intelligence, but the repetitive parts move into code.&lt;/p&gt;

&lt;p&gt;That opens the door to more domain-specific assistants too. A natural next step is something like a private realtor assistant that checks listings, pulls mortgage news, summarizes changes, and sends a Telegram update on a schedule. Same principle, just applied to a workflow that actually matters to someone day to day.&lt;/p&gt;

&lt;p&gt;That is the part I find exciting. Not AI magic, but a steadily improving assistant that gets more useful because I keep teaching it durable skills.&lt;/p&gt;

&lt;p&gt;If you want to see the full walkthrough, including the Hermes session, the weather skill build, and the Telegram-based stock example, watch the YouTube video here:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/ZmYmY91rMkE"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you are experimenting with agents locally, I would love to hear what repeated task you would turn into a skill first.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>agentskills</category>
      <category>hermes</category>
    </item>
  </channel>
</rss>
