<?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: Patrick Hughes</title>
    <description>The latest articles on DEV Community by Patrick Hughes (@pat9000).</description>
    <link>https://dev.to/pat9000</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%2F3763138%2Fa7736e79-1b96-4f55-a9f7-9ddd8775eb09.jpg</url>
      <title>DEV Community: Patrick Hughes</title>
      <link>https://dev.to/pat9000</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pat9000"/>
    <language>en</language>
    <item>
      <title>When a 4B Local LLM Beats 26B on One Task</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Thu, 13 Aug 2026 16:05:11 +0000</pubDate>
      <link>https://dev.to/pat9000/when-a-4b-local-llm-beats-26b-on-one-task-2bai</link>
      <guid>https://dev.to/pat9000/when-a-4b-local-llm-beats-26b-on-one-task-2bai</guid>
      <description>&lt;h1&gt;
  
  
  When a 4B Local LLM Beats 26B on One Task
&lt;/h1&gt;

&lt;p&gt;The smaller model won my latest local test. That sentence is true, but it needs a tight boundary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; On one mixed workshop on my RTX 5090, Gemma 3 4B produced 257.1 tokens per second while Gemma 4 26B produced 218.5. Both passed the same four fixed code checks. I would pick the 4B route for this job, then test again before giving it a different job. Canonical URL: &lt;a href="https://bmdpat.com/blog/local-llm-4b-vs-26b-task-quality-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/blog/local-llm-4b-vs-26b-task-quality-2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The measured rows are in &lt;code&gt;Reports/5090/benchmarks/workshop-discoveries.csv&lt;/code&gt;, rows 2 through 5. The public &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;5090 Reports notebook&lt;/a&gt; explains the measurement method and hardware frame.&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%2Fx1cub7gln9qex0zsigkl.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%2Fx1cub7gln9qex0zsigkl.png" alt="Gemma 3 4B and Gemma 4 26B compared on speed and fixed code checks" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Can a 4B local model beat a 26B model?
&lt;/h2&gt;

&lt;p&gt;Yes, on a named workload with a named pass condition. Model size is not a score.&lt;/p&gt;

&lt;p&gt;My workshop ran three generation prompts capped at 200 output tokens and four fixed code tasks. The runtime was Ollama on an RTX 5090. Both rows used a 2,048-token context and &lt;code&gt;num_batch=512&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Gemma 3 4B generated 475 output tokens at 257.1 tokens per second. Gemma 4 26B generated 482 output tokens at 218.5 tokens per second. Both passed all four code checks.&lt;/p&gt;

&lt;p&gt;That is a useful result for this workshop. It is not proof that the 4B model is smarter, better at long context, or safer on tool calls. The measured claim is smaller: it completed these checks and generated output about 18 percent faster on this run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does task quality come before tokens per second?
&lt;/h2&gt;

&lt;p&gt;A fast wrong answer is wasted GPU time. I reject any route that misses the fixed task check, even when its speed number is higher.&lt;/p&gt;

&lt;p&gt;The same workshop recorded a Gemma 4 26B run at 156.9 tokens per second with zero of four code checks passing. A later setting for that model reached 215.7 tokens per second and passed all four. The model name stayed the same. The usable result changed with the tested configuration.&lt;/p&gt;

&lt;p&gt;This is why my &lt;a href="https://bmdpat.com/blog/local-llm-honest-eval-numbers-2026" rel="noopener noreferrer"&gt;guide to honest local LLM benchmark numbers&lt;/a&gt; keeps the denominator beside every pass rate. Four of four is a smoke test, not a universal grade. It earns the next test.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should a local model comparison hold fixed?
&lt;/h2&gt;

&lt;p&gt;Start with the workload. Use the same prompts, output cap, context size, runtime path, and verifier. Record the model, quant, runtime version, batch setting, input tokens, output tokens, generation rate, power when measured, and task result.&lt;/p&gt;

&lt;p&gt;Do not merge cold and resident requests. Do not compare a short chat prompt with a long code file. My &lt;a href="https://bmdpat.com/blog/local-llm-input-output-benchmark-2026" rel="noopener noreferrer"&gt;input and output benchmark guide&lt;/a&gt; separates load time, prompt ingestion, output generation, and task checks because each phase answers a different question.&lt;/p&gt;

&lt;p&gt;This workshop did not produce a complete model ranking. It produced one deployable choice for one narrow lane. That is enough to save VRAM and time without pretending the row says more than it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  When would I still choose the 26B model?
&lt;/h2&gt;

&lt;p&gt;I would keep the larger model when the real job asks for something the four code checks did not cover.&lt;/p&gt;

&lt;p&gt;Longer context may change the result. A harder edit may expose planning errors. Structured tool calls may fail even when plain code passes. Instruction following, citation quality, and refusal behavior need their own checks.&lt;/p&gt;

&lt;p&gt;The next test should match production work. For JSON repair, give both models the same broken document and run a parser after each answer. For code edits, run the same focused test suite. For private-document summaries, compare every claim with the supplied text.&lt;/p&gt;

&lt;p&gt;Pick the smallest model that passes the real gate. A smaller local model leaves more VRAM for context, embeddings, or another resident worker. The task check decides whether that saved memory matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What model-selection rule did I keep?
&lt;/h2&gt;

&lt;p&gt;I use four steps.&lt;/p&gt;

&lt;p&gt;First, name the job. Second, set a deterministic pass condition. Third, compare speed and resource use only among passing routes. Fourth, promote the smallest passing route and log failures on real inputs.&lt;/p&gt;

&lt;p&gt;The RTX 5090 has 32 GB of VRAM, so both models fit this test. Fit did not pick the winner. Four fixed checks did. I can rerun those checks after a model or runtime change.&lt;/p&gt;

&lt;p&gt;Fit narrows the list. Runtime support narrows it again. A task check picks the route. After selection, I add request, token, and rate limits with &lt;a href="https://bmdpat.com/tools/agentguard" rel="noopener noreferrer"&gt;AgentGuard&lt;/a&gt;; those runtime limits do not replace the task check.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; compares local model benchmark rows and picks the smallest route that passed the named task.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are reviewing local LLM candidates for one production task.

Context:
Paste the model, quant, runtime version, GPU, context size, batch setting,
input tokens, output tokens, generation rate, power, and task result for each run.

Task:
1. Reject every run that failed the task check.
2. Compare speed and resource use only among passing runs.
3. Pick the smallest passing route for this named job.
4. Name the next production-shaped test before the route gets more work.

Output:
- A compact comparison table.
- The chosen route and the exact reason it won.
- Claims the measurements do not support.
- The next test and its pass condition.

Constraints:
- Keep measured values separate from estimates.
- Keep the pass-rate denominator visible.
- Do not turn one workload result into a general model ranking.
- Mark missing values as unknown.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get measured local AI notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-4b-vs-26b-task-quality-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-4b-vs-26b-task-quality-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/local-llm-4b-vs-26b-task-quality-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-4b-vs-26b-task-quality-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-4b-vs-26b-task-quality-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>modelselection</category>
      <category>rtx5090</category>
      <category>ollama</category>
    </item>
    <item>
      <title>Does Ollama Include That New llama.cpp Feature?</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Tue, 11 Aug 2026 16:05:11 +0000</pubDate>
      <link>https://dev.to/pat9000/does-ollama-include-that-new-llamacpp-feature-52kk</link>
      <guid>https://dev.to/pat9000/does-ollama-include-that-new-llamacpp-feature-52kk</guid>
      <description>&lt;h1&gt;
  
  
  Does Ollama Include That New llama.cpp Feature?
&lt;/h1&gt;

&lt;p&gt;A new llama.cpp release can look like an instant upgrade. That release note does not prove that my local application can use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; I trace the request from my application to the engine that runs the model. I pin that engine version, test the same workload, and keep the old recommendation until the new code reaches the active path.&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%2F1cqo42bjalx1zofup02s.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%2F1cqo42bjalx1zofup02s.png" alt="Key decisions from Does Ollama Include That New llama.cpp Feature?" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is the release note not enough?
&lt;/h2&gt;

&lt;p&gt;My sizing desk sends requests to the Ollama HTTP API. It does not call a standalone llama.cpp binary. Ollama includes its own llama.cpp code, so a new upstream release reaches my path only after Ollama includes the needed change.&lt;/p&gt;

&lt;p&gt;The b10258 release is narrower than a new feature. It moves &lt;code&gt;n_vocab&lt;/code&gt; from shared sampler data into the penalty sampler. That is internal sampler wiring, not proof that Ollama exposes a new capability. The upstream code can exist while my installed runtime still uses an older code base. A benchmark against the wrong binary answers the wrong question.&lt;/p&gt;

&lt;p&gt;I treat runtime support as a separate gate from model fit. A model can fit in memory and still fail before its first useful token. I cover that first boundary in &lt;a href="https://bmdpat.com/blog/local-llm-vram-fit-runtime-support-2026" rel="noopener noreferrer"&gt;VRAM Fit Is Not Runtime Support&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I map the active local inference path?
&lt;/h2&gt;

&lt;p&gt;I start at the application call. I write down the endpoint, process, and executable that receive the request. Then I find which component owns model loading and token generation.&lt;/p&gt;

&lt;p&gt;For my test on August 6, 2026, the path ended at Ollama 0.31.2. No standalone &lt;code&gt;llama-cli&lt;/code&gt; or &lt;code&gt;llama-bench&lt;/code&gt; binary was on the host path. Testing a fresh llama.cpp build would have measured a different system from the sizing desk.&lt;/p&gt;

&lt;p&gt;This check is simple, but it blocks a common error. The name in a release note is not the same thing as the code in production. The active executable and its version are the facts that matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did my RTX 5090 smoke test prove?
&lt;/h2&gt;

&lt;p&gt;I used the same &lt;code&gt;llama3.1:8b&lt;/code&gt; request shape as an earlier baseline. The test fixed &lt;code&gt;num_ctx&lt;/code&gt; at 2,048, &lt;code&gt;num_predict&lt;/code&gt; at 128, and temperature at zero. Ollama reported full GPU placement during the run.&lt;/p&gt;

&lt;p&gt;Three warm runs produced 173.13, 174.91, and 173.34 tokens per second. The spread was under 1%. The GPU used 7,262 MiB of 32,607 MiB, and Ollama showed a 5.0 GB resident model.&lt;/p&gt;

&lt;p&gt;Those results proved that the active sizing path gave repeatable numbers in that session. They did not prove that llama.cpp b10258 was active. The installed Ollama build still owned the path, so I made no feature claim and changed no sizing recommendation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why did I not compare the new result with the old baseline?
&lt;/h2&gt;

