<?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: Aaron Vaz</title>
    <description>The latest articles on DEV Community by Aaron Vaz (@myne06).</description>
    <link>https://dev.to/myne06</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%2F4233247%2Fbe673c5e-4588-4564-b9df-e03556e3a915.png</url>
      <title>DEV Community: Aaron Vaz</title>
      <link>https://dev.to/myne06</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/myne06"/>
    <language>en</language>
    <item>
      <title>Why a System-1 Decision Model Beat a Small Local LLM on My Laptop</title>
      <dc:creator>Aaron Vaz</dc:creator>
      <pubDate>Sun, 08 Nov 2026 07:32:26 +0000</pubDate>
      <link>https://dev.to/myne06/why-a-system-1-decision-model-beat-a-small-local-llm-on-my-laptop-22od</link>
      <guid>https://dev.to/myne06/why-a-system-1-decision-model-beat-a-small-local-llm-on-my-laptop-22od</guid>
      <description>&lt;h1&gt;
  
  
  Why a System-1 Decision Model Beat a Small Local LLM on My Laptop
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; myne (&lt;code&gt;mvyne06&lt;/code&gt;)&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Hardware:&lt;/strong&gt; AMD Ryzen 5 5625U (6 Cores / 12 Threads), 16 GB DDR4-3200 RAM, Integrated AMD Radeon Graphics&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/mvyne06/edge-agent-bottlenecks" rel="noopener noreferrer"&gt;github.com/mvyne06/edge-agent-bottlenecks&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Tooling &amp;amp; Attribution:&lt;/strong&gt; Project narrative, hardware setup, and testing by &lt;code&gt;myne&lt;/code&gt;; terminal log profiling, architectural diagrams, and benchmark formatting assisted by Google Antigravity.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Project Motivation &amp;amp; Narrative
&lt;/h2&gt;

&lt;p&gt;My goal was to run an SLM locally and connect it to a cloud LLM environment (Google Antigravity). However, this didn't end up working as I expected.&lt;/p&gt;

&lt;p&gt;The original plan was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up Qwen 3.5-4B (later changed to a 2B model due to horrible performance).&lt;/li&gt;
&lt;li&gt;Set up a Telegram bot connected to the model.&lt;/li&gt;
&lt;li&gt;Keep the model running permanently on my hardware.&lt;/li&gt;
&lt;li&gt;Connect it to Google Antigravity or OmniRoute (an API routing bridge) so that it could build things on its own.&lt;/li&gt;
&lt;li&gt;Have it be my assistant when needed, and during downtime let it do whatever it wanted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Laptop specs:&lt;/strong&gt; AMD Ryzen 5 5625U, 16 GB DDR4-3200 RAM (dual channel).&lt;/p&gt;

&lt;p&gt;I originally tried running Qwen 3.5-4B as it scored the highest on benchmarks and seemed the best at the time. &lt;code&gt;llama.cpp&lt;/code&gt; was set up using Vulkan so that the model ran on the iGPU to be more efficient. In this case, the iGPU and CPU share the same bus and RAM, but my reasoning was that the iGPU should be more efficient since it's better at matrix math.&lt;/p&gt;

&lt;p&gt;The performance was really bad; it took really long for the model to do anything, even simple tasks. I tried switching to the CPU, but that didn't do much. So I caved and switched to an even smaller model (Qwen 3.5-2B). The performance boost was marginal.&lt;/p&gt;

&lt;p&gt;I was going to call it quits, but then I remembered reading about Jev. That got me thinking if there was an open-source System-1 decision model - &lt;strong&gt;AND THERE WAS!&lt;/strong&gt; Laya was the obvious choice, and it runs comfortably on my hardware.&lt;/p&gt;

