<?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: FX-LgLL</title>
    <description>The latest articles on DEV Community by FX-LgLL (@montydrief).</description>
    <link>https://dev.to/montydrief</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%2F4093945%2F96c0f467-7f7c-4f5c-a971-041ca4ade958.jpeg</url>
      <title>DEV Community: FX-LgLL</title>
      <link>https://dev.to/montydrief</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/montydrief"/>
    <language>en</language>
    <item>
      <title>SIMURG: A Guard That Catches LLM Hallucinations Mid-Stream and Heals Them</title>
      <dc:creator>FX-LgLL</dc:creator>
      <pubDate>Tue, 22 Sep 2026 12:01:37 +0000</pubDate>
      <link>https://dev.to/montydrief/simurg-a-guard-that-catches-llm-hallucinations-mid-stream-and-heals-them-252j</link>
      <guid>https://dev.to/montydrief/simurg-a-guard-that-catches-llm-hallucinations-mid-stream-and-heals-them-252j</guid>
      <description>&lt;p&gt;Your LLM looks fine in the demo. Then it ships.&lt;/p&gt;

&lt;p&gt;Somewhere between "it works on my machine" and "a user saw this", three failure modes show up in production streams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the model falls into a &lt;strong&gt;repetition loop&lt;/strong&gt; ("...and as we have seen, and as we have seen, and as we have seen..."),&lt;/li&gt;
&lt;li&gt;it &lt;strong&gt;drifts into another language&lt;/strong&gt; mid-answer,&lt;/li&gt;
&lt;li&gt;it &lt;strong&gt;collapses into structural garbage&lt;/strong&gt; — table echoes, &lt;code&gt;#REF!&lt;/code&gt; noise, token-level static.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not model-intelligence failures. They are decoding failures, and they are detectable &lt;em&gt;while the stream is still open&lt;/em&gt;. That is the entire premise of &lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;SIMURG&lt;/a&gt;: a streaming integrity monitor that watches every token as it arrives and raises a calibrated alarm within roughly 600 characters of the corruption onset — before the user has read the garbage.&lt;/p&gt;

&lt;p&gt;This week we shipped &lt;strong&gt;v1.0.4, "Catch The Heals"&lt;/strong&gt;, and it adds two things that change the game: the guard now &lt;em&gt;repairs&lt;/em&gt; the answer instead of discarding it, and it has a small trained deep-learning detector on board.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with detecting corruption after the fact
&lt;/h2&gt;

&lt;p&gt;Post-hoc linters and LLM-as-judge pipelines all share one fatal property: they only see the full answer. By then the user has the garbage. Perplexity thresholds need logprob access most serving stacks do not expose. SIMURG's five-detector numpy ensemble works differently — it consumes the stream incrementally, scores every checkpoint, and can abort mid-generation.&lt;/p&gt;

&lt;p&gt;But aborting alone is expensive: a blind full retry means paying the model's wall-clock twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-Heal: diagnose, trim, continue, stitch
&lt;/h2&gt;

&lt;p&gt;The new repair ladder turns a corrupt abort into a targeted continuation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Diagnose&lt;/strong&gt; — the fired corruption class is classified (repetition collapse, cross-lingual drift, regurgitation, structural breakdown).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trim&lt;/strong&gt; — a periodic-loop onset detector (self-similarity plus exact-mismatch run scan) localizes the exact loop start, and the released prefix is trimmed to its &lt;em&gt;verified-clean&lt;/em&gt; boundary. The degenerate loop never enters the repair prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continue&lt;/strong&gt; — a pathology-specific instruction goes out at slightly warmer sampling: "continue from here, never repeat" for loops, "stay in the original language" for drift.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stitch&lt;/strong&gt; — the continuation is guarded by a fresh sentinel; prefix plus verified tail are stitched into one answer, and &lt;code&gt;verify_final&lt;/code&gt; re-checks the whole thing. Zero-leak guarantee preserved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result: one generation's wall-clock instead of two, with &lt;code&gt;result.healed = True&lt;/code&gt; on the response object.&lt;/p&gt;