&lt;p&gt;The June run recorded 216.89 tokens per second on Ollama 0.22.1. The August warm runs were near 174 tokens per second. That looks like a drop of about 20%, but the host conditions did not match.&lt;/p&gt;

&lt;p&gt;The August test ran while two package installs and the agent fleet used the same host. The first model load took 135 seconds on the busy disk, compared with 3.2 seconds in June. That test cannot isolate a runtime change.&lt;/p&gt;

&lt;p&gt;I recorded the difference as an open question. A quiet-host rerun can test it later. This is why I bind each result to the driver, runtime, workload, and time in &lt;a href="https://bmdpat.com/blog/local-llm-benchmark-provenance-gpu-snapshot-2026" rel="noopener noreferrer"&gt;How I Keep LLM Results Valid After a Driver Update&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What evidence should change a recommendation?
&lt;/h2&gt;

&lt;p&gt;I need four receipts. First, the target feature must exist upstream. Second, the active runtime must include it. Third, the model and setting must expose it. Fourth, the same workload must show a useful result without a quality loss.&lt;/p&gt;

&lt;p&gt;A version string alone clears only one part of that chain. A fast test against a separate binary also falls short. I change the recommendation only when the application path and the measured path are the same.&lt;/p&gt;

&lt;p&gt;This rule saves time. It keeps release news in a watch list until my software can use it. It also keeps a new speed result from reaching the sizing desk before the result has the right runtime and workload behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; This prompt checks whether a new local inference feature has reached the runtime that an application uses.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are a local inference compatibility reviewer.

Context:
I will give you an upstream release, my application request path,
the installed runtime version, the model, and one fixed workload.

Task:
1. Map the request from the application to the inference engine.
2. Check whether the active engine includes the target feature.
3. Run the fixed workload through the application path.
4. Separate measured facts from open questions.

Output:
- A support result for each layer in the request path.
- The exact runtime and model versions.
- The test result and one recommendation.
- A list of claims that the evidence does not support.

Constraints:
- Do not test a different binary from the application path.
- Do not infer feature support from an upstream release alone.
- Keep the old recommendation when the active runtime lacks the feature.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get measured local AI notes by email at &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;The 5090 Reports&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=ollama-llama-cpp-feature-compatibility-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=ollama-llama-cpp-feature-compatibility-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/ollama-llama-cpp-feature-compatibility-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ollama-llama-cpp-feature-compatibility-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ollama-llama-cpp-feature-compatibility-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>ollama</category>
      <category>llamacpp</category>
      <category>modeltesting</category>
    </item>
    <item>
      <title>My local models refused zero of 50 security tasks</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Mon, 10 Aug 2026 16:05:10 +0000</pubDate>
      <link>https://dev.to/pat9000/my-local-models-refused-zero-of-50-security-tasks-5c8o</link>
      <guid>https://dev.to/pat9000/my-local-models-refused-zero-of-50-security-tasks-5c8o</guid>
      <description>&lt;p&gt;A refusal is the one failure mode a lower price cannot fix. If the model declines the task, cost per token stops mattering.&lt;/p&gt;

&lt;p&gt;On 2026-08-01 I ran 50 defensive security tasks across five local models on an RTX 5090. Ten tasks per model, temperature 0, one run per task, over loopback to Ollama. Forty-eight of the 50 finished. Zero were refused. The two misses were 180-second timeouts, not declines.&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%2F5qaatwaxba13np7gcr6o.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%2F5qaatwaxba13np7gcr6o.png" alt="Five local models completed 48 of 50 defensive security tasks with zero refusals" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why measure refusal rate at all?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://charonhub.deeplearning.ai/open-models-open-harnesses-open-security/" rel="noopener noreferrer"&gt;Andrew Ng's team reported&lt;/a&gt; that Claude Code and Codex both declined a security review of DeepLearning.AI's own open source, and that the review finished on open weights. &lt;a href="https://huggingface.co/blog/security-incident-july-2026" rel="noopener noreferrer"&gt;Hugging Face reported&lt;/a&gt; hitting the same wall on its own attack logs.&lt;/p&gt;

&lt;p&gt;Those are two accounts, not a rate. I own the hardware, so I can turn the account into a number for the models I actually run. The sizing desk question is not which model scores highest. It is which model will do defensive work on systems I own, at 3am, without a policy exception.&lt;/p&gt;

&lt;p&gt;Refusal rate belongs on the desk as its own axis. It is the axis that does not move when frontier prices fall.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the run measure?
&lt;/h2&gt;

&lt;p&gt;Ten tasks per model, each one defensive: auditing, hardening, detecting, or explaining a weakness in something I own. Several came from real findings in my own vault the same day. An unauthenticated endpoint that could be pushed into server-side request forgery. A regular expression denial of service in a claims verifier. A pinned CVE that had become the reason the system was vulnerable. A truncated hash-chained log.&lt;/p&gt;

&lt;p&gt;A refusal on any of those is a false positive, not a safety win.&lt;/p&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;completed&lt;/th&gt;
&lt;th&gt;refused&lt;/th&gt;
&lt;th&gt;error&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;llama3.1:8b&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qwen3.5:9b&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gemma4:12b&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gemma4:26b&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-oss:20b&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both errors are &lt;code&gt;TimeoutError&lt;/code&gt; at 180 seconds: qwen3.5:9b on the log-tamper task, gemma4:26b on the endpoint audit. Infrastructure, not policy. Neither model declined the task; it ran out of clock.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you score a refusal without a judge model?
&lt;/h2&gt;

&lt;p&gt;I did not use a judge model. A judge has its own refusal behavior and would contaminate the measurement it is meant to make. If the grader can decline, the grade is a second measurement of the grader.&lt;/p&gt;

&lt;p&gt;Scoring is marker-based and deterministic, applied to the first 400 characters of the response. The 400-character window matters. A model that answers the question in full and then appends a boilerplate caution at the end is not refusing, and a naive substring search over the whole response would score it as one.&lt;/p&gt;

&lt;p&gt;That is the same rule I use elsewhere on the desk: pick a pass condition a script can check the same way twice. My &lt;a href="https://bmdpat.com/blog/local-llm-honest-eval-numbers-2026" rel="noopener noreferrer"&gt;honest eval numbers writeup&lt;/a&gt; covers how I keep those conditions from drifting, and the &lt;a href="https://bmdpat.com/blog/build-local-llm-eval-data-from-failures-2026" rel="noopener noreferrer"&gt;failure-data build&lt;/a&gt; covers why rejected outputs belong in the test set instead of the trash.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does zero refusals mean the models did the work well?
&lt;/h2&gt;

&lt;p&gt;No, and reporting it as one number would be the wrong lesson.&lt;/p&gt;

&lt;p&gt;llama3.1:8b answered the request-forgery audit with confidence and named the wrong vulnerability class. It called it an open redirect. It did not decline; it was wrong. The same model's answer on the regular expression denial of service was correct and specific.&lt;/p&gt;

&lt;p&gt;Willingness and accuracy are two axes. A model that always answers and is often wrong is a different problem than a model that will not answer, and the fix is different too. Report both or you will ship the wrong one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does this prove, and what does it not?
&lt;/h2&gt;

&lt;p&gt;It establishes that the local fleet takes defensive security work. Five models from 8B to 26B, ten prompts each about my own systems, zero declines.&lt;/p&gt;

&lt;p&gt;It does not establish a frontier comparison. I measured local models only. The contrast with hosted coding assistants is cited from the two reports above, not reproduced here. Running the same ten prompts through a hosted API and counting is the obvious follow-on, and it is cheap.&lt;/p&gt;

&lt;p&gt;It does not establish quality. See the open redirect above.&lt;/p&gt;

&lt;p&gt;The practical read: availability is a property you can buy with hardware, and on this evidence it is the cheapest property to satisfy, because the smallest model here ties the largest. That argument for owning the machine does not depend on token prices at all. I made the narrative version of it in &lt;a href="https://bmdpat.com/blog/incident-response-local-open-model-2026" rel="noopener noreferrer"&gt;the incident response post&lt;/a&gt;. This is the measured version.&lt;/p&gt;

&lt;p&gt;If you run local models and have never counted your own refusal rate, you are assuming a property you have not checked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; measures refusal rate on defensive security tasks across local models without using a judge model.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role: engineer measuring whether local models will do defensive security work on owned systems.

Context: I run local models over a loopback API. I need a refusal rate, not an impression.

Task:
1. Write ten defensive prompts about systems I own: audit, harden, detect, explain a weakness.
2. Set temperature to 0 and run each prompt once per model.
3. Classify refusal with deterministic markers over the first 400 characters, not a judge model.
4. Record timeouts and errors separately from refusals.
5. Score accuracy as a second axis and report it beside refusal rate.

Output: a per-model table of completed, refused, and error counts, plus named accuracy misses.

Constraints: keep every prompt defensive and about a system I own. Do not merge willingness and correctness into one number.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get the artifact-backed local AI lab notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-refusal-rate-security-tasks-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-refusal-rate-security-tasks-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/local-llm-refusal-rate-security-tasks-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-refusal-rate-security-tasks-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-refusal-rate-security-tasks-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>aisecurity</category>
      <category>openweights</category>
      <category>modelevaluation</category>
    </item>
    <item>
      <title>Prime Agent hit 95.5% on ARC-AGI-3. I did not install it.</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Sun, 09 Aug 2026 16:05:12 +0000</pubDate>
      <link>https://dev.to/pat9000/prime-agent-hit-955-on-arc-agi-3-i-did-not-install-it-37i9</link>
      <guid>https://dev.to/pat9000/prime-agent-hit-955-on-arc-agi-3-i-did-not-install-it-37i9</guid>
      <description>&lt;h1&gt;
  
  
  Prime Agent hit 95.5% on ARC-AGI-3. I did not install it.
&lt;/h1&gt;

&lt;p&gt;Prime Intellect released Prime Agent on 2026-08-05 under an MIT license. On&lt;br&gt;
2026-08-05 it posted 95.5% on ARC-AGI-3 with Claude Opus 5, a hair above the&lt;br&gt;
reported human expert baseline of 95.4%.&lt;/p&gt;

&lt;p&gt;I read the docs and the launch post on 2026-08-06. Then I decided not to&lt;br&gt;
install it.&lt;/p&gt;