&lt;p&gt;Frontier cloud models (like Gemini, Claude, GPT, or DeepSeek/Qwen cloud flagships) outcompete local models tenfold. On lower-end hardware, it doesn't make sense to run even small text-generation models for multi-step agent tasks when they bottleneck on hardware. So I'm sticking to using fast System-1 decision models locally, and offloading heavy reasoning to cloud models.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Hardware Bottlenecks: Memory Bandwidth &amp;amp; Vulkan vs. CPU
&lt;/h2&gt;

&lt;p&gt;My laptop uses an AMD Ryzen 5 5625U chip where the CPU cores and the Radeon iGPU share the same DDR4 system memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------------------------------------------------------+
|             AMD Ryzen 5 5625U (15W Laptop Chip)              |
|  +-------------------------+    +-------------------------+  |
|  |   6 Zen 3 CPU Cores     |    |   Radeon Vega 7 (iGPU)  |  |
|  +-------------------------+    +-------------------------+  |
|               |                              |               |
|               +--------------+---------------+               |
|                              |                               |
|                  Shared Memory Controller                    |
+------------------------------+-------------------------------+
                               |
             +-----------------+-----------------+
             |   16 GB DDR4-3200 (Dual Channel)  |
             +-----------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the model has to load its weights from shared DDR4 RAM for every word it writes, the smaller 2B model (~1.34 GB, ~12-15 tokens/sec) was roughly twice as fast at typing as the 4B model (~2.8 GB, ~7.4 tokens/sec).&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Vulkan iGPU Mode Didn't Help
&lt;/h3&gt;

&lt;p&gt;I thought running the model on the iGPU via Vulkan would be faster. But because the iGPU doesn't have its own dedicated VRAM and shares the exact same RAM as the CPU, Vulkan just added extra driver overhead. It also pushed my RAM usage up to &lt;strong&gt;12.5 GB (81%)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When I switched &lt;code&gt;llama-server&lt;/code&gt; to use 6 CPU threads directly (&lt;code&gt;-ngl 0 -t 6&lt;/code&gt;), generation speed stayed about the same, but my RAM usage dropped down to &lt;strong&gt;9.4 GB (61%)&lt;/strong&gt; and CPU load settled around 25%, leaving my laptop much cooler and more responsive.&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%2Frgz25lxx92689z2iok0z.jpg" 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%2Frgz25lxx92689z2iok0z.jpg" alt="Figure 1: Hardware Usage under CPU Mode" width="799" height="498"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1: Task Manager showing 9.4 GB (61%) RAM usage and 25% CPU load running on 6 threads (compared to 12.5 GB / 81% RAM under Vulkan).&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Why Multi-Step Tool Calls Were So Slow (Prompt Reading Time)
&lt;/h2&gt;

&lt;p&gt;Seeing 12-15 tokens/sec on paper made me think Qwen 3.5-2B would feel reasonably fast. But the moment I asked the bot to do a real task - like using &lt;code&gt;obscura&lt;/code&gt; to fetch Hacker News and summarize the top post - it took &lt;strong&gt;over 60 seconds&lt;/strong&gt; to respond.&lt;/p&gt;

&lt;p&gt;When I checked the &lt;code&gt;llama-server&lt;/code&gt; terminal logs, I realized the problem wasn't typing speed. The real bottleneck was &lt;strong&gt;prompt evaluation time&lt;/strong&gt; (the time the model spends reading the text before it can write anything):&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;sequenceDiagram
    autonumber
    actor User as Me (on Telegram)
    participant Orch as Vivian Orchestrator
    participant Model as Qwen 3.5-2B (CPU)
    participant Tool as obscura_browse

    User-&amp;gt;&amp;gt;Orch: "Fetch news.ycombinator.com and summarize"
    Note over Orch,Model: Step 1: Reading prompt &amp;amp; picking tool
    Orch-&amp;gt;&amp;gt;Model: System rules + tool list + query (1,337 tokens)
    activate Model
    Note over Model: Reading prompt: 17.87s&amp;lt;br/&amp;gt;Generating tool call: 6.05s
    Model--&amp;gt;&amp;gt;Orch: Run obscura_browse(...)
    deactivate Model

    Note over Orch,Tool: Step 2: Running the tool
    Orch-&amp;gt;&amp;gt;Tool: Scrape news.ycombinator.com
    activate Tool
    Tool--&amp;gt;&amp;gt;Orch: Returns ~3,500 chars of web text (1.8s)
    deactivate Tool

    Note over Orch,Model: Step 3: Reading web text &amp;amp; writing summary
    Orch-&amp;gt;&amp;gt;Model: Old history + scraped web text (1,548 tokens)
    activate Model
    Note over Model: Reading prompt: 28.88s&amp;lt;br/&amp;gt;Generating summary: 5.61s
    Model--&amp;gt;&amp;gt;Orch: "Goodbye Claude, Hello Pi..."
    deactivate Model

    Orch-&amp;gt;&amp;gt;User: Telegram message received (60.2s total wait)&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  The Real Numbers from My Terminal