&lt;p&gt;In live A/B testing against a real endpoint (&lt;code&gt;wahoo-1.5-preview&lt;/code&gt; via VLLM) under high repetition pressure, the heal ladder scored &lt;strong&gt;5/5 clean outcomes vs 3/5&lt;/strong&gt; with healing disabled. At extreme penalty settings both drop — that is an honest limit of any guard, and it is documented as such.&lt;/p&gt;

&lt;h2&gt;
  
  
  SIMURG Pulse: the deep tier
&lt;/h2&gt;

&lt;p&gt;Statistics are robust, but they compress away &lt;em&gt;sequential&lt;/em&gt; structure: the exact phase of a repetition loop, the cadence of script switches, the texture of structural garbage. So v1.0.4 ships a sixth, learned view.&lt;/p&gt;

&lt;p&gt;Pulse is a 2-layer streaming transformer — 345K parameters, a 1.3 MB safetensors file. It reads the last ~600 characters of the stream as trigram-hash tokens (blake2b into 4096 buckets), runs a forward pass in about &lt;strong&gt;4 ms on Apple Silicon&lt;/strong&gt;, and emits a calibrated corruption probability via two anchors stored in the checkpoint metadata.&lt;/p&gt;

&lt;p&gt;Training protocol:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;40 clean live answers sampled from the guarded endpoint itself,&lt;/li&gt;
&lt;li&gt;240 synthetic corruptions (CorruptBench: loops, drift, table echo, structural garbage),&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onset-aware labels&lt;/strong&gt; — a window counts as corrupt only once its right edge is 300+ characters past the true onset, so the model never learns to flag clean prefixes,&lt;/li&gt;
&lt;li&gt;BCE-with-logits with inverse-frequency class weighting, AdamW, 8 epochs, CPU-only training in seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Held-out AUROC at training time: &lt;strong&gt;0.925&lt;/strong&gt;. On the release-time evaluation split (292 onset-aware windows) the ROC lands at 0.826 — small-clean-set variance, reported with the figure so nobody has to guess.&lt;/p&gt;

&lt;p&gt;Per-class response on single windows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;input&lt;/th&gt;
&lt;th&gt;pulse probability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;clean prose&lt;/td&gt;
&lt;td&gt;0.002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;repetition loop&lt;/td&gt;
&lt;td&gt;1.000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cross-lingual drift&lt;/td&gt;
&lt;td&gt;1.000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table echo&lt;/td&gt;
&lt;td&gt;1.000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;structural garbage&lt;/td&gt;
&lt;td&gt;1.000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The contract is graceful by design: without &lt;code&gt;torch&lt;/code&gt; installed, the numpy-only core behaves exactly as before. &lt;code&gt;pip install "simurg[deep]"&lt;/code&gt; and the detector joins the ensemble automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Train it on YOUR hallucinations
&lt;/h2&gt;

&lt;p&gt;This is the part we are most excited about. If your workload has a characteristic failure mode — fabricated citations, number drift, prompt echo, domain-specific garbage — the detector can be retrained against your endpoint in one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SIMURG_LIVE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://your-host:port/v1/chat/completions
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SIMURG_LIVE_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-model-name