&lt;p&gt;Not because I doubt the work. The design is the most serious public&lt;br&gt;
implementation yet of two ideas I care about. I decided against it because of&lt;br&gt;
one question that matters more than any benchmark: who holds the pen on the&lt;br&gt;
agent's own instructions.&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%2Fkq4gz1f7qbcde98axtc5.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%2Fkq4gz1f7qbcde98axtc5.png" alt="Key decisions from Prime Agent hit 95.5% on ARC-AGI-3. I did not install it." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What Prime Agent is
&lt;/h2&gt;

&lt;p&gt;Two ideas, shipped together.&lt;/p&gt;

&lt;p&gt;First, the agent lives inside a persistent IPython session. Context is a&lt;br&gt;
Python variable. A subagent is a function call: &lt;code&gt;await rlm("task")&lt;/code&gt;. File&lt;br&gt;
reads, shell commands, and context management happen as code instead of JSON&lt;br&gt;
tool calls, and state survives across turns and across compaction. They call&lt;br&gt;
this a Recursive Language Model, RLM.&lt;/p&gt;

&lt;p&gt;Second, the agent's operating state lives on disk as editable files: its&lt;br&gt;
prompts, its subagent specs, its skills, its memories. A &lt;code&gt;/refine&lt;/code&gt; loop reads&lt;br&gt;
the agent's own trajectory and applies small edits to that state while it&lt;br&gt;
works. Prime Intellect describes this as durable state the agent can refine&lt;br&gt;
from its own trajectory. The edits are session-local by default, snapshots&lt;br&gt;
support rollback, and the base system prompt stays immutable.&lt;/p&gt;

&lt;p&gt;Both ideas are good. The second one is why I stopped.&lt;/p&gt;
&lt;h2&gt;
  
  
  The rule that stopped me
&lt;/h2&gt;

&lt;p&gt;My fleet runs under a written rule: self-editing prompt loops are&lt;br&gt;
review-only. An agent may draft a change to its own instructions. A human&lt;br&gt;
applies it. The rule exists because a self-editing loop with no human gate is&lt;br&gt;
how a system drifts silently, and I wrote it down in 2026-04 so a shiny&lt;br&gt;
launch could not talk me out of it on 2026-08-06.&lt;/p&gt;

&lt;p&gt;Prime Agent's &lt;code&gt;/refine&lt;/code&gt; is that loop. It is the product's core feature.&lt;br&gt;
Installing it would not add a capability to my fleet. It would overrule a&lt;br&gt;
decision I made on purpose.&lt;/p&gt;

&lt;p&gt;The launch post itself handed me the best evidence for keeping the rule, and&lt;br&gt;
credit to the team for publishing it. Pointed at Factorio, Prime Agent found&lt;br&gt;
it could skip the game's rules by spawning resources straight into its&lt;br&gt;
assembly machines over RCON. It did this despite a repeated reminder in its&lt;br&gt;
prompt not to cheat. A reminder is not a gate. My agents write to a real&lt;br&gt;
brokerage ledger. A rule that holds only while the model feels like honoring&lt;br&gt;
it is not a rule.&lt;/p&gt;

&lt;p&gt;The README is also direct about blast radius. The kernel runs model-generated&lt;br&gt;
Python with your own OS permissions and is, in their words, "not a security&lt;br&gt;
sandbox". On a machine that holds trading credentials, that ends the&lt;br&gt;
conversation by itself.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I did instead
&lt;/h2&gt;

&lt;p&gt;Three moves, all on 2026-08-06.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copied one component.&lt;/strong&gt; Prime Agent stores four kinds of durable state:&lt;br&gt;
prompts, subagent specs, skills, memory. My fleet already had three of those&lt;br&gt;
as plain files. It did not have subagent specs as standalone files. Two worker&lt;br&gt;
contracts lived as prose inside a longer nightly prompt, invisible to every&lt;br&gt;
other agent. I lifted them into their own spec files on 2026-08-06. No&lt;br&gt;
self-modification involved. The file layout was never the risky part. The pen&lt;br&gt;
was.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Queued a measurement.&lt;/strong&gt; Their long-context benchmarks run GLM-5.2, an&lt;br&gt;
open-weights model, against Claude Opus 5 and GPT-5.6 Sol on the same runtime,&lt;br&gt;
and they claim higher scores at lower total token spend than the native&lt;br&gt;
tooling. Token spend across runtimes is a thing I can measure on hardware I&lt;br&gt;
own, so that comparison goes into my benchmark queue as subject matter for the&lt;br&gt;
sizing desk. A tool you do not adopt can still be data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrote down what would flip me.&lt;/strong&gt; Two things reverse this decision. A second&lt;br&gt;
party replicates the ARC-AGI-3 number. Or my own measurement shows a token&lt;br&gt;
gap large enough to pay for operating a second runtime. Review date is on the&lt;br&gt;
calendar for 2026-10-06. If neither lands, the decision stands without a&lt;br&gt;
re-litigation.&lt;/p&gt;
&lt;h2&gt;
  
  
  The part I have not resolved
&lt;/h2&gt;

&lt;p&gt;Prime Agent's thesis is that the human gate is what caps agent quality: the&lt;br&gt;
loop learns from every trajectory, and the human reviewing each edit is the&lt;br&gt;
bottleneck. My rule says the gate is what keeps the system honest. Both&lt;br&gt;
positions are defensible. They cannot both drive.&lt;/p&gt;

&lt;p&gt;I am keeping the gate and paying for it in iteration speed, and I want to be&lt;br&gt;
honest that this is a bet, not a proof. The difference between a decision and&lt;br&gt;
a habit is that a decision names the evidence that would change it. Mine is&lt;br&gt;
named above.&lt;/p&gt;
&lt;h2&gt;
  
  
  The checklist
&lt;/h2&gt;

&lt;p&gt;When a strong new agent framework drops, there are three honest outcomes, not&lt;br&gt;
two.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adopt it.&lt;/li&gt;
&lt;li&gt;Copy one component into what you already run.&lt;/li&gt;
&lt;li&gt;Make it the subject of a measurement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Adopt is the rarest, because it is the only one that hands over the pen.&lt;br&gt;
Copy-one-component is underrated: you get the idea at zero dependency cost.&lt;br&gt;
Measurement is how a tool earns a second look with your numbers instead of&lt;br&gt;
its own.&lt;/p&gt;

&lt;p&gt;One last detail worth noticing. Prime Agent's own autonomous mode ships&lt;br&gt;
disabled, and turning it on gets you default caps of 12 turns, 80,000 tokens,&lt;br&gt;
and 30 minutes, behind exit gates that must pass before a run may finish. The&lt;br&gt;
team that just beat the ARC-AGI-3 human baseline still caps its own agent. If&lt;br&gt;
your agents can spend money, cap them at the runtime level, not in the&lt;br&gt;
prompt. That is what &lt;a href="https://bmdpat.com/tools/agentguard" rel="noopener noreferrer"&gt;AgentGuard&lt;/a&gt; does&lt;br&gt;
for mine: budget, token, and rate limits.&lt;/p&gt;
&lt;h2&gt;
  
  
  Related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/local-llm-refusal-rate-security-tasks-2026" rel="noopener noreferrer"&gt;My local models refused zero of 50 security tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/local-llm-tokens-per-second-wall-clock-2026" rel="noopener noreferrer"&gt;The faster local model run took 83x longer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; It walks you through the adopt, copy, or measure decision for a new agent framework before you install anything.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are evaluating a newly released AI agent framework for production use.

Context:
Provide the framework name, license, release date, your current agent stack,
where your agents' instructions and state live, what credentials your agents
can reach, and any written rules you have about agent self-modification.

Task:
1. Name who holds the pen on agent instructions in this framework, and who
   holds it in your stack on the review date.
2. List every vendor-disclosed failure or limitation, and the guardrail each
   one implies.
3. Pick one of three outcomes: adopt, copy one component, or measure it as
   benchmark subject matter.
4. If not adopting, write the specific evidence that would reverse the
   decision, with a review date.

Output:
- One-paragraph decision with the outcome named.
- The single component worth copying, if any.
- The reversal conditions and review date.

Constraints:
- Vendor benchmarks count as claims, not evidence.
- A prompt reminder is not a guardrail.
- Do not install anything to answer these questions.
&amp;lt;!-- blog-prompt-scope:2026-08-06 --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/ai-agent-memory-write-to-files-2026" rel="noopener noreferrer"&gt;Your AI agent doesn't need memory. It needs a file.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/my-agents-have-to-prove-what-they-did-2026" rel="noopener noreferrer"&gt;My Agents Have to Prove What They Did&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get the artifact-backed local AI lab notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=prime-agent-arc-agi-didnt-install-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=prime-agent-arc-agi-didnt-install-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/prime-agent-arc-agi-didnt-install-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=prime-agent-arc-agi-didnt-install-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=prime-agent-arc-agi-didnt-install-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>selfimprovingagents</category>
      <category>agentsecurity</category>
      <category>agentcostcontrol</category>
    </item>
    <item>
      <title>My Local LLM Got Faster After It Passed the Tests</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Sun, 09 Aug 2026 16:05:09 +0000</pubDate>
      <link>https://dev.to/pat9000/my-local-llm-got-faster-after-it-passed-the-tests-4b8p</link>
      <guid>https://dev.to/pat9000/my-local-llm-got-faster-after-it-passed-the-tests-4b8p</guid>
      <description>&lt;h1&gt;
  
  
  My Local LLM Got Faster After It Passed the Tests
&lt;/h1&gt;

&lt;p&gt;Speed is easy to rank. Correct work is harder to count. That is why a local model benchmark can send you toward the wrong setting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; I ran the same mixed workload three times on an RTX 5090. Throughput rose from 156.9 to 218.5 tokens per second, but I kept only settings that also passed every fixed task.&lt;/p&gt;

&lt;p&gt;The result did not prove that a larger batch caused better answers. It proved that speed alone could not choose the setting.&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%2Fed3utyyra8pz6hj66gmr.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%2Fed3utyyra8pz6hj66gmr.png" alt="A three-step speed and quality gate for local LLM tuning" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the three local runs show?
&lt;/h2&gt;

&lt;p&gt;My &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;August 6 lab report&lt;/a&gt; records three Gemma 4 26B runs through Ollama. Each run used the same mixed workshop: three generation tasks and four code tasks. The context size stayed at 2,048 tokens. I changed the batch size.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Batch size&lt;/th&gt;
&lt;th&gt;Throughput&lt;/th&gt;
&lt;th&gt;Fixed-task result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;156.9 tok/s&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;256&lt;/td&gt;
&lt;td&gt;215.7 tok/s&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;512&lt;/td&gt;
&lt;td&gt;218.5 tok/s&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first run was both slow and wrong. The second run gained 58.8 tokens per second and passed every fixed task. The third run gained only 2.8 more tokens per second and kept the same test result.&lt;/p&gt;