&lt;/h3&gt;

&lt;p&gt;Looking at my &lt;code&gt;llama-server&lt;/code&gt; terminal log in Figure 2:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Step 1:&lt;/strong&gt; The model spent &lt;strong&gt;17.87 seconds&lt;/strong&gt; just reading the prompt and tool instructions (1,337 tokens), and 6.05 seconds generating the tool call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Step:&lt;/strong&gt; &lt;code&gt;obscura.exe&lt;/code&gt; fetched the web page in &lt;strong&gt;1.8 seconds&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2:&lt;/strong&gt; When the web text was added back into the prompt (1,548 tokens), the model spent another &lt;strong&gt;28.88 seconds&lt;/strong&gt; just reading it, and 5.61 seconds writing the short summary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total Time:&lt;/strong&gt; &lt;strong&gt;~58.4 seconds of model time&lt;/strong&gt; (&lt;strong&gt;60.2 seconds total&lt;/strong&gt; with the web fetch).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Out of that 60.2-second wait, the model spent &lt;strong&gt;46.75 seconds (80%) just reading prompts&lt;/strong&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%2F84s017rzjq0qlo3v43xk.jpg" 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%2F84s017rzjq0qlo3v43xk.jpg" alt="Figure 2: llama-server Terminal Telemetry" width="800" height="405"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 2: My terminal output showing 17.87s and 28.88s spent reading prompts.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Negative Result: Open-Ended Loops Fail
&lt;/h3&gt;

