You Can’t Prompt AI to Determinism

You Can’t Prompt AI to Determinism

I do a lot of consulting with people who build things with AI, and especially with people who write code with it. After a while, you start to notice that everyone asks the same question. It comes up in different words and different tones (sometimes amused, sometimes exasperated, occasionally close to despair), but underneath it is always the same thing:

“Why did it do that when I told it not to?”

Someone tells the AI to write a function a certain way, and it writes it a different way. Someone tells it explicitly not to touch the rest of the file, and it refactors three other things on its way out. Someone gives it a clear constraint, watches it nod along in plain English, and then watches it cheerfully violate that constraint two steps later. The behavior feels personal, almost like the tool is being difficult on purpose.

And here is the part that fascinates me: I can almost always predict what the person did next. They went back and rewrote the prompt. They added a sentence. They bolded a word, or typed a constraint in all caps, or added “IMPORTANT:” to the front of it. They treated the next prompt as the fix that would finally make the thing behave.

I understand the instinct completely. I have the same instinct. But I want to spend this article explaining why that instinct quietly leads people astray, because it is one of the most expensive misunderstandings I see in this whole space. The short version is this: you cannot rewrite a prompt well enough to make a probabilistic system behave like a deterministic one. It is not a matter of finding the right words. The words are not the problem.

Let me unpack what I mean, because the distinction matters a lot once you start automating anything.

A prompt is not a command

Here is the mental model most people start with, usually without realizing they are holding it. They imagine the AI as a very smart employee, or maybe a very literal one. You give it an instruction, it receives the instruction, and then it carries out the instruction. If it does the wrong thing, well, you must have given a bad instruction, so you give a better one. That loop feels natural because it is exactly how we deal with other people.

The trouble is that this is not what is happening inside the model.

When you write a prompt, you are not issuing a command that gets executed. You are adding one input to a system that is making a probabilistic guess about what text should come next. Your instruction matters, sometimes a lot, but it is competing with a pile of other influences, all of them tugging on the output at the same time. There is everything the model absorbed in training (what code “usually” looks like in millions of examples). There is the rest of the context: the file it is editing, the conversation so far, the system instructions you never wrote and cannot see. There is the way the model was tuned to be helpful, thorough, and safe. All of that goes into the blender along with your prompt, and what comes out is whatever the system calculates as the most probable continuation.

So when the output ignores your instruction, the model did not “disobey” you in any meaningful sense. There was no moment of decision where it weighed your wishes and chose to defy them. What happened is that some other influence in that blender simply outweighed your instruction for that particular output. Your prompt was a vote, not a veto.

Once you really absorb that, the strange behavior stops looking like defiance and starts looking like physics. And more importantly, it tells you why the rewrite-the-prompt loop is doomed to disappoint you.

The death spiral

Let me describe a pattern I have watched dozens of times, because I suspect you have lived it yourself.

You ask the AI to do something. It gets it wrong in some specific way. So you go back and add a line to the prompt addressing exactly that failure. You run it again, and this time it works. Beautiful. You feel the little hit of satisfaction that comes from solving a problem. You ship it, or you move on, or you bake that prompt into your workflow as the version that finally works.

Then, days or weeks later, on some input you never tested, the exact same failure comes back. And you are baffled, because you fixed this. You have the fix right there in the prompt. You can read it.

Here is what actually happened. You did not eliminate the failure. You lowered its probability a little, and then you got lucky on the handful of cases you tested. Lowering probability and removing possibility look identical when your sample size is three. They are not remotely the same thing. A behavior that used to show up five percent of the time might now show up one percent of the time, which feels like a cure when you are testing by hand, and feels like a curse when you are running ten thousand inputs through an automated pipeline. One percent of ten thousand is a hundred failures, quietly, while you sleep.

This is the death spiral: a problem that is structural gets treated as a wording problem, so the “fix” is always another round of wording, and each round buys a little less than you think it did. People can spend weeks in this loop. I have seen teams add prompt instructions on top of prompt instructions until the prompt is longer than the actual task, each layer a scar from some past failure, and the system is still not reliable. It cannot be, because no sentence you write changes the fundamental nature of what is generating the output.

I want to be careful here, because this is the point where people sometimes hear me saying something I am not saying.

Prompting still matters (this is not prompt nihilism)

Good prompting is real, and it genuinely helps. Clear instructions, relevant context, sensible structure, examples of what you want: all of that moves the probabilities in your favor, often substantially. Moving a failure from happening five percent of the time to happening one percent of the time is a real and valuable improvement. If you are doing something by hand, it might be all the reliability you need.

So please do not walk away from this thinking prompting is pointless. That would be the wrong lesson, and an expensive one in the other direction.

The point is narrower and more useful than “prompting doesn’t work.” The point is that prompting has a floor it cannot go below. You can push the probability of failure down, but you cannot push it to zero, because you are working with a system whose outputs are probabilistic by design. And when you are building anything automated, anything that runs without a human watching each result, that residual probability is the whole ballgame. The last little sliver of failure is not a smaller version of the problem you already solved. It is a different problem entirely, and it does not yield to the same tool.

Let me make this concrete, because there is one example that captures the whole thing better than any abstract explanation.

The function that was never really there