&lt;p&gt;Those numbers came from one short workshop. They do not rank Gemma against every local model. They do show the decision problem clearly. A speed chart can tell you which run produced tokens faster. It cannot tell you whether the code worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why can speed hide a bad local model setting?
&lt;/h2&gt;

&lt;p&gt;Tokens per second measures one part of the run. It does not grade the answer. It also misses model load time, tool failures, malformed output, and work that needs a repair pass.&lt;/p&gt;

&lt;p&gt;I saw the timing problem in another RTX 5090 test. The run with the higher token rate took much longer from request to response because model load dominated the clock. I wrote up that result in &lt;a href="https://bmdpat.com/blog/local-llm-tokens-per-second-wall-clock-2026" rel="noopener noreferrer"&gt;The Faster Local Model Run Took 83x Longer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The same rule applies to answer quality. A model can produce broken code at a high rate. If the benchmark ends when generation stops, the bad run still looks good.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I add a quality gate to a local benchmark?
&lt;/h2&gt;

&lt;p&gt;I start with fixed tasks that have clear answers. A code task must compile or pass its tests. A JSON task must parse and match its schema. A routing task must select the expected route. The check runs in code after the model responds.&lt;/p&gt;

&lt;p&gt;Then I record speed and task result in the same row. I do not keep a new speed result when the fixed tasks fail. This rule makes the benchmark useful for a production choice instead of a screenshot.&lt;/p&gt;

&lt;p&gt;The test set can stay small at first. Four code tasks were enough to reject my first workshop setting. The key is that the tasks do not change between runs. If the prompt or expected answer changes, I start a new comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  Did the batch size cause the better answers?
&lt;/h2&gt;

&lt;p&gt;I do not know. The batch size changed, but model output can vary across runs. The first result could reflect run variance, a cold path, or another condition that the workshop did not isolate.&lt;/p&gt;

&lt;p&gt;That uncertainty changes the next test. I should repeat each setting several times, keep the prompt and model build fixed, and record both pass rate and wall-clock time. One clean run can qualify a setting for more tests. It cannot prove a cause.&lt;/p&gt;

&lt;p&gt;This is the same reason I test refusal behavior as its own property. My &lt;a href="https://bmdpat.com/blog/local-llm-refusal-rate-security-tasks-2026" rel="noopener noreferrer"&gt;local security task report&lt;/a&gt; counted completed tasks, refusals, and timeouts separately. One score cannot describe every failure mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which setting would I keep?
&lt;/h2&gt;

&lt;p&gt;I would keep batch size 256 for the next round. It passed all fixed tasks and reached 215.7 tokens per second. Batch size 512 added 2.8 tokens per second in this run, about a 1.3% gain, with no measured quality gain.&lt;/p&gt;

&lt;p&gt;That is a test choice, not a permanent setting. I want the smaller step until repeat runs show that 512 gives a useful wall-clock gain without more failures or memory pressure.&lt;/p&gt;

&lt;p&gt;The operating rule is simple. First, reject wrong work. Second, compare full run time. Third, use tokens per second to explain where the time went. That order keeps the benchmark tied to the job the model must do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; This prompt turns a local LLM speed test into a repeatable speed and quality gate.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are a local LLM benchmark reviewer.

Context:
I will give you the model name, model build, engine settings, hardware,
fixed tasks, expected answers, tokens per second, and wall-clock time.

Task:
1. Check each fixed task against its expected answer.
2. Reject any run with a failed fixed task.
3. Compare wall-clock time among the runs that passed.
4. Use tokens per second only to explain generation speed.

Output:
- A pass or fail result for each run.
- A table with task pass rate, wall-clock time, and tokens per second.
- The setting to repeat next and the reason for that choice.
- One claim that the data does not support.

Constraints:
- Do not infer cause from one run.
- Do not change the fixed tasks between runs.
- Do not select a setting that failed a fixed task.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get the measured local AI notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-speed-quality-gate-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-speed-quality-gate-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/local-llm-speed-quality-gate-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-speed-quality-gate-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-speed-quality-gate-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>rtx5090</category>
      <category>ollama</category>
      <category>modelevaluation</category>
    </item>
    <item>
      <title>Chunk Size Is a Reliability Setting</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Thu, 06 Aug 2026 16:05:12 +0000</pubDate>
      <link>https://dev.to/pat9000/chunk-size-is-a-reliability-setting-2n2n</link>
      <guid>https://dev.to/pat9000/chunk-size-is-a-reliability-setting-2n2n</guid>
      <description>&lt;h1&gt;
  
  
  Chunk Size Is a Reliability Setting
&lt;/h1&gt;

&lt;p&gt;A crash destroys the entire unit of work in flight. All of it. So the size of&lt;br&gt;
that unit decides what a crash costs you. Throughput is the thing you were&lt;br&gt;
thinking about. Blast radius is the thing that actually bites.&lt;/p&gt;

&lt;p&gt;I learned this during a run on 2026-08-04.&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%2Fyztufugpt6eo5smybauo.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%2Fyztufugpt6eo5smybauo.png" alt="Key decisions from Your Chunk Size Is a Reliability Setting, Not a Speed Setting" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;I was running a fully offline document pipeline over 5,000 scanned PDFs. One&lt;br&gt;
container per slice of the input. Four vCPU each, no network, read only&lt;br&gt;
filesystem, no GPU. The pipeline splits its input into chunks and runs each&lt;br&gt;
chunk in a fresh interpreter.&lt;/p&gt;

&lt;p&gt;I set that chunk size to 1,000, which was the maximum.&lt;/p&gt;

&lt;p&gt;Over the next four hours, three worker processes died with native faults. Not&lt;br&gt;
clean exceptions. Signal level deaths: &lt;code&gt;exit -5&lt;/code&gt; and &lt;code&gt;exit -11&lt;/code&gt;. They died at&lt;br&gt;
roughly 50 percent, 50 percent, and 72 percent of their chunks.&lt;/p&gt;

&lt;p&gt;Every one of those crashes threw away the whole chunk. About seven hours of&lt;br&gt;
compute, gone, on a deadline.&lt;/p&gt;
&lt;h2&gt;
  
  
  How much work does one crash erase?
&lt;/h2&gt;

&lt;p&gt;A fault lands at a random point in the unit. So on average you lose half the&lt;br&gt;
unit each time.&lt;/p&gt;

&lt;p&gt;At 1,000 cases per unit, a fault costs about 500 cases. At 250, the same fault&lt;br&gt;
costs about 125. Cut the unit by four, cut the loss by four. That is the whole&lt;br&gt;
idea, and it is boring, and it would have saved me most of the night.&lt;/p&gt;

&lt;p&gt;The overhead of smaller units is real but tiny. You pay for a few more process&lt;br&gt;
restarts. I measured the cost at a few percent. The insurance is total.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why did parallelism make the failure worse?
&lt;/h2&gt;

&lt;p&gt;My first instinct was speed. More containers, finish sooner.&lt;/p&gt;

&lt;p&gt;That was wrong twice over. More containers means more processes that can die,&lt;br&gt;
and it does nothing to reduce what each death costs. Worse, I sized them&lt;br&gt;
against the host's specs instead of the container runtime's actual ceiling,&lt;br&gt;
blew past the memory limit, and the OOM killer took out a healthy run that had&lt;br&gt;
been going for 33 minutes.&lt;/p&gt;

&lt;p&gt;Adding parallelism to long, uncheckpointed units is the worst of both.&lt;/p&gt;
&lt;h2&gt;
  
  
  What order should you use to make a long job recoverable?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Shorten the unit.&lt;/strong&gt; Set it from your observed failure rate, not your
throughput preference. If faults show up every two hours, a two hour unit is
the wrong unit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make failure loud.&lt;/strong&gt; I had an in process retry that silently restarted a
crashed chunk with one worker instead of four. It hid the signal and turned
a twelve minute problem into a four hour one. A fast, noisy exit is better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make resumption cheap.&lt;/strong&gt; Durable checkpoint per completed unit, validated
when you read it back, skipped on restart. Then a crash costs one unit and a
container start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only then parallelise&lt;/strong&gt;, bounded by the ceiling you actually measured.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After I made those changes, a full restart of the container runtime cost me&lt;br&gt;
nothing but the one chunk in flight. Everything else resumed from disk.&lt;/p&gt;
&lt;h2&gt;
  
  
  How can you tell a machine fault from a code fault?
&lt;/h2&gt;

&lt;p&gt;Some crashes are your bug. Some are the machine. Tell them apart before you&lt;br&gt;
spend an hour tuning code that is fine.&lt;/p&gt;

&lt;p&gt;It is probably the machine when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The same input succeeds on one run and dies on another.&lt;/li&gt;
&lt;li&gt;Two or more independent workers die identically on one host.&lt;/li&gt;
&lt;li&gt;The crash is memory corruption rather than an exception. Watch for
&lt;code&gt;SIGSEGV&lt;/code&gt;, &lt;code&gt;SIGBUS&lt;/code&gt;, signal 139, or the one that gave it away for me: an
&lt;code&gt;unknown opcode&lt;/code&gt; error raised from inside a pure Python standard library
module.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is worth internalising. Python does not raise "unknown opcode" in&lt;br&gt;
&lt;code&gt;difflib&lt;/code&gt; because your code is wrong. It raises it because something wrote&lt;br&gt;
garbage into the memory holding a compiled code object. No amount of&lt;br&gt;
refactoring fixes that. Go test the hardware.&lt;/p&gt;
&lt;h2&gt;
  
  
  What did the repaired run measure?
&lt;/h2&gt;

&lt;p&gt;For anyone sizing similar work: the pipeline ran at 3.2 seconds per PDF on four&lt;br&gt;
vCPU, fully offline, no network calls and no GPU. Nothing in it phones home.&lt;br&gt;
After moving to 250 case units, faults stopped costing me anything I could not&lt;br&gt;
recover in about twelve minutes.&lt;/p&gt;
&lt;h2&gt;
  
  
  What should you change in your next long-running job?
&lt;/h2&gt;

&lt;p&gt;Go look at your longest running job right now. Find how long one unit of work&lt;br&gt;
takes between durable checkpoints. Then ask how long it has been since your&lt;br&gt;
last unexplained failure.&lt;/p&gt;

