Why LLM Decisions Should Be Deterministic
July 13, 2026 · By Justyn Larry
// TL;DR
I originally treated deterministic boundaries around LLMs as a consistency mechanism. I now think their real value is auditability. If the system’s decisions are made by deterministic code rather than the model, every decision has a reproducible implementation. The LLM can explain that decision to humans, but it should never be the source of the decision itself.
In two previous posts I argued for keeping narration and decision-making separate. One covered monthly reporting. The other covered a real-time alert annotator. Both focused on consistency. This post argues that consistency is only the visible benefit; auditability is the deeper one. By auditability, I mean that a third party can inspect how a decision was reached and reproduce it from the implementation rather than relying on an after-the-fact explanation.
// THE DETERMINISTIC LAYER
The alert annotator classifies every alert into one of eight values, enforced in Python against a fixed set, not requested in a prompt. If the model’s output does not match one of the eight strings exactly, the field falls back to unknown rather than accepting whatever the model produced. That validation step is more important than the enum itself.
ALLOWED_CAUSES = {
"memory_pressure", "cpu_saturation", "disk_pressure",
"service_unavailability", "network_issue",
"configuration_error", "external_dependency", "unknown",
}
def resolve_cause(model_output: str) -> str:
cause = model_output.strip()
if cause not in ALLOWED_CAUSES:
return "unknown"
return cause
Given the same input, this function always produces the same output. That means every classification is reproducible from the source code alone.
This is the shape of the check, not a copy of the production code, but the principle is that you should never trust an external system’s output by letting it pass through unchecked. This is not an LLM-specific idea, it is the same discipline that should apply to a third-party webhook payload or an API response before it touches your data model. The model just happens to be the least predictable external system I integrate with, which makes the validation step the most visibly valuable.
I originally wrote about this as a consistency fix, and failed to discuss its full value. Before the enum existed, the same alert produced different category strings across separate runs, which made cross-tenant pattern analysis impossible. What the validation step actually guarantees is that every classification belongs to a bounded, deterministic set of outcomes. resolve_cause() is a pure function, and every valid result is reproducible from its implementation. It creates consistency in the input and output every time, and the entire decision is just sixteen lines of Python.
Traditional pipeline:
Metrics | v Deterministic rules | |-- classification | v LLM narration | v Client
LLM-centric pipeline:
Metrics | v LLM | |-- classification |-- explanation | v Client
The important distinction isn’t whether an LLM appears accurate most of the time. It’s whether a reviewer can reproduce the decision months later from the same inputs. In the first architecture, the decision exists independently of the model’s narration. In the second, the classification and its explanation originate from the same probabilistic process, making them difficult to separate during an audit.
// INDUSTRY TRENDS
It turns out a great deal of current AI governance work is aimed at exactly this property, approached from the opposite direction. A large part of the LLM governance tooling market exists because production language model behavior does not offer the guarantee classical software does. The same prompt can produce different answers across runs, so teams are building trace-level evidence systems, output evaluators, and audit logging specifically to reconstruct what a probabilistic system did and why after the fact.
The regulatory backdrop makes the stakes explicit rather than abstract. Under the EU AI Act, certain classes of LLM application are treated as high-risk and come with mandatory logging and human-oversight requirements, with an explicit standard that records must be sufficient to reconstruct the system’s operation, not just gesture at it. NIST’s AI Risk Management Framework leans on the same assumption from a different angle, treating a reliable and auditable record of system behavior as a prerequisite for its governance functions.
None of that applies to the projects that I’m working on directly. Advisory infrastructure monitoring for small server fleets is not a high-risk category, and I am not building toward EU AI Act compliance. But the underlying problem is the same problem, just at a different scale and a different level of legal consequence. If a decision matters enough that someone might reasonably ask “why did the system do that,” the honest answer needs to survive more scrutiny than a model’s own account of itself.
// SELF-REPORTING IS NOT AN EXPLANATION
You can ask a language model why it produced a given output, and it will give you a fluent, plausible answer, but it will not give you the actual causal mechanism. The explanation is generated during a new inference over the conversation history, not by inspecting the internal computation that produced the original answer. The model generates a plausible explanation rather than retrieving the causal process behind its earlier output. The model will make a guess and present it as a first-hand account.
Recent AI governance research states the practical consequence of this directly, stating that systems that need genuinely reproducible decisions should not rely on a probabilistic layer alone, they should sit a deterministic enforcement layer underneath it as a secondary safeguard. That is a formal way of describing something a lot of people building on LLMs arrive at independently once they hit production. I arrived at it because an enum kept coming back spelled three different ways, before I had even thought about what the industry was doing. Other people are arriving at it because a regulator asked for a record that would hold up. We’re both coming to the same conclusion, but the reasons behind it are different.
Classical software doesn’t explain itself, we inspect the implementation. A pure function doesn’t tell us why it returned cpu_saturation, we read the code that produced that output. LLMs invert that relationship. They readily generate explanations, but those explanations are themselves model outputs rather than evidence of the underlying computation.
// WHAT DOES NARRATION ACTUALLY DO?
None of this makes the narration layer pointless, it just refines its allowed job. The prose the model writes for a client report, or the plain-English line attached to an alert, is still probabilistic. I can log exactly what it said. I cannot claim a rigorous account of why it phrased something one way over another, but I do not need one, because that text is not load-bearing. It explains a decision, but it doesn’t make one. If the narration layer disappeared entirely tomorrow, every report and every alert would still carry a correct, if blunter, classification, because the classification does not depend on the prose existing.
That is the actual shape of the boundary. Not “the model is untrustworthy so keep it away from important things,” which is too broad to be useful, but “know exactly which outputs in your pipeline need to be reproducible, and make sure none of those outputs pass through a step you cannot validate against a fixed answer.”
// WHERE THIS IS HEADING
Before the narrative layer ships to a client, it needs a short, plain statement of what the model is permitted to produce, how its output is labeled in the report, and what happens when it is wrong or unavailable. If a system needs to justify a decision months later, the justification should be found in deterministic code and recorded inputs, not in asking the model what it thinks it did. The model narrates a state that was already decided; it never gets to decide the state itself.
// RELATED READING
- Adding an LLM Narration Layer to Prometheus and Grafana. Where this series started, on the monthly report pipeline.
- The LLM Narrates. The Code Decides. The harder real-time case, on the alert annotator.