Knowing When Not to Use AI
The more AI systems I build, the more convinced I am that good AI engineering is not about putting models everywhere. It is about knowing where uncertainty is useful, where deterministic software is better, and where AI should not be involved at all.
7 min read · AI · AI Engineering · LLMs · AI Agents · Software Engineering · Systems Design
AI is very good at making bad architecture look exciting.
Give a problem to an LLM, wrap it in an agent loop, connect a few tools, add memory, and suddenly something that could have been a CASE statement has a system diagram.
I understand the appeal. I have built with LLMs, SLMs, agents, embeddings, retrieval systems, classifiers, tool-calling systems, and most of the machinery people currently put under the very broad label of AI.
The more I work with them, though, the less interested I am in putting AI everywhere.
I think one of the most important skills an AI engineer develops is knowing when not to use AI.
AI is useful because it is not deterministic
That sounds obvious, but I think it gets forgotten surprisingly often.
A language model is useful precisely because it can deal with inputs we cannot completely describe in advance.
Language is messy. Intent is messy. Relevance is messy. Documents are inconsistent. People describe the same thing in twenty different ways. Sometimes there simply is no clean rule that maps an input to the answer we want.
That is where models become interesting.
Give me thousands of pieces of content and ask which ones are semantically related to a new article. That is a good place for embeddings.
Give me an email written in whatever way a human happened to write it and ask me to extract the underlying request. That may be a good place for a language model.
Give me several plausible options with incomplete information and ask me to rank them using context that is difficult to express as a fixed formula. Again, potentially useful.
These are problems involving ambiguity.
The model is doing something valuable because writing every possible rule would either be impossible or produce something far more brittle than the model.
But a strange thing happens once people see AI solving those problems.
They start giving it problems that were never ambiguous in the first place.
If you already know the rule, write the rule
Suppose a request can only move to approved after a specific person approves it.
You do not need an agent to decide whether the request should move to approved.
You need an if.
Suppose users are allowed to perform certain actions based on their role.
That is not a reasoning problem. It is access control.
Suppose a task should be considered complete only when a URL returns 200 and contains the expected value.
That is not something I want an LLM to "judge."
Make the HTTP request. Parse the result. Check the condition.
There is a category of problems where the correct answer is already completely known. In those cases, replacing ordinary software with AI usually makes the system worse.
You take something deterministic and make it probabilistic.
You take something cheap and make it expensive.
You take something easy to test and make it difficult to reproduce.
You take a bug that would have produced the same wrong result every time and replace it with one that appears only occasionally.
That is not intelligence. It is just uncertainty added to a problem that did not have any.
Models handle uncertainty. Software handles guarantees.
This has gradually become one of the ways I think about AI systems.
I am happy to let a model interpret.
I am much less happy to let it enforce.
A model can decide which category an unusual request probably belongs to. Code can decide what categories are actually allowed.
A model can suggest an action. The system can determine whether that action is permitted.
A model can extract a URL from unstructured text. The system can verify that the URL exists.
A model can reason about whether two pieces of content are relevant. The system can still enforce hard constraints around where links are allowed, how many can exist, and whether the final placement is actually live.
This is usually where AI becomes useful to me.
Not as the system itself, but as a probabilistic component inside a system whose important boundaries remain explicit.
The model deals with the part we cannot cleanly encode.
Everything around it should be as boring as possible.
An agent saying "done" does not mean the job is done
Agents make this distinction even more important.
It is surprisingly easy to build an agent that looks capable in a demo.
Give it a task. Let it reason. Give it some tools. Watch it call them. Eventually it produces something that looks like a completed result.
The harder question is what happens after that.
Did it actually complete the task?
Did the external system accept the change?
Did it modify the correct thing?
Did it partially succeed?
Can we safely retry it?
What if it performs the same action twice?
What if the tool call succeeds but the response never reaches the agent?
What if the model concludes that something happened when it did not?
At that point, the interesting engineering is no longer the prompt.
It is state, idempotency, permissions, retries, verification, auditability, and failure recovery.
The AI can decide what it wants to do.
The surrounding software still needs to know what actually happened.
I think this is one reason there is such a large gap between an impressive agent demo and an agent I would trust with a real operational process.
Autonomy is easy to demonstrate.
Reliable autonomy is a systems problem.
Sometimes the fastest solution has no AI in it
There is also a practical reason I care about this.
I like shipping quickly.
Using AI where it is unnecessary often slows that down.
A deterministic solution gives you a smaller surface area. There are fewer behaviours to evaluate, fewer strange outputs to account for, less infrastructure, less latency, fewer external dependencies, and usually much clearer failures.
If I can solve something with a database constraint in five minutes, I am not going to spend an afternoon building an agent that remembers not to violate it.
If a regular expression reliably extracts a value from a fixed format, I do not need a language model to read it.
If ten explicit rules cover the domain well, I would rather have ten rules I can inspect than a classifier I now need to evaluate and monitor.
This is not resistance to AI.
It is using AI where its cost buys something.
The point of an AI system is not to contain as much AI as possible.
The point is to solve the problem.
The boring parts matter more than people think
A lot of the AI systems I like are mostly normal software.
There is a database.
There are queues.
There are APIs.
There are state transitions.
There are permissions.
There are logs.
There are deterministic checks.
And somewhere inside that system is a model doing the one thing that would have been awkward to implement without one.
That does not make the system less sophisticated.
If anything, I think it reflects a better understanding of what the model is actually for.
You do not ask a brilliant but occasionally unreliable colleague to remember your database invariants.
You give them the problem that requires judgment.
The rest gets written down.
The question I care about
When I look at a problem now, I try not to start with:
How can I solve this with AI?
That question already assumes too much.
A better question is:
Where does this problem actually require uncertainty?
Sometimes the answer is everywhere.
Sometimes it is one small step.
Sometimes there is no meaningful uncertainty at all, and the best AI architecture is no AI architecture.
Knowing the difference matters.
Models will keep getting better. Agents will become more capable. Tasks that require careful prompting today will probably become trivial.
But I do not think that changes the underlying engineering judgment.
The better the models become, the more tempting it will be to use them for everything.
And the more valuable it will become to know when not to.
all posts