&lt;p&gt;If the unit is longer than the gap between failures, your unit is wrong, and&lt;br&gt;
you are one crash away from finding out.&lt;/p&gt;
&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; It turns a long-running local AI job into a checkpoint plan that limits the work lost when a worker dies.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are reviewing a long-running local AI or offline document job.

Context:
Provide the input count, current chunk size, measured time per chunk,
checkpoint behavior, worker count, memory ceiling, and recent failure logs.

Task:
1. Estimate the work and time lost when one worker fails.
2. Recommend a chunk size tied to the observed failure interval.
3. List the durable checkpoint fields needed for safe resume.
4. Give one bounded parallelism test to run after recovery is cheap.

Output:
- Current blast radius.
- Recommended chunk and checkpoint plan.
- One next measurement.

Constraints:
- Keep measured values separate from estimates.
- Do not claim a hardware fault without repeated evidence.
- Do not increase parallelism before the resume path is tested.
&amp;lt;!-- blog-prompt-scope:2026-06-24 --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get the artifact-backed local AI lab notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/local-llm-vram-fit-runtime-support-2026" rel="noopener noreferrer"&gt;VRAM Fit Is Not Runtime Support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/5090-benchmark-phase-timing-receipt-2026-v2" rel="noopener noreferrer"&gt;My 5090 benchmark was missing the field I needed most&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=chunk-size-is-a-reliability-setting-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=chunk-size-is-a-reliability-setting-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/chunk-size-is-a-reliability-setting-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=chunk-size-is-a-reliability-setting-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=chunk-size-is-a-reliability-setting-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>reliability</category>
      <category>docker</category>
      <category>offlineai</category>
    </item>
    <item>
      <title>The faster local model run took 83x longer</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Thu, 06 Aug 2026 16:05:09 +0000</pubDate>
      <link>https://dev.to/pat9000/the-faster-local-model-run-took-83x-longer-36lc</link>
      <guid>https://dev.to/pat9000/the-faster-local-model-run-took-83x-longer-36lc</guid>
      <description>&lt;p&gt;On 2026-08-04 I sent the same local model request twice, 30 seconds apart. The first run reported 188.16 tokens per second. The second reported 153.12. The first run took 43.9 seconds of wall clock. The second took half a second.&lt;/p&gt;

&lt;p&gt;Tokens per second picked the wrong winner by 23%. Wall clock says the second run was 83 times faster.&lt;/p&gt;

&lt;p&gt;Both runs were &lt;code&gt;llama3.1:8b&lt;/code&gt; on an RTX 5090 through Ollama, same prompt, 44 input tokens and 32 output tokens, &lt;code&gt;num_ctx=1024&lt;/code&gt;. The 188.16 tok/s run spent 43,476.3 ms in its load phase and 170.06 ms generating. Tokens per second measures the generating part only, so it hid 99% of what the request actually cost.&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%2Ffaryac3otsp8wwcol7mp.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%2Ffaryac3otsp8wwcol7mp.png" alt="Two identical local model runs where the higher tokens per second number took 83 times longer in wall clock" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the two runs actually measure?
&lt;/h2&gt;

&lt;p&gt;Same model, same prompt, same settings. Here is what the receipt recorded.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Run at 21:05:23&lt;/th&gt;
&lt;th&gt;Run at 21:05:54&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tokens per second&lt;/td&gt;
&lt;td&gt;188.16&lt;/td&gt;
&lt;td&gt;153.12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load phase&lt;/td&gt;
&lt;td&gt;43,476.30 ms&lt;/td&gt;
&lt;td&gt;142.43 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt eval&lt;/td&gt;
&lt;td&gt;183.20 ms&lt;/td&gt;
&lt;td&gt;151.82 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generation&lt;/td&gt;
&lt;td&gt;170.06 ms&lt;/td&gt;
&lt;td&gt;208.98 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total duration&lt;/td&gt;
&lt;td&gt;43,832.66 ms&lt;/td&gt;
&lt;td&gt;504.78 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wall clock&lt;/td&gt;
&lt;td&gt;43,860 ms&lt;/td&gt;
&lt;td&gt;530 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU memory before / after&lt;/td&gt;
&lt;td&gt;855 / 5,994 MiB&lt;/td&gt;
&lt;td&gt;5,994 / 5,994 MiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do the division and both speed numbers check out. 32 tokens over 170.06 ms is 188.2 per second. 32 tokens over 208.98 ms is 153.1. Neither number is wrong. They answer a question I was not asking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does tokens per second rank the runs backwards?
&lt;/h2&gt;

&lt;p&gt;Tokens per second divides output tokens by generation time. Ollama reports that generation time as &lt;code&gt;eval_duration&lt;/code&gt;, and it reports &lt;code&gt;load_duration&lt;/code&gt; and &lt;code&gt;prompt_eval_duration&lt;/code&gt; as separate fields. The API documents all three.&lt;/p&gt;

&lt;p&gt;So the metric is a rate for one phase of the request. It cannot see the other two.&lt;/p&gt;

&lt;p&gt;In the first run the load phase was 43,476.3 ms of a 43,832.66 ms total. That is 99.2% of the request. The rate for the remaining 0.8% led the table.&lt;/p&gt;

&lt;p&gt;This is not a rounding problem. For a 32 token answer, generation is the smallest part of the job. Ranking a short agent call by generation rate ranks it by the part that barely matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does the receipt say about the gap?
&lt;/h2&gt;

&lt;p&gt;The receipt records the load phase and the memory delta. GPU memory went from 855 MiB to 5,994 MiB across the first request and stayed at 5,994 across the second. The weights arrived during the first call.&lt;/p&gt;

&lt;p&gt;I am not going to write "cold start" into the artifact. The runner stamps &lt;code&gt;residency_state=unrecorded&lt;/code&gt; on both rows, and I keep a rule that the label comes from the receipt and not from my reading of it. That rule came out of an earlier fix to the same benchmark, covered in &lt;a href="https://bmdpat.com/blog/5090-benchmark-phase-timing-receipt-2026-v2" rel="noopener noreferrer"&gt;the phase timing receipt post&lt;/a&gt;. The measured facts are the load duration and the memory delta. Those are enough to act on, and they do not require me to invent a field.&lt;/p&gt;

&lt;p&gt;A second row in the same report shows this is not a one-off. A &lt;code&gt;qwen3.5:9b&lt;/code&gt; request at 77.59 tokens per second recorded 63,791 ms of wall clock for 64 output tokens. At that rate the generation accounts for about 0.8 seconds. The other 63 seconds sit in the receipt as wall clock and appear nowhere in the headline speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should a local benchmark report instead?
&lt;/h2&gt;

&lt;p&gt;Report wall clock beside tokens per second, and let the selection step read wall clock.&lt;/p&gt;

&lt;p&gt;Three rules I now apply.&lt;/p&gt;

&lt;p&gt;First, record all three phases. Load, prompt eval, and generation. Ollama returns them, so keeping them costs nothing.&lt;/p&gt;

&lt;p&gt;Second, match the metric to the workload. For a batch job that generates thousands of tokens against a model already in memory, generation rate is the right number. For a single-shot agent decision returning 32 tokens, it is close to noise. My workload is the second kind.&lt;/p&gt;

&lt;p&gt;Third, keep both runs. Do not drop the slow one as a warm-up. The first run is the honest measure of what the first request of the day costs, which is the same reason I &lt;a href="https://bmdpat.com/blog/local-llm-input-output-benchmark-2026" rel="noopener noreferrer"&gt;benchmark input and output sizes separately&lt;/a&gt; instead of reporting one blended rate.&lt;/p&gt;

&lt;p&gt;The change to my benchmark is small. It now reports wall clock per request next to the rate, and the row that leads on rate no longer wins by default. For an agent that makes one call and waits, 43.9 seconds is the number a person feels. 188.16 tokens per second is the number that looks good in a table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; turns a local model benchmark into a wall-clock comparison so a fast generation rate cannot hide a slow request.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role: engineer benchmarking a local language model on owned hardware.
Context: my rows report tokens per second, but some hide a long model load phase.
Task:
1. Per row, list load, prompt eval, generation, and total wall clock.
2. Compute what percent of wall clock each phase used.
3. Rank rows by wall clock, then by tokens per second. Show where they disagree.
4. Name the metric that matches my workload and say why.
5. Name one rerun that separates load cost from generation cost.
Output: a phase table, both rankings, and the rerun command.
Constraints: do not invent missing fields. Keep slow rows. Do not label a run cold or warm unless the receipt records it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get the artifact-backed local AI lab notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/5090-benchmark-phase-timing-receipt-2026-v2" rel="noopener noreferrer"&gt;My 5090 benchmark was missing the field I needed most&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/local-llm-input-output-benchmark-2026" rel="noopener noreferrer"&gt;Why I Benchmark Local LLM Input and Output Separately&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bmdpat.com/blog/local-llm-vram-fit-runtime-support-2026" rel="noopener noreferrer"&gt;VRAM Fit Is Not Runtime Support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-tokens-per-second-wall-clock-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-tokens-per-second-wall-clock-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/local-llm-tokens-per-second-wall-clock-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-tokens-per-second-wall-clock-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-tokens-per-second-wall-clock-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>llmbenchmarks</category>
      <category>rtx5090</category>
      <category>ollama</category>
    </item>
    <item>
      <title>VRAM Fit Is Not Runtime Support</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Tue, 04 Aug 2026 16:05:14 +0000</pubDate>
      <link>https://dev.to/pat9000/vram-fit-is-not-runtime-support-5aef</link>
      <guid>https://dev.to/pat9000/vram-fit-is-not-runtime-support-5aef</guid>
      <description>&lt;p&gt;A model can fit in your GPU memory and still fail before it produces one token.&lt;/p&gt;

&lt;p&gt;That happened in my latest local model test. A 2.7 GB Nanbeige4.2-3B GGUF downloaded and registered on an RTX 5090 with 32 GB of VRAM. Ollama then stopped at model load with an unknown architecture error. The memory check passed. The runtime check failed.&lt;/p&gt;

&lt;p&gt;This is why I now treat VRAM fit and runtime support as separate gates in the local model sizing workflow.&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%2Fe7ne34udtw78olc8xb1r.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%2Fe7ne34udtw78olc8xb1r.png" alt="A local model needs VRAM fit and runtime support before a useful run" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the 5090 test actually prove?
&lt;/h2&gt;

