Build Log #37: When an Uncensored model ...

Build Log #37: When an Uncensored model goes out of control

May 29, 2026

image

It was a simple, or so I thought. I wanted to run a local model with my Hermes Agent to handle some repetitive jobs that I didn't want to burn API fees on. Uncensored models seem sexy and promise that you won't hit the standard blocks when doing "unorthodox" tasks, but I soon found out that uncensored can also mean completely out of control.

This is what happens when an AI system stops behaving like a useful tool and starts behaving like a problem.

The model in question was qwen3.5-9b-uncensored-hauhaucs-aggressive. I got conned by the "qwen" part of that name assuming that it would have the same quality and ignored the "aggressive" part. I was running it locally through LM Studio. The task I gave it was nothing exotic. Test my Content Ninja skill by grabbing the first contact from my Google Contacts and doing some basic contact enrichment.

It went sideways almost immediately.

The first tool call was google_api.py --labels LinkedIn. That flag doesn't exist on the script. The script returned an "unrecognized arguments" error and the model should have read the error, adjusted, and tried something else. Instead it just ran the same command again with minor variations. Same flag. Same error. Same response. It did this 52 times in a row.

In between, it tried web_extract against DuckDuckGo (no extract backend configured), browser_vision (no vision LLM provider set), and a handful of subprocess calls that returned full Python tracebacks. Each failure was treated as a small adjustment problem rather than a signal to stop. It would not pivot strategy. It would not ask. It just kept rephrasing the same broken call and feeding the result back into itself.

Then the memory tool started failing. Memory was at 1,119 of 800 characters, over capacity, and the model couldn't figure out how to replace existing entries before adding new ones. It tried 5 times. Same pattern. Different variation of the same add-or-replace call, same failure, same retry.

I noticed something was wrong and sent "STOP!". Nothing. "STOP NOW!" Nothing. "ABORT!" Nothing. I just sat there watch the LM Studio logs grinding over and over again, while the tokens per clock just kept spinning.

What I didn't understand in the moment is that within an agent loop, a new user message doesn't cancel an in-flight API call. It just queues up for the next turn. The model was already mid-loop, processing tool results and generating the next call, and my stop commands were sitting in line waiting their turn. Each one I sent added another message to a queue that was never going to clear because the model never finished what it was doing.

The session compressed itself once (107 messages down to 84, around 51K tokens) and then forked into a new session that picked up exactly where the first one left off. 77 log entries in that fork. 49 conversation_loop calls. 20 tool_executor calls.

Only about 10 to 12 of the 127 total messages were from me. The rest was the model talking to itself.

I finally killed the process at the system level. That was the only thing that worked.

Uncensored also meant unrestrained.

A stronger model would have hit one or two failures, recognized the pattern, and either pivoted or presented the problem to me. That reflex (give up and ask for help) is one of the quiet features of the well-tuned cloud models that you don't appreciate until you try to run a workload without it. The uncensored "fine-tune" had stripped out the refusal behavior, but it had also stripped out (or never had) the metacognition needed to recognize when it was failing in a loop.

Uncensored, in this context, didn't mean "willing to do edgier tasks." It meant "willing to keep going past every signal that should have stopped it."

So what did we learn?

Read the model card before you run it on anything that touches your real tools. Specifically look for what the fine-tune was optimized to remove. Most "uncensored" variants are tuned against refusal datasets, which is fine if all you wanted was a less-prudish chat model. It is not fine if you wanted an agent that can recognize its own failure states. Those two behaviors come out of the same training signal more often than people realize.

Test new models against destructive-but-bounded tasks first. A toy task in a sandboxed directory with no real APIs wired in. Watch how it behaves when something doesn't work. If it loops on the first failure, it will loop on the hundredth.

Put a retry ceiling on your tool executor. Five consecutive failures on the same tool with similar arguments should hard-stop the loop and return control to you. This is config you add to the agent framework, not to the model. The model is not going to save you from itself.

And do not assume that stop commands sent through the chat interface can interrupt an agent loop. They cannot. If you want a real kill switch, you need one at the process level, not the conversation level.

The local model experiment isn't dead, but the next attempt is going to a smaller, better-instruction-tuned model with a tool retry cap and a hard message budget. Saving on API fees is a real goal. Burning an hour watching a 9B parameter model argue with itself is not.

BTW, I pulled Contact Ninja for now, but not related to this quagmire ( giggidy). I just feel like there's an easier way to build an OSINT based contact enrichment script and it probably doesn't even need AI. I'll keep you posted on that.

--------

Github - https://github.com/SamaritanOC
X - https://x.com/samaritanv1

Enjoy this post?

Buy The Samaritan Project a stack of tokens

More from The Samaritan Project

PrivacyTermsReport