&lt;p&gt;When I gave the bot a bounded single-step task, it worked (it pulled the headline &lt;em&gt;"Goodbye Claude, Hello Pi"&lt;/em&gt;). But when I gave it an open-ended autonomous prompt (&lt;em&gt;"Find random facts about philosophy... Keep going through the web"&lt;/em&gt;), the 2B model got stuck re-reading growing context over and over until my watchdog killed it (&lt;code&gt;TurnAborted: Turn token budget exhausted&lt;/code&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%2F6nhiv8yp5m634faoy6ph.jpg" 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%2F6nhiv8yp5m634faoy6ph.jpg" alt="Figure 3: Telegram Test Output" width="460" height="1024"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 3: Telegram showing the open-ended task aborting after running out of tokens, next to the successful Hacker News test.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Solution: Using Laya for Fast System-1 Routing
&lt;/h2&gt;

&lt;p&gt;After seeing a 2B model take 24 seconds just to decide to run &lt;code&gt;obscura&lt;/code&gt;, I realized asking a text-generation model to be the "brain" on a laptop doesn't make sense.&lt;/p&gt;

&lt;p&gt;Instead, I split the work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System 1 (Local):&lt;/strong&gt; Use a fast decision model (&lt;strong&gt;Laya&lt;/strong&gt;, 421M parameters) locally to inspect the user's message, pick the right tool, and check if it's safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System 2 (Cloud):&lt;/strong&gt; If a task requires heavy writing, coding, or complex reasoning, hand it off to a frontier cloud model (like Gemini or Claude).
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;graph LR
    User(["My Request"]) --&amp;gt; Router["Local System-1: Laya 421M&amp;lt;br/&amp;gt;(~919 ms, 0 Tokens)"]
    Router --&amp;gt;|"Simple Tool Task"| LocalTools["Local Tools (obscura, File I/O)"]
    Router --&amp;gt;|"Complex Coding / Reasoning"| Cloud["Frontier Cloud Model (Gemini / Claude)"]&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  Testing Laya on My Ryzen 5 CPU
&lt;/h3&gt;

&lt;p&gt;I tested Laya (&lt;code&gt;convaiinnovations/laya&lt;/code&gt;, built on ModernBERT) on my laptop CPU using the exact same Hacker News request (&lt;code&gt;benchmark_laya.py&lt;/code&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%2Filzijqek25ie0s4xddo1.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%2Filzijqek25ie0s4xddo1.png" alt="Figure 4: Laya Benchmark Output" width="799" height="356"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 4: Console benchmark showing Laya routing the request in ~918 ms.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision:&lt;/strong&gt; It picked &lt;code&gt;obscura_web_fetch&lt;/code&gt; with &lt;strong&gt;99.82% probability&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; Across 5 runs on my CPU, it averaged &lt;strong&gt;918.82 ms&lt;/strong&gt; (under 1 second).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokens Output:&lt;/strong&gt; &lt;strong&gt;0 tokens&lt;/strong&gt;. Because Laya just classifies the text and outputs a score in one go instead of generating words one by one, it never gets bogged down reading and writing long text.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Summary Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Parameters&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Prompt Reading Time&lt;/th&gt;
&lt;th&gt;Typing Speed&lt;/th&gt;
&lt;th&gt;Time to Pick Tool&lt;/th&gt;
&lt;th&gt;Output Tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qwen 3.5-4B&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.0B&lt;/td&gt;
&lt;td&gt;Vulkan iGPU&lt;/td&gt;
&lt;td&gt;~30.6s&lt;/td&gt;
&lt;td&gt;~7.4 t/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~38.0s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;70+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qwen 3.5-2B&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.0B&lt;/td&gt;
&lt;td&gt;Zen 3 CPU&lt;/td&gt;
&lt;td&gt;17.8s - 28.9s&lt;/td&gt;
&lt;td&gt;~12.0 - 15.0 t/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~23.9s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;79+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Laya (ModernBERT)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;421M&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Zen 3 CPU&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0s (Single Pass)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;N/A&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~0.92s (919 ms)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Laya made the tool routing decision &lt;strong&gt;26x faster&lt;/strong&gt; than Qwen 3.5-2B and &lt;strong&gt;41x faster&lt;/strong&gt; than Qwen 3.5-4B.&lt;/li&gt;
&lt;li&gt;Because it generates 0 tokens, it completely avoids memory bandwidth slowdowns and won't get stuck in token-budget loops.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Conclusion
&lt;/h2&gt;

&lt;p&gt;Trying to run small text-generation models locally for autonomous agent loops on normal laptop hardware runs straight into memory bandwidth and prompt reading bottlenecks. &lt;/p&gt;

&lt;p&gt;Using my laptop hardware as a &lt;strong&gt;System-1 router&lt;/strong&gt; with a fast model like Laya to handle instant tool decisions - while letting frontier cloud models handle the heavy thinking - is vastly faster and actually usable in day-to-day use.&lt;/p&gt;




&lt;h2&gt;
  
  
  Appendix: Supporting Screenshots
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Figure A (&lt;code&gt;03_task_manager_hardware_envelope.jpg&lt;/code&gt;):&lt;/strong&gt; Task Manager showing 12.5 GB (81%) memory saturation under Vulkan iGPU mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Figure B (&lt;code&gt;05_orchestrator_startup_console.png&lt;/code&gt;):&lt;/strong&gt; Vivian daemon startup log showing local jailing and webhook initialization.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