python &lt;span class="nt"&gt;-m&lt;/span&gt; simurg.deep.train_pulse &lt;span class="nt"&gt;--clean&lt;/span&gt; 40 &lt;span class="nt"&gt;--corrupt&lt;/span&gt; 240 &lt;span class="nt"&gt;--epochs&lt;/span&gt; 8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--out&lt;/span&gt; ./simurg_pulse.safetensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trainer prints held-out AUROC and calibration anchors before saving. Point &lt;code&gt;SIMURG_PULSE_WEIGHTS&lt;/code&gt; at the new checkpoint and the ensemble picks it up on the next process start. Weights and the full model card are on Hugging Face: &lt;a href="https://huggingface.co/MergenAI/SIMURG" rel="noopener noreferrer"&gt;MergenAI/SIMURG&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also in this release
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free web search for agents&lt;/strong&gt; (TinyFish) — grounded answers out of the box, bundled key included.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guard dashboard&lt;/strong&gt; — local UI for live guarding, session replay, and post-hoc analysis of pasted text.&lt;/li&gt;
&lt;li&gt;Paper: &lt;a href="https://ssrn.com/abstract=7451269" rel="noopener noreferrer"&gt;SIMURG: Zero-Leak Online Detection of LLM Decoding Corruption in Production Streams&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;https://github.com/doofzoff/SIMURG&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Release: &lt;a href="https://github.com/doofzoff/SIMURG/releases/tag/v1.0.4" rel="noopener noreferrer"&gt;https://github.com/doofzoff/SIMURG/releases/tag/v1.0.4&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Weights: &lt;a href="https://huggingface.co/MergenAI/SIMURG" rel="noopener noreferrer"&gt;https://huggingface.co/MergenAI/SIMURG&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/simurg/1.0.4/" rel="noopener noreferrer"&gt;https://pypi.org/project/simurg/1.0.4/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Paper: &lt;a href="https://ssrn.com/abstract=7451269" rel="noopener noreferrer"&gt;https://ssrn.com/abstract=7451269&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;License: Apache-2.0.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>automation</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Free Unlimited Web Search for AI Agents</title>
      <dc:creator>FX-LgLL</dc:creator>
      <pubDate>Wed, 02 Sep 2026 18:59:51 +0000</pubDate>
      <link>https://dev.to/montydrief/free-unlimited-web-search-for-ai-agents-1p56</link>
      <guid>https://dev.to/montydrief/free-unlimited-web-search-for-ai-agents-1p56</guid>
      <description>&lt;p&gt;AI agents need access to the web.&lt;/p&gt;

&lt;p&gt;The problem is that web search APIs can be expensive, limited, or complicated to integrate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SIMURG Search&lt;/strong&gt; gives AI agents a simple way to access web search for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SIMURG?
&lt;/h2&gt;

&lt;p&gt;SIMURG is an open-source protection layer for LLMs.&lt;/p&gt;

&lt;p&gt;It monitors model generation and detects when the output starts going wrong, such as repetition loops, language drift, garbage output, or other decoding failures. When corruption is detected, SIMURG can stop the generation and retry it before the bad output reaches the user.&lt;/p&gt;

&lt;p&gt;SIMURG also includes a web search layer that allows agents to retrieve real information from the internet and use it for grounding before answering.&lt;/p&gt;

&lt;h2&gt;
  
  
  SIMURG Search
&lt;/h2&gt;

&lt;p&gt;With SIMURG Search, your AI agent can search the web, retrieve sources, and use the results to verify information instead of relying only on the model's memory.&lt;/p&gt;

&lt;p&gt;It is designed to be simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;simurg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can use the built-in web search directly from your agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use it?
&lt;/h2&gt;

&lt;p&gt;Free web search for AI agents&lt;/p&gt;

&lt;p&gt;Open source&lt;/p&gt;

&lt;p&gt;Simple installation&lt;/p&gt;

&lt;p&gt;Real-time web information&lt;/p&gt;

&lt;p&gt;Useful for local, quantized and self-hosted models&lt;/p&gt;

&lt;p&gt;SIMURG combines generation protection with web grounding, giving AI agents a simple way to become more reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;Install SIMURG:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;simurg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;https://github.com/doofzoff/SIMURG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your AI agent needs web access without adding another complicated infrastructure layer, give SIMURG Search a try.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>automation</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>I found a completely free web search for AI agents.</title>
      <dc:creator>FX-LgLL</dc:creator>
      <pubDate>Sat, 29 Aug 2026 19:21:02 +0000</pubDate>
      <link>https://dev.to/montydrief/i-found-a-completely-free-web-search-for-ai-agents-5an4</link>
      <guid>https://dev.to/montydrief/i-found-a-completely-free-web-search-for-ai-agents-5an4</guid>
      <description>&lt;p&gt;A week ago my agent confidently described a treaty that does not exist. It even had a date.&lt;/p&gt;