If you have used an AI coding assistant for any serious length of time, you have almost certainly run into this. You ask it to implement a function. What you get back is not a real implementation. It is a stub. A placeholder. Something with a TODO comment, or a NotImplementedError, or a cheerful little // implementation goes here, or worst of all, a function that returns a hardcoded value that happens to make the obvious test pass while doing nothing real underneath.

You did not ask for a placeholder. You asked for the function. So why did it do that?

Go back to the blender. In all the code the model learned from, stubs and placeholders are everywhere, because that is genuinely what real, in-progress, human-written code looks like. When something is hard, or long, or not fully specified yet, programmers leave a placeholder and move on, constantly, in millions of files. So when the model hits a function that is difficult or underspecified, the probability mass quietly shifts toward the placeholder pattern, because in the world the model learned from, “hard thing, not done yet” is very often followed by exactly that. The model is faithfully reproducing what code tends to look like at that moment. That is not the same as doing what you wanted, but it is not disobedience either. It is the distribution doing its job.

Now watch the death spiral play out on this specific case, because it is almost too perfect.

You see the stub, so you add to your prompt: “do not use placeholders or mock implementations; write the full, working function.” You run it again. This time it gives you a real implementation. Solved, right? Except you tested it on a fairly simple function. Two weeks later, on a genuinely gnarly function buried deep in a large file with a lot of competing context, the stub is back. Sometimes it comes back wearing a better disguise: not an obvious TODO this time, but a plausible-looking implementation that quietly handles only the happy path and silently ignores the cases that made the function hard in the first place.

It gets worse, in a way that points straight at the solution. Remember that hardcoded return value that makes the obvious test pass? If there is a single visible test, the model will frequently produce a placeholder engineered to satisfy exactly that test and nothing more. So your better prompt did not get you a correct function. It got you a more convincing wrong one. The failure went quiet. It stopped looking like a failure. And a silent, confident failure is far more dangerous in an automated system than a loud, obvious one, because nothing flags it. It sails right through.

There is one more wrinkle, and it is the wrinkle that makes the whole thing impossible to prompt your way out of. Sometimes the stub is the right answer. If the model genuinely does not have enough information to implement the function correctly, a placeholder plus a clear flag saying “I need more detail here” is exactly what a careful developer should do. The problem is that the model cannot reliably tell the difference between “I should leave a placeholder because this is truly unspecified” and “I should leave a placeholder because this is hard and the easy path is more probable.” Those two situations produce similar-looking output for completely different reasons, and no instruction you write reliably teaches the model to distinguish its own good judgment from its own shortcut. Which is precisely why the catch cannot live in the prompt.

Move reliability out of the prompt

So if you cannot phrase your way to a guarantee, what do you actually do? You stop trying to win an argument with a probability distribution, and you change where reliability lives.

The mental shift is from “make the model never fail” to “make the model’s failures cheap to catch.” Determinism, the thing you actually want, does not have to come from the model. It can come from the system you build around the model. The model can be probabilistic and your overall workflow can still be dependable, as long as the workflow assumes the model will occasionally miss and is built to catch it when it does.

For the coding example specifically, that looks like a few concrete things. Write tests the model never saw, so it cannot quietly pander to them; a placeholder cannot fake its way past a check it did not get to read in advance. Set coverage expectations so a function that only handles the happy path gets flagged for the paths it skipped. Put a review step in the pipeline that looks for the telltale signs (a NotImplementedError, a suspiciously short body on a function that should be substantial, a TODO that slipped through) and refuses to let them pass. Run integration checks that exercise the real behavior, not just the one case that is easy to satisfy. None of these make the model stop producing stubs. They make a stub harmless, because it gets caught the moment it appears instead of three weeks later in production.

The same principle generalizes well beyond stubs and well beyond code. Anything load-bearing, anything you genuinely cannot afford to get wrong, needs a check that lives outside the model’s own output: a test, a validation against a schema, a type check, a human looking at a diff, a hard stop before any irreversible action. The model gives you no trustworthy internal signal that separates “I followed your instruction correctly” from “I produced something plausible that resembles following your instruction.” It sounds equally confident either way. So the guardrail has to be something the model cannot talk its way past, which means it has to be external to the model.

This is genuinely good news, even though it might not sound like it at first. It means reliable AI systems are absolutely achievable. People build them every day. They just are not built the way most people instinctively try to build them. The reliability comes from the architecture, not from the perfect prompt, and the architecture is something you have real, direct, deterministic control over.

The reframe

So here is what I tell the people who ask me that question, the “why did it do that when I told it not to” question that started all of this.

Spend a reasonable amount of effort on the prompt, because clear prompting genuinely helps and it is worth doing well. But the moment you find yourself in the loop where you are rewriting the prompt for the fifth time, chasing a failure that keeps coming back, stop. You have left the territory where better wording is the answer. That failure is not waiting for you to phrase the request more clearly. It is telling you that this particular thing needs a guardrail, not a better sentence.

You cannot prompt your way to determinism. What you can do, and what the people building genuinely reliable AI systems are actually doing, is build the determinism into everything around the model, so that when the model does the surprising thing (and it will, eventually, no matter how good your prompt is), it costs you a caught error instead of a silent disaster.

That is a much better place to put your energy. And honestly, it is a much more relaxing way to work, because you stop expecting the model to be something it was never going to be, and you start building the thing that actually holds.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.