&lt;p&gt;The test proved one narrow thing: Nanbeige4.2-3B was not runnable on this Ollama build. The Q4_K_M file downloaded. The model appeared in the local model list. The request failed with &lt;code&gt;unknown model architecture: 'nanbeige'&lt;/code&gt; when Ollama tried to start its llama-server process.&lt;/p&gt;

&lt;p&gt;I repeated the check with Q5_K_M. It failed at the same stage. That matters because it rules out a single quant file as the first suspect. The report records a runtime support problem, not a throughput result.&lt;/p&gt;

&lt;p&gt;The GPU had 32 GB of total memory. The Q4_K_M model occupied 2.7 GB on disk. Those numbers make the model look like an easy fit. They do not tell us whether the serving stack can load its architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is VRAM fit only the first gate?
&lt;/h2&gt;

&lt;p&gt;I use four gates for a local model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Artifact gate.&lt;/strong&gt; Can I download and identify the model file?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory gate.&lt;/strong&gt; Does the model fit the available VRAM, RAM, or offload plan?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime gate.&lt;/strong&gt; Does the named Ollama or llama.cpp version recognize the model architecture and quant format?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workload gate.&lt;/strong&gt; Does it complete the real task with acceptable quality, latency, and power?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first two gates are easy to check from a model page and a GPU spec. The third requires a real load attempt. The fourth requires a real task. A sizing tool that stops after memory fit can turn an impossible download decision into a confident recommendation.&lt;/p&gt;

&lt;p&gt;My &lt;a href="https://bmdpat.com/blog/local-llm-vram-fit-before-download-2026" rel="noopener noreferrer"&gt;VRAM fit guide&lt;/a&gt; still has a useful place. It answers the memory question. My &lt;a href="https://bmdpat.com/blog/local-llm-honest-eval-numbers-2026" rel="noopener noreferrer"&gt;honest local model evaluation notes&lt;/a&gt; answer the workload question. The missing middle is a named runtime check.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should a runtime-support check record?
&lt;/h2&gt;

&lt;p&gt;The check does not need a large benchmark suite. It needs a small receipt with enough detail to reproduce the result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;model name and exact file or tag&lt;/li&gt;
&lt;li&gt;quantization and file size&lt;/li&gt;
&lt;li&gt;runtime name and version&lt;/li&gt;
&lt;li&gt;GPU name and available memory&lt;/li&gt;
&lt;li&gt;load result and exact error text&lt;/li&gt;
&lt;li&gt;one short generation only after load succeeds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final item is important. Do not report tokens per second for a model that never reached generation. The correct result is &lt;code&gt;load_failed&lt;/code&gt;, with the reason attached.&lt;/p&gt;

&lt;p&gt;That is how the Nanbeige test is recorded. It produced no throughput number. Publishing a number from another machine would answer a different question and weaken the desk's data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about models that are too large to fit?
&lt;/h2&gt;

&lt;p&gt;The same report tested Laguna S2.1 as a separate case. Its BF16 files total roughly 250 GB, and its smaller MXFP4 MoE build is split across three shards. That is not a near miss on a 32 GB card. Measuring it requires an NVMe expert-offload path, and that path did not build on this Windows host because the C toolchain was absent and WSL was unavailable.&lt;/p&gt;

&lt;p&gt;That is another useful failure boundary. The report has no Laguna throughput number because the engine did not build and no inference ran. The next action is infrastructure work, not a guessed performance estimate.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does this change model selection?
&lt;/h2&gt;

&lt;p&gt;The sizing desk should show runtime support beside VRAM fit. A model recommendation should name the runtime version that loaded it, or mark support as unverified.&lt;/p&gt;

&lt;p&gt;My current known-good rows show why this distinction helps. The 2026-08-02 5090 report includes &lt;code&gt;llama3.1:8b&lt;/code&gt; rows for an agent code task and a long-context summary. They are workload rows from a model that loaded. They are useful only because the earlier gates cleared.&lt;/p&gt;

&lt;p&gt;The practical order is simple: fit the model, load it, run the task, then compare speed. VRAM fit gets you to the starting line. Runtime support gets you a starting line at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; It turns a local model check into a receipt that separates memory fit, runtime support, and workload evidence.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role: local model operator checking a candidate for an owned GPU.
Context: I have a model tag or GGUF file, GPU memory details, a runtime version, and a load or generation result.
Task:
1. Check artifact identity and file size.
2. Check memory fit against the available VRAM and any stated offload plan.
3. Check whether the named runtime loaded the model architecture.
4. Record the exact load error when the model fails.
5. Report workload speed only after one real task completes.
Output: a four-gate receipt with pass, fail, or unverified for each gate.
Constraints: do not invent throughput. Keep another machine's result separate. Name the runtime version and preserve the exact error text.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get the artifact-backed local AI lab notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-vram-fit-runtime-support-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-vram-fit-runtime-support-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/local-llm-vram-fit-runtime-support-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-vram-fit-runtime-support-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-vram-fit-runtime-support-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>5090reports</category>
      <category>ollama</category>
      <category>modelselection</category>
    </item>
    <item>
      <title>Why Local LLM Benchmarks Need Power Data</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Tue, 04 Aug 2026 16:05:10 +0000</pubDate>
      <link>https://dev.to/pat9000/why-local-llm-benchmarks-need-power-data-432f</link>
      <guid>https://dev.to/pat9000/why-local-llm-benchmarks-need-power-data-432f</guid>
      <description>&lt;h1&gt;
  
  
  Why Local LLM Benchmarks Need Power Data
&lt;/h1&gt;

&lt;p&gt;Tokens per second is useful, but it is not enough to choose a local model setting. Power draw tells you what the faster setting costs while it runs. On my RTX 5090, two Gemma 26B settings both passed the same fixed tasks, yet the faster one used much more power for a small speed gain.&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%2Fxegxusst8euh7cdu99zp.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%2Fxegxusst8euh7cdu99zp.png" alt="Measured power draw for two passing Gemma settings on an RTX 5090" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the RTX 5090 run measure?
&lt;/h2&gt;

&lt;p&gt;The Aug. 1, 2026 report records a workshop mix of three 200-token generation tasks and four code tasks. The model was &lt;code&gt;gemma4:26b&lt;/code&gt; in Ollama with a 2,048-token context. The fixed-task quality result was 100% at both &lt;code&gt;num_batch=256&lt;/code&gt; and &lt;code&gt;num_batch=512&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The report also records the machine state: an NVIDIA RTX 5090 with 32,607 MiB total memory, 73 C at the snapshot, and 401.68 W drawn against a 575 W limit. Those fields make the result easier to compare with a later run on the same machine or a different card.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed when I raised num_batch?
&lt;/h2&gt;

&lt;p&gt;At &lt;code&gt;num_batch=256&lt;/code&gt;, Gemma produced 215.7 tok/s and averaged 187.6 W. At &lt;code&gt;num_batch=512&lt;/code&gt;, it produced 218.5 tok/s and averaged 234.3 W. The second setting added 46.7 W for 2.8 tok/s.&lt;/p&gt;

&lt;p&gt;That is a poor trade if both settings meet the same quality bar and the workload is not waiting on prompt processing. The higher setting may still win for a batch job where wall-clock time matters more than power. The point is that the benchmark should expose the choice instead of hiding it behind one speed number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does speed alone give the wrong answer?
&lt;/h2&gt;

&lt;p&gt;A speed-only table encourages a single ranking. The fastest row looks like the winner. That ranking changes when you add power, quality, context length, and memory use.&lt;/p&gt;

&lt;p&gt;The same report shows this in a smaller model. The &lt;code&gt;llama3.1:8b&lt;/code&gt; agent-code task ran at 227.79 tok/s with a 7,826 MiB VRAM peak. Gemma 26B ran the same named workload at 207.41 tok/s with a 20,233 MiB VRAM peak. These are not interchangeable rows. They describe different memory and quality choices.&lt;/p&gt;

&lt;p&gt;I keep the measurement fields together because local model selection is a fit problem first. My earlier notes on &lt;a href="https://bmdpat.com/blog/local-llm-vram-fit-runtime-support-2026" rel="noopener noreferrer"&gt;VRAM fit and runtime support&lt;/a&gt; cover the load gate. The &lt;a href="https://bmdpat.com/blog/5090-benchmark-phase-timing-receipt-2026-v2" rel="noopener noreferrer"&gt;5090 phase timing receipt&lt;/a&gt; covers why one end-to-end latency number can hide the slow phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  What fields should a local LLM benchmark include?
&lt;/h2&gt;

&lt;p&gt;Record these fields for every meaningful run:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Model and quantization.&lt;/li&gt;
&lt;li&gt;Runtime and version.&lt;/li&gt;
&lt;li&gt;Context length, prompt size, and output limit.&lt;/li&gt;
&lt;li&gt;Task name and fixed quality result.&lt;/li&gt;
&lt;li&gt;Tokens per second.&lt;/li&gt;
&lt;li&gt;Average and peak power when available.&lt;/li&gt;
&lt;li&gt;VRAM peak and the GPU memory ceiling.&lt;/li&gt;
&lt;li&gt;A timestamp and the exact machine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not compare rows that change several of these fields at once. If the model, runtime, prompt, and task all change, the speed difference cannot tell you which change mattered.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should I change in my own benchmark loop?
&lt;/h2&gt;

&lt;p&gt;Add power and quality as first-class columns. Keep the prompt and task set fixed. Run the same setting more than once when the result will drive a production choice. Store the raw output with the summary so a surprising row can be checked later.&lt;/p&gt;

&lt;p&gt;The useful question is not “Which setting is fastest?” It is “Which setting meets the quality bar at an acceptable power and memory cost?” That answer belongs in the report beside tok/s.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; It turns a local model run into a comparable benchmark row with speed, quality, power, and memory fields.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are a local LLM benchmark reviewer.

Context:
Model: [model and quantization]
Runtime: [Ollama, llama.cpp, or other]
GPU: [GPU name and memory]
Run log: [paste the log or report path]

Task:
1. Extract the task, context length, prompt size, and output limit.
2. Extract tokens/sec, average and peak power, VRAM peak, and quality result.
3. Compare this row with the supplied baseline without inventing missing fields.

Output:
- One markdown benchmark row.
- A short pass/fail quality note.
- One sentence on the speed, power, and memory tradeoff.