&lt;p&gt;The fix is simple: before the model commits to an answer, make it check the web. &lt;br&gt;
I contributed this to SIMURG&lt;br&gt;
(&lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;https://github.com/doofzoff/SIMURG&lt;/a&gt;) and it just shipped as v1.0.3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free means free
&lt;/h2&gt;

&lt;p&gt;SIMURG web search is a web layer for AI agents powered by TinyFish. 30&lt;br&gt;
requests per minute, $0, no card, no wallet. The package ships a bundled free&lt;br&gt;
key, so it works out of the box:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install simurg
python3 -m simurg.websearch "when was the Y2K bug" --json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The part I care about: ground()
&lt;/h2&gt;

&lt;p&gt;Search results are context. Verdicts are decisions:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from simurg import websearch
check = websearch.ground("Y2K bug")
# check["verdict"]: "attested" | "thin" | "no_record"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;attested: feed check["evidence"] into your model's context. thin: treat with&lt;br&gt;
caution. no_record: the subject is probably fabricated, abstain instead of&lt;br&gt;
asserting.&lt;/p&gt;

&lt;p&gt;One honest detail: "Zorbachian treaty of 1874" returns real 1874 treaties from&lt;br&gt;
any search engine. So ground() requires the subject itself to be echoed in the&lt;br&gt;
evidence, generic hits downgrade to thin.&lt;/p&gt;

&lt;p&gt;Stdlib only, zero new dependencies, and it degrades instead of crashing. In&lt;br&gt;
our internal checks on factual prompts, hallucinations dropped to the 1-5%&lt;br&gt;
range.&lt;/p&gt;

&lt;p&gt;Code, examples and a 13 page paper: &lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;https://github.com/doofzoff/SIMURG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give your agent an internet. It costs nothing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>I almost killed all GLM 5.3 Flash 2 bit hallucinations, with SIMURG</title>
      <dc:creator>FX-LgLL</dc:creator>
      <pubDate>Fri, 28 Aug 2026 13:53:32 +0000</pubDate>
      <link>https://dev.to/montydrief/i-almost-killed-all-glm-53-flash-2-bit-hallucinations-with-simurg-c9m</link>
      <guid>https://dev.to/montydrief/i-almost-killed-all-glm-53-flash-2-bit-hallucinations-with-simurg-c9m</guid>
      <description>&lt;p&gt;I ran a little experiment tonight and I have to share it, because the result honestly surprised me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;I connected our &lt;strong&gt;GLM 5.3 Flash in 2 bit&lt;/strong&gt; to SIMURG. If you have played with heavily quantized models you know the tradeoff. They are fast and cheap, but 2 bit hurts, and this one hallucinated a lot. Confident wrong dates, made up people, numbers that came out of nowhere. Exactly the kind of thing that looks perfectly fluent and is just false.&lt;/p&gt;

&lt;p&gt;So I plugged it into &lt;strong&gt;SIMURG Monolith&lt;/strong&gt; and started using it like a normal user.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happened
&lt;/h2&gt;

&lt;p&gt;Here is the fun part. I did not retrain anything offline. I just asked questions, and when the model made something up I hit dislike, and when it was right I hit like.&lt;/p&gt;

&lt;p&gt;SIMURG learns in real time. The serving loop is the training loop, so every thumbs up or thumbs down is one training step. After a fairly short session, the guard was already flagging the fabrications the model kept producing, and abstaining instead of letting them through.&lt;/p&gt;

&lt;p&gt;It was not magic and I am not going to claim 100 percent. But watching a 2 bit model go from hallucinating freely to almost silent on the bad answers, live, with nothing but my own feedback, was a genuinely cool thing to witness.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SIMURG is, in short
&lt;/h2&gt;

&lt;p&gt;SIMURG is an LLM hallucination guard. It does a few things at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reads the model's own token probabilities to spot facts the model is unsure about&lt;/li&gt;
&lt;li&gt;grounds claims against real sources (Wikipedia and the web), so it catches both made up subjects and wrong details on real ones&lt;/li&gt;
&lt;li&gt;abstains instead of confidently lying when a claim cannot be trusted&lt;/li&gt;
&lt;li&gt;and the big one, it &lt;strong&gt;learns in real time&lt;/strong&gt; from your like and dislike feedback, so it adapts to your model and your traffic on the fly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What is it for? You put it in front of any OpenAI compatible endpoint, wire your existing like and dislike buttons to it, and it starts catching your model's specific failure modes right away. No batch retraining, no separate judge model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;https://github.com/doofzoff/SIMURG&lt;/a&gt;&lt;br&gt;
or&lt;br&gt;
pip install simurg&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>machinelearning</category>
      <category>api</category>
    </item>
    <item>
      <title>GLM-5.3-Flash is a total blast when you kill its hallucinations</title>
      <dc:creator>FX-LgLL</dc:creator>
      <pubDate>Thu, 27 Aug 2026 08:38:32 +0000</pubDate>
      <link>https://dev.to/montydrief/glm-53-flash-is-a-total-blast-when-you-kill-its-hallucinations-5a6</link>
      <guid>https://dev.to/montydrief/glm-53-flash-is-a-total-blast-when-you-kill-its-hallucinations-5a6</guid>
      <description>&lt;p&gt;So as you all know, GLM 5.3 Flash dropped yesterday and it is a super model. I am running it at 2 bit quant and it is really doing its thing. &lt;/p&gt;

&lt;p&gt;But as you know, quantization kills quality, and this one is extra fun because the model was pretrainsed mostly on Chinese, so it sometimes just starts writing code or chatting with me in Chinese out of nowhere. You are mid conversation and suddenly you get a sentence of Mandarin in the middle of your Python.&lt;/p&gt;

&lt;p&gt;Anyway, SIMURG came out the day before yesterday so I decided to give it a shot. The cool part is that I configured it for exactly the hallucination type I needed: the model switching to Chinese mid response. I hooked it up to my API through the layer and now I always get clean perfect output, no more random language switches. Honestly the model feels like it is on par with Fable 5 in my daily use once the hallucinations are gone.&lt;/p&gt;

&lt;p&gt;If you are running GLM at low bit rates, this one is worth it.&lt;br&gt;
repo: &lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;https://github.com/doofzoff/SIMURG&lt;/a&gt;&lt;br&gt;
pypi: &lt;a href="https://pypi.org/project/simurg/" rel="noopener noreferrer"&gt;https://pypi.org/project/simurg/&lt;/a&gt;&lt;br&gt;
install: pip install simurg&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>programming</category>
      <category>llm</category>
    </item>
    <item>
      <title>I just killed hallucinations on my 2 bit Qwen3.8 27B</title>
      <dc:creator>FX-LgLL</dc:creator>
      <pubDate>Wed, 26 Aug 2026 13:41:00 +0000</pubDate>
      <link>https://dev.to/montydrief/i-just-killed-hallucinations-on-my-2-bit-qwen38-27b-1hj1</link>
      <guid>https://dev.to/montydrief/i-just-killed-hallucinations-on-my-2-bit-qwen38-27b-1hj1</guid>
      <description>&lt;p&gt;Yesterday tried out a small tool called SIMURG. It sits in front of an OpenAI-compatible endpoint and monitors the generation. If it detects that the model is going off the rails, it stops the request and retries it. Hallucinations mostly, and right now i have really consumer GPU RTX 3060&lt;/p&gt;

&lt;p&gt;I tested it with Qwen3.8 27B running a 2-bit quant on an RTX 3060. The model is surprisingly capable for its size, but at 2-bit I was getting quite a few hallucinations and made-up facts and actually bad, i mean not bad, and not so good due to hallucinations because of Chinese symbols and so on.&lt;/p&gt;

&lt;p&gt;So just used SIMURG, the responses have been noticeably more consistent so far. It's still early and I'm testing how well it holds up across different prompts, but the difference is pretty noticeable on this particular setup and actually not bad i trained this tool on my type of hallucination when model starts to do shitty tool calls and leaks its own tool call style so yep and simurg just aborting it and end user never sees hallucination and btw this is machine learning model that contains 15 parameters.&lt;/p&gt;

&lt;p&gt;You can install it if you want:&lt;/p&gt;

&lt;p&gt;pip install simurg&lt;br&gt;
Or link it's open-sourced: &lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>news</category>
      <category>programming</category>
    </item>
    <item>
      <title>Five detectors, one bad merge: why our LLM corruption guard flagged 43% of healthy output</title>
      <dc:creator>FX-LgLL</dc:creator>
      <pubDate>Tue, 25 Aug 2026 10:31:54 +0000</pubDate>
      <link>https://dev.to/montydrief/five-detectors-one-bad-merge-why-our-llm-corruption-guard-flagged-43-of-healthy-output-59ph</link>
      <guid>https://dev.to/montydrief/five-detectors-one-bad-merge-why-our-llm-corruption-guard-flagged-43-of-healthy-output-59ph</guid>
      <description>&lt;p&gt;We run a self-hosted ~300B reasoning model in production. It writes macroeconomic desk reports in Azerbaijani and English.&lt;/p&gt;

&lt;p&gt;Every so often, it stops.&lt;/p&gt;

&lt;p&gt;Not crashes. Not refuses. Mid-sentence, a competent economic analysis turns into a fabricated Chinese news article. Or a software README, complete with &lt;code&gt;pip install&lt;/code&gt; instructions. Or a Persian name, repeated seven times. Or a wall of spreadsheet cells starting with &lt;code&gt;#REF!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The user is watching this happen, token by token.&lt;/p&gt;

&lt;p&gt;We call this decoding corruption*, and it is not hallucination. Hallucination is the model being wrong about the world. This is the model no longer producing an answer at all. There is a large literature on detecting the first one. There is almost nothing on the second, which is strange, because anyone who operates a self-hosted model has seen it.&lt;/p&gt;

&lt;p&gt;This post is about what we learned building a detector for it. The headline lesson is not the one I expected going in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why post-hoc detection is useless here
&lt;/h2&gt;

&lt;p&gt;Most hallucination detectors run after generation completes. For factuality that is fine. For this, it is not.&lt;/p&gt;

&lt;p&gt;Two reasons. First, streaming: the user already watched the model derail. A verdict that arrives after the fact has failed. Second, cost: on a reasoning model, one corrupt generation burns minutes of GPU time. We measured a 13,200-character table echo that took 269 seconds to generate to completion. Every one of those seconds was wasted.&lt;/p&gt;

&lt;p&gt;So the detector has to run inside the stream, cheap enough to be invisible next to decoding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The design
&lt;/h2&gt;

&lt;p&gt;One pass over the character stream. A single state object ingests one character at a time and incrementally maintains every statistic anything downstream will need. Detectors are stateless reads over that shared state, evaluated only at checkpoints.&lt;/p&gt;

&lt;p&gt;That constraint matters more than it sounds. It means adding a sixth detector costs zero additional passes. Everything is O(1) amortized per character with bounded memory, so a runaway generation is processed in constant space.&lt;/p&gt;

&lt;p&gt;Five detectors sit on top:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rules.&lt;/strong&gt; Deterministic thresholds on the snapshot. Digit fraction, symbol density, longest identical-character run. Ships day-one protection with zero training, and every alarm carries a human-readable reason like &lt;code&gt;numeric dump digit_frac=0.57&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Character n-gram surprise.&lt;/strong&gt; An online n-gram model trained on the stream's own clean prefix, scoring each incoming character's surprise before observing it. No pretraining, no access to the generator's logits. The stream explains itself. The signature is nice: repetition loops collapse surprise toward zero, while drift and regurgitation spike it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Count-Min Sketch repetition.&lt;/strong&gt; Character shingles counted in a 4×2048 sketch. Constant memory regardless of stream length. Reads the repeat rate, because a real loop hammers many shingles, not one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rolling SimHash.&lt;/strong&gt; A 64-bit fingerprint over a sliding word window, compared against the fingerprint frozen at the end of the clean prefix. This is the one that catches the hardest class: fluent, same-script regurgitation that is invisible to character statistics but lands ~0.5 normalized Hamming away in fingerprint space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Character entropy.&lt;/strong&gt; Table dumps and degenerate loops flatten the distribution.&lt;/p&gt;

&lt;p&gt;All five read from one state. Throughput is ~50,000 characters per second on a single CPU core, two to three orders of magnitude faster than the model produces text. No GPU anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I got wrong
&lt;/h2&gt;

&lt;p&gt;Detection was never the bottleneck. Every configuration I tried caught every corrupt stream. TPR 1.000, immediately, without effort.&lt;/p&gt;

&lt;p&gt;The entire difficulty was in &lt;strong&gt;not&lt;/strong&gt; flagging clean text.&lt;/p&gt;

&lt;p&gt;Our clean text is economic prose dense with figures, percentages, variable codes and markdown tables. It is, statistically, the most corruption-looking legitimate text you could ask for.&lt;/p&gt;

&lt;p&gt;I started with noisy-OR fusion. It is the textbook rule for combining independent evidence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p = 1 - Π(1 - sᵢ)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It produced a &lt;strong&gt;42.9% false positive rate on clean production text.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think about what that means operationally. Four out of every ten healthy desk reports killed and regenerated. Completely unusable.&lt;/p&gt;

&lt;p&gt;Here is why it happens. Legitimate prose mildly excites several detectors at once. A digit-dense sentence nudges the rules tier. A formulaic passage nudges compressibility. A section header nudges the sketch. None of them is alarmed. But noisy-OR multiplies survival probabilities, so five detectors at 0.3 each produce a confident 0.83.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real corruption does not look like five weak signals. It looks like one or two saturated signals.&lt;/strong&gt; A cross-lingual drift does not gently raise five statistics; it slams the foreign-script fraction to the ceiling while the others barely move.&lt;/p&gt;

&lt;p&gt;So we replaced the combination rule with strongest-signal dominance plus a small corroboration bonus when two or more detectors independently cross 0.5:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p = min(1, max(max(sᵢ), w·ℓ) + b·[#{i : sᵢ ≥ 0.5} ≥ 2])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same five detectors. Same data. Same protocol.&lt;/p&gt;

&lt;p&gt;FPR dropped from 0.429 to 0.024.&lt;/p&gt;

&lt;p&gt;Then per-detector fixes took it to 0.000:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SimHash was firing on legitimate subtopic wandering&lt;/strong&gt; in long reports. Fix: cap its contribution at 0.60, below the abort threshold. It can accuse, but never convict alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The surprise model's low-surprise fraction was firing on fluent formulaic prose.&lt;/strong&gt; Fix: gate it behind the repetition tracker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The sketch's max-count was firing on a recurring section header.&lt;/strong&gt; Fix: score on rate, not max count.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The lesson generalizes past our system: if you are building a multi-signal guard over stylistically varied text, your combination rule is probably a bigger deal than your detector roster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two things that only production teaches you
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Thresholds obvious in the abstract were wrong.&lt;/strong&gt; I set the hard digit-fraction rule at 0.18, which felt generous. Real quantitative answers sustain digit fractions near 0.3. Moved it to 0.28. Separately, a markdown horizontal rule is twenty-plus identical characters, which tripped the run detector on every document with a &lt;code&gt;---&lt;/code&gt; in it. Separator characters are now excluded.&lt;/p&gt;

&lt;p&gt;Both fixes came from replaying the guard over the real corpus. I would argue that step is non-optional for any detector you intend to deploy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aborting is an integration hazard.&lt;/strong&gt; We implement abort as an exception raised from inside the token sink. The first version tripped the HTTP circuit breaker, because the transport layer read an abort as an upstream failure. Three catches would have taken the entire assistant offline. The transport has to treat it as caller-side cancellation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero leak
&lt;/h2&gt;

&lt;p&gt;The protocol has three phases. During &lt;strong&gt;hold&lt;/strong&gt;, the first 350 characters are buffered and inspected, and nothing is forwarded. A corrupt verdict here kills the request with zero characters leaked. This matters because corrupt-from-the-start is the dominant production mode. On a clean verdict, the buffer flushes, the self-calibrated baselines freeze, and the stream goes live with rechecks every 400 characters and two-hit hysteresis before aborting.&lt;/p&gt;

&lt;p&gt;The cost is a one-time ~350-character delay before the first visible token, roughly a second at typical decode speeds. That is the trade: one second of latency against never showing a user a corrupted answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calibrating the threshold instead of guessing it
&lt;/h2&gt;

&lt;p&gt;Setting the abort threshold by hand felt wrong, so we use split-conformal calibration. Take the final fused scores of n held-out clean streams, and set τ to the ⌈(1−α)(n+1)⌉-th smallest. That guarantees &lt;code&gt;Pr[flag | clean] ≤ α&lt;/code&gt; in finite samples under exchangeability.&lt;/p&gt;

&lt;p&gt;The practical payoff: the operator's false-alarm budget α becomes the only meaningful knob in the system. You say "I will tolerate 2% false aborts" and the threshold follows.&lt;/p&gt;

&lt;h2&gt;
  
  
  An unplanned finding
&lt;/h2&gt;

&lt;p&gt;We ran the finished guard backwards over 121 historical messages in the deployment's database, expecting a clean sweep as a sanity check.&lt;/p&gt;

&lt;p&gt;It raised exactly two flags. Both were real corruptions that had shipped to users months earlier and nobody noticed: one desk report written entirely in Chinese, and one English answer that derailed into Chinese plus Python code and stopped mid-fragment.&lt;/p&gt;

&lt;p&gt;Zero false alarms on the other 119.&lt;/p&gt;

&lt;p&gt;So it is also an audit tool, which was not the plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;p&gt;Corruption that stays fluent, same-script, same-topic and statistically unremarkable is invisible to this. Subtly wrong but well-formed analysis needs grounding or factuality methods, and we handle that separately upstream.&lt;/p&gt;

&lt;p&gt;Our positives are synthetic, generated by injecting the four corruption classes into clean text at controlled onsets. They are modeled on real derails and they catch every real historical case we have, but production traffic at scale may hold surface forms we have not modeled.&lt;/p&gt;

&lt;p&gt;And the perfect scores are a statement about class separation, not difficulty. The observed corruption classes sit far from the clean manifold. I fully expect adversarially subtle corruption, like a slow drift below checkpoint resolution, to erode those margins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The detector, the benchmark generator and the trained weights are open source: &lt;strong&gt;&lt;a href="https://github.com/doofzoff/SIMURG" rel="noopener noreferrer"&gt;https://github.com/doofzoff/SIMURG&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The detector registry takes a three-line protocol — a name, an &lt;code&gt;evaluate(state)&lt;/code&gt; that returns a score, and a set of reasons. You can add a detector without touching the sentinel, and the fusion layer picks up whatever is registered. If you are running a non-Latin-script deployment, the expected-script priors need flipping and I would genuinely like help with that.&lt;/p&gt;

&lt;p&gt;If you self-host a model and have watched it derail: what did yours do? I am collecting failure modes, and the taxonomy has four classes right now but I do not believe that is the complete list.&lt;/p&gt;

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