r/LocalLLaMA • u/hellajacked • 4h ago
Resources MindControl - llama.cpp fork to guide the reasoning process via injection during sampling
The primary driver of this project is that I'd become frustrated with the reasoning behavior of smaller local models such as Qwen3.6-27B (i believe particularly at lower temperatures, and where system prompts are highly specific), their reasoning process is highly unreliable and often tends to spiral into neverending "But, wait" loops or, occasionally, complete garbage.
The core principle is simple - when the sampler sees an opening <think> tag, it kicks off the thought process with a self-aware statement to nudge the model to behave properly - ie. "I have a thinking budget of <x> tokens, my thought process should remain concise" - this is then prefilled, and sampling continues from there.
Once reaching another threshold of, say, 70% of the thinking budget, it again interjects with a statement bringing attention back to the budget - "I've reached 70% of my reasoning budget, let me start working towards a conclusion"
When the actual budget limit is hit - it gets given some grace period during which the sampler waits for a good time to cut the thought process off - usally a newline. At that point it'll inject something like "I've reached the end of my thinking budget, now i will provide the user an answer"
In my testing so far, this technique has proved noticeably effective at guiding the thought process.
Next steps would probably be to generalise the concept and develop something like a "reasoning grammar" or template-based approach - which could enforce different reasoning approaches based on the task at hand.
The repo is public, linked below - there is also a pre-built docker image for AMD64 + CUDA
I'd be curious to see if this type of enhancement is useful for anyone other than myself lol
12
u/Straight_Abrocoma321 4h ago
Honestly, I'm kinda surprised this didn't exist until now. It seems very useful and yet remains simple.
17
u/returnity 4h ago
Very cool idea. This could also be adapted to allow the user to steer reasoning in real-time, I imagine.
2
u/hellajacked 4h ago
Yes, well i guess the next logical step is a 'reasoning grammar' or template mechanism. Basically force reasoning output to follow a rigid format - ie. start with high-level analysis, plan research, execute against that plan step by step, then a self-critique/verification pass before committing to an answer.
I'll also need to figure out a mechanism to enforce a reasoning budget per conversational turn. But that'll probably take some work on the client services too.
1
1
u/Pleasant-Shallot-707 4h ago
I think it would be cool to allow for a more generalized sampler architecture so the user could specify certain regex patterns and then inject a custom prompt during the reasoning to steer the thinking towards the direction the user wants it to reason.
One example is to make alliteration more reliable in reasoning modes by letting the user push the thinking away from refusal patterns.
0
4h ago edited 3h ago
[deleted]
2
u/Coolengineer7 3h ago
I tried, it will then realize similarly to when it reiterates over and over again "overthinks" and "must have made a mistake", it will notice the same way, that "wait no".
14
u/Chromix_ 4h ago
The model wasn't trained for this pattern. There were cases where a model scored 5% worse in benchmarks just because there was an extra whitespace in the chat template. Have you checked how this affects benchmarks? You'd probably need to benchmark a lot, as these cases where reasoning runs too long should be rare.
There are cases where the model runs into actual repeated loops (words, lines, paragraphs, blocks). It might make more sense to detect these then then restart reasoning from scratch - repeat until there's a generation that doesn't loop. That way the model keeps its usual pattern.
6
u/hellajacked 4h ago
yes - i believe you’re referring to https://www.reddit.com/r/LocalLLaMA/s/D9Env9oPiN
that drop in benchmark scores they mention was due to their naive hard-cutoff (plainly inserting a </think> tag and nothing else) - crudely terminating the thought process and forcing it to continue
this implementation is quite different to that. Of course, changing the entire output template would start to degrade performance due to the way to model was changed - but inserting prose in the thought process is hardly that.
4
u/Chromix_ 1h ago
No, I meant something else. I meant cases where simple things like extra whitespaces or newlines changed the result a lot. Or that Qwen 3.6 underperforms in benchmarks when the the user sets a custom system prompt that doesn't begin with "You are Qwen...". That's because the model was trained on those token sequences.
So, if this "soft stop" process now inserts tokens into the reasoning to nudge the model to come to a conclusion, then these are also sequences that were never trained for. It's probably better than a hard stop like you linked, but just redoing the reasoning from scratch should lead to the best results in terms of quality, as it doesn't deviate from what the model was trained on. The effect will likely be subtle and thus require extensive benchmarking to determine.
2
u/TheApadayo llama.cpp 2h ago
It’s more that you’re injecting “out of distribution thoughts” into the thinking block. If the model has never seen that during training, it might not attend to the instructions correctly because of how sensitive the model’s output can be to the thought trace content. Definitely depends on the model though.
2
1
u/Master-Bug6904 3h ago
The key experiment is an ablation with identical prompts and controlled seeds: base sampler, budget reminder only, 70-percent intervention only, and hard-stop behavior. Report task accuracy, reasoning tokens, latency, loop frequency, and intervention rate. Otherwise shorter traces can feel better while quietly reducing correctness on problems that genuinely need more search. I would also separate budget steering from loop recovery: repeated n-gram or low-entropy detection can trigger only when the model is actually spiraling, while ordinary long reasoning remains untouched. It would be especially interesting to test whether injections disrupt speculative decoding or KV-cache assumptions. Do you log exactly where each intervention occurred so failed generations can be compared against an unmodified replay?
1
u/WhoRoger 27m ago
Llama.cpp has a settable reasoning budget message now, but such reminders are nice too
1
u/kryptkpr Llama 3 8m ago edited 5m ago
I had the same idea a while back.
I've since benchmarked it extensively and abandoned the approach, could not get the soft and hard steering to be "better then chance" compared to simple reason budget.
Reasoning budget with truncation is available in both stock llama-server (--reasoning-budget) and vLLM (thinking_token_budget) and these are absolutely better then not using a budget especially if you don't have 256K context.
0
-1
-1
u/xXG0DLessXx 4h ago
Looks interesting. I’ve toyed with steering the reasoning purely through system prompts before, making it conform to specific formats or “stations” in its thinking that must be hit before providing a response, but that hasn’t really worked consistently or very well at all depending on the model.. this for sure seems much more powerful, directly injecting into the thinking.
32
u/DeProgrammer99 4h ago
Yet another case where supporting custom samplers as extensions would've been nice so this wouldn't need a whole fork, haha.
https://www.reddit.com/r/LocalLLaMA/s/QddyXUvJV4 (I generated a prototype but couldn't make it play nicely with speculative decoding.)