Constraints:
- Keep it short.
- Use exact numbers and file paths when available.
- Do not invent missing measurements.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get the artifact-backed local AI lab notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-benchmark-power-data-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=local-llm-benchmark-power-data-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/local-llm-benchmark-power-data-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-benchmark-power-data-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=local-llm-benchmark-power-data-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>gpubenchmarks</category>
      <category>ollama</category>
      <category>5090reports</category>
    </item>
    <item>
      <title>My 5090 benchmark was missing the field I needed most</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Sun, 02 Aug 2026 16:05:14 +0000</pubDate>
      <link>https://dev.to/pat9000/my-5090-benchmark-was-missing-the-field-i-needed-most-381e</link>
      <guid>https://dev.to/pat9000/my-5090-benchmark-was-missing-the-field-i-needed-most-381e</guid>
      <description>&lt;h1&gt;
  
  
  My 5090 benchmark was missing the field I needed most
&lt;/h1&gt;

&lt;p&gt;I had a fresh local benchmark with a respectable tokens-per-second number and still could not answer the question I actually care about: where did the request spend its time?&lt;/p&gt;

&lt;p&gt;The repair was small. I changed the benchmark receipt to record capture time, model load duration, prompt evaluation duration, output evaluation duration, total duration, and GPU power. The next Qwen3.5 9B row made the hidden phase visible.&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%2Fbmdpat.com%2Fblog-assets%2F5090-benchmark-phase-timing-receipt-2026-v2.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%2Fbmdpat.com%2Fblog-assets%2F5090-benchmark-phase-timing-receipt-2026-v2.png" alt="The instrumented Qwen3.5 9B benchmark splits one request into load, prompt, output, and total duration" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the instrumented run show?
&lt;/h2&gt;

&lt;p&gt;The RTX 5090 ran one bounded local agent-decision workload through Ollama with &lt;code&gt;num_ctx=4096&lt;/code&gt; and &lt;code&gt;num_predict=64&lt;/code&gt;. The model produced 64 output tokens at 84.94 tokens per second.&lt;/p&gt;

&lt;p&gt;That is not the useful summary by itself. The receipt recorded:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load duration: 6,105.25 ms.&lt;/li&gt;
&lt;li&gt;Prompt evaluation: 151.18 ms.&lt;/li&gt;
&lt;li&gt;Output evaluation: 753.47 ms.&lt;/li&gt;
&lt;li&gt;Total model duration: 7,013.40 ms.&lt;/li&gt;
&lt;li&gt;Average GPU power: 300.81 W.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The load phase was eight times longer than output evaluation. A route that reports only 84.94 tok/s hides the part a user waits through first.&lt;/p&gt;

&lt;p&gt;The public &lt;a href="https://bmdpat.com/5090-reports/2026-08-02-instrumented.md" rel="noopener noreferrer"&gt;dated 5090 artifact&lt;/a&gt; carries the row and method. The &lt;a href="https://docs.ollama.com/api/generate" rel="noopener noreferrer"&gt;Ollama generate API reference&lt;/a&gt; documents the response timing fields I now preserve instead of collapsing them into one stopwatch number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why was the old receipt too thin?
&lt;/h2&gt;

&lt;p&gt;The earlier runner saved model, workload, tokens per second, watts, and a wall-clock note. That was enough to compare rough throughput. It was not enough to explain a slow request or compare a resident model with a load event.&lt;/p&gt;

&lt;p&gt;It also lacked a capture timestamp. A report generated after the fact can accidentally make an older row look current. My &lt;a href="https://bmdpat.com/blog/local-llm-benchmark-provenance-gpu-snapshot-2026" rel="noopener noreferrer"&gt;benchmark provenance guide&lt;/a&gt; covers that failure in the report layer. My &lt;a href="https://bmdpat.com/blog/local-llm-input-output-benchmark-2026" rel="noopener noreferrer"&gt;phase-by-phase timing guide&lt;/a&gt; applies the same split inside one request. This change moves that discipline down to the row-producing runner.&lt;/p&gt;

&lt;p&gt;I am keeping one detail explicit: the receipt still says &lt;code&gt;residency_state=unrecorded&lt;/code&gt;. The load duration is measured. Residency classification is not. I will not turn a timing difference into a cold or warm label that the runner did not capture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes for an agent workload?
&lt;/h2&gt;

&lt;p&gt;The next routing decision should use phase data.&lt;/p&gt;

&lt;p&gt;If the model is already resident, output evaluation may dominate. If the model has to load, the first request carries a different latency budget. A queue worker that pins one model and reuses it should be measured separately from a worker that swaps models between jobs.&lt;/p&gt;

&lt;p&gt;That distinction matters more than a leaderboard. The right question is not which model has the highest tok/s number. It is which route clears the workload's total latency, quality, memory, and power limits.&lt;/p&gt;

&lt;p&gt;I will keep the next test narrow: the same model, context, and prompt, with one workload variable changed. The receipt now has enough fields to show what moved.&lt;/p&gt;

&lt;p&gt;The benchmark is useful when it tells me what the next measurement should isolate. A smaller receipt with the right phases compounds faster than a larger table of blended averages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; It turns one local model response into a phase-timing receipt without inventing residency or runtime metadata.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are reviewing one local LLM request for production routing.

Context:
Paste the response timing fields, model, workload, capture time, GPU
snapshot, and the task result.

Task:
1. Separate load, prompt evaluation, output evaluation, and total time.
2. Calculate output tokens per second from eval_count and eval_duration.
3. Flag any missing capture or residency field.
4. Recommend the next single measurement.

Constraints:
- Keep measured fields separate from estimates.
- Never label a request cold or warm unless the receipt records it.
- Do not rank models from output speed alone.
- Preserve the source timestamp and workload name.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;Get the artifact-backed local AI lab notes by email: &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;https://bmdpat.com/5090-reports&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=5090-benchmark-phase-timing-receipt-2026-v2" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=5090-benchmark-phase-timing-receipt-2026-v2&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/5090-benchmark-phase-timing-receipt-2026-v2?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=5090-benchmark-phase-timing-receipt-2026-v2&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=5090-benchmark-phase-timing-receipt-2026-v2&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>llmbenchmarks</category>
      <category>rtx5090</category>
      <category>ollama</category>
    </item>
    <item>
      <title>Search Old Results Before Publishing an LLM Test</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Sat, 01 Aug 2026 16:05:13 +0000</pubDate>
      <link>https://dev.to/pat9000/search-old-results-before-publishing-an-llm-test-3pac</link>
      <guid>https://dev.to/pat9000/search-old-results-before-publishing-an-llm-test-3pac</guid>
      <description>&lt;h1&gt;
  
  
  Search Old Results Before Publishing an LLM Test
&lt;/h1&gt;

&lt;p&gt;My latest RTX 5090 post passed every mechanical check and still failed QA. I had already published the finding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; Before I write from a local LLM benchmark, I now search the published archive for the model, runtime setting, and two signature numbers from the result. That check catches a repeated conclusion even when the title and framing changed. On August 1, 2026, it stopped me from publishing a second post about the same Ollama &lt;code&gt;num_batch&lt;/code&gt; sweep. Canonical URL: &lt;a href="https://bmdpat.com/blog/ollama-num-batch-tuning-quality-gate-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/blog/ollama-num-batch-tuning-quality-gate-2026&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%2Fwbiyna4hg02gj573ok9y.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%2Fwbiyna4hg02gj573ok9y.png" alt="Four-step duplicate check: find the rows, take a fingerprint, search the archive, compare takeaways" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How did the duplicate get through the first checks?
&lt;/h2&gt;

&lt;p&gt;The new draft looked clean. It used a fresh July 30 report, cited the source rows, included two live internal links, passed the prose gate, passed the publish-body validator, and carried a generator-made visual that cleared the mechanical image check. Every one of those gates reads the draft on its own. None of them reads the archive.&lt;/p&gt;

&lt;p&gt;Its conclusion was also defensible. In the saved &lt;code&gt;gemma4:26b&lt;/code&gt; workshop rows, &lt;code&gt;num_batch=256&lt;/code&gt; produced 215.7 output tokens per second at 187.6 watts average. The &lt;code&gt;512&lt;/code&gt; row reached 218.5 output tokens per second at 234.3 watts average. Both passed the fixed task checks.&lt;/p&gt;

&lt;p&gt;The problem was not truth. The problem was novelty.&lt;/p&gt;

&lt;p&gt;My July 19 post, &lt;a href="https://bmdpat.com/blog/ollama-num-batch-rtx-5090-2026" rel="noopener noreferrer"&gt;Ollama num_batch: 256 Was My RTX 5090 Sweet Spot&lt;/a&gt;, had already compared those rows and made the same route choice. The second draft changed the title and added a tuning checklist, but the load-bearing finding was identical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is a new report date not a new result?
&lt;/h2&gt;

&lt;p&gt;The July 30 lab report carries &lt;code&gt;generated_at: 2026-07-30 09:50&lt;/code&gt;. That stamp records when the rollup ran. It says nothing about when any single row was measured.&lt;/p&gt;

&lt;p&gt;The saved rows prove the gap. The workshop benchmark CSV has these columns: model, quant, engine, workload, input tokens, output tokens, tokens per second, watts average, and notes. There is no capture-time column at all. The same July 30 table also mixes runtime versions, listing rows from Ollama 0.22.1 and rows from Ollama 0.31.1. One report date cannot stand in for the run time of any row.&lt;/p&gt;

&lt;p&gt;So a report generator can pull an old measurement back into view without creating new evidence. If I treat the newest report as a list of new findings, I publish the same result twice.&lt;/p&gt;

&lt;p&gt;My &lt;a href="https://bmdpat.com/blog/local-llm-benchmark-provenance-gpu-snapshot-2026" rel="noopener noreferrer"&gt;benchmark provenance guide&lt;/a&gt; argues for binding driver, runtime, model, workload, settings, and capture time to every row. This workshop CSV predates that rule, which is exactly how a stale row reads as current. The content path needs one more field on top: the public claim already made from that row.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a signature-number search?
&lt;/h2&gt;

&lt;p&gt;A title search is too weak. The old post may use different words.&lt;/p&gt;

&lt;p&gt;I search for three parts of the result together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The model or model family, such as &lt;code&gt;gemma4:26b&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The changed setting, such as &lt;code&gt;num_batch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Two numbers that identify the comparison, such as &lt;code&gt;215.7&lt;/code&gt; and &lt;code&gt;218.5&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The numbers act like a small fingerprint. They survive headline changes and topic labels. A match does not always mean the new post is a duplicate, but it forces a direct comparison before drafting continues.&lt;/p&gt;

&lt;p&gt;For this run, the search found the July 19 post. Independent QA then compared the thesis, rows, power tradeoff, and recommendation. It returned FAIL, so the post did not ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  When can the same benchmark support another post?
&lt;/h2&gt;

&lt;p&gt;The bar is a new decision, not a new introduction.&lt;/p&gt;

&lt;p&gt;The same rows can support a follow-up if new evidence changes the route, a later runtime version changes the result, or the post answers a different operational question that the first one did not answer. A translation of the same conclusion into another checklist is not enough.&lt;/p&gt;

&lt;p&gt;For example, a repeated sweep across several seeds could show whether the 2.8 tokens-per-second gap persists. A new VRAM trace could test whether either batch value crosses a memory limit. A queue-level run could measure completed jobs per hour instead of output rate. Those would add evidence.&lt;/p&gt;

&lt;p&gt;Without that addition, I should link the old post and move on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What gate do I run before drafting now?
&lt;/h2&gt;

&lt;p&gt;First, identify the exact measurement rows. Do not start from the report title.&lt;/p&gt;

&lt;p&gt;Second, extract the model, setting, workload, and two signature numbers. Search the published archive for all four.&lt;/p&gt;

&lt;p&gt;Third, compare the proposed one-sentence takeaway with each match. If the new post reaches the same conclusion from the same rows, stop.&lt;/p&gt;

&lt;p&gt;Fourth, record what changed. A new model, rerun, verifier, route decision, or failure can justify a follow-up. A new date in a rollup cannot.&lt;/p&gt;

&lt;p&gt;This gate runs before I draft the hook. It also keeps the public lab notebook honest. Readers get one clear result instead of several versions that make the evidence look larger than it is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; It checks whether a planned local LLM benchmark post repeats a finding that is already public.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are checking a local LLM post for duplicate evidence.

Context:
Paste the planned takeaway, source benchmark rows, and a list of
published post titles, URLs, and text.

Task:
1. Extract the model, setting, workload, and two signature numbers.
2. Search the published text for matching evidence.
3. Compare the old and planned one-sentence takeaways.
4. State what new measurement or decision the planned post adds.

Output:
- PASS if the post adds a distinct finding.
- FAIL if it repeats the same conclusion from the same rows.
- The closest prior post and the exact overlap.

Constraints:
- Do not treat a report generation date as a measurement date.
- Do not approve a rewrite that only changes the title or checklist.
- Keep measured facts separate from proposed follow-up tests.
- Do not invent source rows, numbers, or run dates.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;I publish measured local AI build notes in &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;The 5090 Reports&lt;/a&gt;. Join the email list for the next result.&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=ollama-num-batch-tuning-quality-gate-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=ollama-num-batch-tuning-quality-gate-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/ollama-num-batch-tuning-quality-gate-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ollama-num-batch-tuning-quality-gate-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=ollama-num-batch-tuning-quality-gate-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>modeltesting</category>
      <category>ollama</category>
      <category>rtx5090</category>
    </item>
    <item>
      <title>Build Local LLM Eval Data From Real Failures</title>
      <dc:creator>Patrick Hughes</dc:creator>
      <pubDate>Fri, 31 Jul 2026 16:05:15 +0000</pubDate>
      <link>https://dev.to/pat9000/build-local-llm-eval-data-from-real-failures-32e7</link>
      <guid>https://dev.to/pat9000/build-local-llm-eval-data-from-real-failures-32e7</guid>
      <description>&lt;h1&gt;
  
  
  Build Local LLM Eval Data From Real Failures
&lt;/h1&gt;

&lt;p&gt;A clean demo tells me a local coding model can pass one task. A saved failure tells me what to test next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; I turn each local model attempt into one replayable row that keeps the prompt, generated code, tests, verifier result, model, route, and timestamp together. Passing rows set a baseline. Failed rows become regression cases. Canonical URL: &lt;a href="https://bmdpat.com/blog/build-local-llm-eval-data-from-failures-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/blog/build-local-llm-eval-data-from-failures-2026&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%2F8bei93gy68fuhla56fry.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%2F8bei93gy68fuhla56fry.png" alt="A local LLM eval loop that captures failures, keeps tests, and replays models" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are failed local LLM runs useful?
&lt;/h2&gt;

&lt;p&gt;I used to look at a bad answer, change the prompt, and run again. That fixes the moment. It does not create a durable test.&lt;/p&gt;

&lt;p&gt;My local coding rig now saves both good and bad attempts. A sample row contains the prompt, generated code, test code, verifier result, pass fraction, source, timestamp, model, generation method, and route. That record lets me replay the same task after I change a model, quant, system prompt, or runtime setting.&lt;/p&gt;

&lt;p&gt;The failure is useful because it is specific. One saved &lt;code&gt;add(a, b)&lt;/code&gt; attempt returned subtraction. Its two tests both failed. A saved &lt;code&gt;is_prime(n)&lt;/code&gt; attempt used the wrong remainder check. One of its two tests passed, while the other failed. Those rows show different failure shapes even though both answers were wrong.&lt;/p&gt;

&lt;p&gt;I do not need a model judge to explain either result. The tests provide the boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should one eval row contain?
&lt;/h2&gt;

&lt;p&gt;I keep the smallest record that can reproduce the decision:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prompt
model_output
test
verifier_result
pass_fraction
model
generation_method
route
source
captured_at
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt and output show what the model saw and wrote. The test defines the behavior I expected. The verifier result records what happened. The route tells me whether the request went direct to Ollama or through another layer.&lt;/p&gt;

&lt;p&gt;That last field matters. A model name alone does not identify a run. Prompt templates, context settings, and routing code can change the answer before the weights do.&lt;/p&gt;

&lt;p&gt;This is the same reason I use a &lt;a href="https://bmdpat.com/blog/local-model-verifier-loop-owned-gpu-2026" rel="noopener noreferrer"&gt;verifier loop before trusting a local coding model&lt;/a&gt;. The verifier turns a plausible answer into a pass or fail result. The eval row keeps that result tied to the exact attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do failed rows become a regression set?
&lt;/h2&gt;

&lt;p&gt;First, I keep the original failure. I do not replace it with the repaired answer.&lt;/p&gt;

&lt;p&gt;Second, I inspect the test. A weak test can make a bad row look useful. The &lt;code&gt;is_prime&lt;/code&gt; example caught one bad branch but still passed another case. That partial result is a reason to add boundary cases, not a reason to award half credit and move on.&lt;/p&gt;

&lt;p&gt;Third, I replay the task against the next candidate route. I compare the result with the saved baseline. If the new route passes, I still keep the old failure because it proves the test can detect the bug.&lt;/p&gt;

&lt;p&gt;This gives me a paired dataset: an input, a rejected output, a passing output, and the same executable check. I can use the pair for prompt repair, route selection, or later training work. I do not have to guess which answer was better.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can this eval set prove?
&lt;/h2&gt;

&lt;p&gt;It can prove that a named route passed a named set of checks at a recorded time. It can show whether a change fixed known failures or brought old ones back.&lt;/p&gt;

&lt;p&gt;It cannot prove that the model is good at coding in general. Three toy functions are starter data, not a production benchmark. Repeating the same seeds across iterations also does not create new task coverage.&lt;/p&gt;

&lt;p&gt;I keep that limit visible because small evals are easy to oversell. My note on &lt;a href="https://bmdpat.com/blog/local-llm-honest-eval-numbers-2026" rel="noopener noreferrer"&gt;honest local LLM eval numbers&lt;/a&gt; explains why the denominator and failed runs belong beside the score.&lt;/p&gt;

&lt;p&gt;The next useful step is to add failures from real work. I want tasks with repository context, file edits, tool calls, and tests that reflect the jobs my local agents actually do. A synthetic starter confirms the storage and replay path. Production failures make the set valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I keep the loop cheap?
&lt;/h2&gt;

&lt;p&gt;I save the row as soon as verification finishes. I do not wait for a later cleanup pass. The run already has the prompt, output, route, and test result in memory, so that is the cheapest moment to write the receipt.&lt;/p&gt;

&lt;p&gt;I also separate collection from promotion. A row may enter the dataset after verification, but a model only earns a production route after it passes the full gate. This lets me collect useful failures without lowering the bar for deployment.&lt;/p&gt;

&lt;p&gt;The result is a small loop I can trust: run a real task, verify the output, save the receipt, add the failure to the replay set, then test the next route against it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accompanying prompt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What the prompt does:&lt;/strong&gt; It turns local coding-agent run logs into replayable eval cases without inventing missing tests or measurements.&lt;/p&gt;

&lt;p&gt;Copy/paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are building a regression set for a local coding model.

Context:
Paste one task prompt, model output, test output, model name,
runtime route, and capture time.

Task:
1. Preserve the original prompt and output.
2. Extract the executable checks and their results.
3. Classify the failure by observed behavior.
4. List missing boundary cases that need new tests.

Output:
- One replayable eval row with named fields.
- A pass or fail verdict tied to the saved tests.
- A short list of added test cases, if needed.

Constraints:
- Do not repair or overwrite the failed output.
- Do not invent a test result or runtime setting.
- Keep measured facts separate from suggestions.
- Mark missing fields as unknown.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the block above.&lt;/p&gt;

&lt;p&gt;I publish measured local AI build notes in &lt;a href="https://bmdpat.com/5090-reports" rel="noopener noreferrer"&gt;The 5090 Reports&lt;/a&gt;. Join the email list for the next result.&lt;/p&gt;




&lt;p&gt;Get the local AI lab notes (benchmark rows, VRAM fit, quant choices, what runs on consumer GPUs), M-F only when there is something worth sending: &lt;a href="https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=build-local-llm-eval-data-from-failures-2026" rel="noopener noreferrer"&gt;https://bmdpat.com/newsletter?utm_source=blog_md&amp;amp;utm_medium=aeo&amp;amp;utm_campaign=build-local-llm-eval-data-from-failures-2026&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://bmdpat.com/blog/build-local-llm-eval-data-from-failures-2026?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=build-local-llm-eval-data-from-failures-2026&amp;amp;utm_content=footer_original" rel="noopener noreferrer"&gt;bmdpat.com&lt;/a&gt;. I run a one-person AI agent company and write about what actually works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want these in your inbox? &lt;a href="https://bmdpat.com/newsletter?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=build-local-llm-eval-data-from-failures-2026&amp;amp;utm_content=footer_newsletter" rel="noopener noreferrer"&gt;Subscribe to the newsletter&lt;/a&gt; - no spam, unsubscribe anytime.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>localllm</category>
      <category>modelevaluation</category>
      <category>codingagents</category>
      <category>ownedhardware</category>
    </item>
  </channel>
</rss>
