The Deterministic Layer Under the LLM

Where we deliberately do not use a model: deterministic, testable backstops at the boundaries where correctness is non-negotiable.

The industry talks about legal AI as if it were all model. Pick the biggest one, prompt it well, wrap it in a nice interface, and ship. That framing is wrong in a way that matters for anyone whose signature goes on the work product.

A language model is the right tool for exactly one class of problem: language. Reading a contract, weighing two arguments, phrasing a holding, synthesizing five passages into one paragraph. Nothing else in our stack does that, and nothing else could. So the model sits at the center of the system, and it earns its place there.

But a model is a probabilistic tool. It produces the most plausible next token, not the provably correct one. For most of what it does, plausible is exactly what you want. For a specific and identifiable set of moments, plausible is not good enough, because a wrong answer there is not a lower-quality answer. It is a fabricated citation, a misrouted request, a quote that was never in the document, a crash on a piece of dirty data.

Our design thesis is simple. Use the probabilistic tool for what only it can do. At every boundary where a mistake is not negotiable, put a deterministic backstop underneath it: code that cannot itself hallucinate, that runs in milliseconds, and that you can prove correct with ordinary unit tests. This post is a tour of where we deliberately do not use a model, and why that makes the system more trustworthy, not less.

The shape of it

Here is the pattern, drawn as a pipeline. The engine in the middle is probabilistic. Everything touching the user is deterministic.

Loading diagram...

None of the boxes on the outside call a model. They are string logic, regular expressions, and type coercion. Each one is a place where we decided that correctness had to be a guarantee rather than a probability, and where a guarantee was actually achievable in code. Let me walk through them one at a time, because the reason each is deterministic is more interesting than the fact that it is.

A fabricated citation is removed, not judged

When an answer cites its sources inline, it writes markers like [1] or [3] that point at the passages we retrieved. Sometimes a model writes [7] when only five passages were retrieved. That marker points at nothing. It is a fabricated citation, and it is precisely the failure that has put lawyers in front of judges.

You could ask a second model whether the citation looks trustworthy. We do not, because there is nothing to judge. A citation to source seven when there are five sources is not a matter of opinion, it is a matter of counting. So the check is arithmetic: parse every marker, expand its numbers, and compare each against the count of retrieved sources.

The rule is strict in one direction on purpose. Only an out of range index is treated as fabricated, so a valid citation is never touched. That is what makes the check safe to run on every answer with zero false positives: it cannot remove a real citation, because a real citation is in range by definition. A grouped marker like [2,7] against five sources becomes [2], keeping the good half. A lone [7] is removed cleanly, and the check even reasons about the surrounding whitespace so it never leaves a double space or merges two words together.

This runs before the answer reaches the reader, and it runs in about the time it takes to scan the text once. The deep dive on this gate, including how it composes with a corrective regeneration when a whole answer's citations fail, is in Catching a Fabricated Citation Before It Reaches the Lawyer. The point for this essay is narrower. We did not make citation integrity more accurate by using a bigger model. We made it a property of the code by refusing to use a model at all.

A markdown blockquote is a promise. It tells the reader these are the exact words from a source. When an answer dresses up paraphrased or invented clause text as a verbatim blockquote, that is a citation grade fabrication, because the reader sees exact language that was never retrieved.

The backstop is the same shape. Concatenate the retrieved source text, normalize it, and check whether each verbatim blockquote actually appears in it, by literal substring or high fuzzy overlap. Anything that does not match loses its blockquote marker and renders as ordinary prose, so it stops claiming to be an exact quote. It never touches callout boxes, which are context rather than quotations, and it leaves short fragments alone to avoid false positives.

There is no model in this loop and there does not need to be one. Whether a string appears in another string is a decidable question, and decidable questions do not belong to a probabilistic tool.

A misroute is caught by a guard the model cannot overrule

Not every deterministic backstop sits after the model. One of the most important ones sits in front of it, deciding which engine the request even reaches.

When a user is talking to a pinned document, the request might be a targeted question, or it might be a whole document operation like summarize, extract every field, or review clause by clause. Those go to completely different engines, and sending a request to the wrong one produces a confidently wrong result. We use a model as the authority on this classification, because phrasing is subtle and an eleven way route is genuinely a language problem. The full design, including a free stress sweep of more than a thousand labeled prompts, is in Sending Rewrite This Transcript, NOT a Summary to the Right Engine.

But the model classifier has known, reproducible failure families, and for those we do not argue with it politely. We overrule it with code. When a user writes rewrite the transcript in third person, NOT a summary, the model has a habit of hearing the word transcript and the word summary and routing to the summarizer, which is the one thing the user explicitly forbade. So a regular expression catches the rewrite and transform verbs, catches the explicit negation of a task, and short circuits the whole route to the safe inline path before the model classifier ever runs.

The design note in the router says it plainly: this is a deterministic override the model cannot beat. That is the deliberate move. A confirmed misroute does not become a prompt tweak we hope holds. It becomes a permanent guard with a unit test, so the same request routes the same way forever, no matter what the model does that day. A probabilistic classifier is the right default for a nuanced multi way decision. A deterministic guard is the right floor underneath it, and the floor wins.

A matrix cell's quote is verified by substring, not vibes

The Document Matrix is a spreadsheet where every cell is an extraction from a single document, with a citation. This is the surface where being wrong is least acceptable, because a cell reads like a fact in a table, stripped of all the hedging a sentence can carry.

So the cell is built to make fabrication structurally hard. The model is given a strict schema that lets it emit only two outcomes, an extracted answer or a plain not found, with no third path to wander down. Then every citation it returns runs through a deterministic check: the quoted text must be a literal, normalized substring of the exact passage it cited. A quote that is not actually present is dropped. If a claimed extraction has no citation left standing after that, the whole cell is downgraded to not found rather than shown as an answer. There is even a guard for the case where a dropped quote still leaked into the human readable answer text, so a fabricated phrase cannot ride along after its citation was removed.

That substring check is a few lines of string logic, and it is the entire difference between a cited number and a decorative one. The full walk through, including the conditional columns and idempotent re-runs, is in A Spreadsheet Where Every Cell Is a Cited, Verified Extraction. We could have asked a model to rate its own confidence in each quote. Instead we ask a question with a definite answer, is this text in that passage, and let string comparison answer it.

Dirty data is coerced by rules, not guessed

The last boundary is not about hallucination at all. It is about the world being messier than a schema.

US statutory metadata is not clean. Most title numbers are integers, but Alabama's criminal code lives under Title 13A, an alphanumeric identifier that a strict integer field rejects with a server error. Some rows carry amendment years that were scraped from sunset clauses and land in the future, or before the Republic existed. A model could be asked to clean each field, but that would be slow, expensive, and itself a source of new errors on the one job that most needs to be boring.

So we degrade gracefully with rules. A lenient integer coercion accepts an int, a numeric string, or an integral float, and turns anything genuinely non numeric into a null instead of raising. Title numbers coerce to strings so both 26 and 13A serialize cleanly. An amendment year sanitizer drops anything outside a plausible window, from the founding era to the current year, and re-derives the latest amendment from what survives. The deeper treatment, including the enum drift guards, is in The Law Is Not Clean Data. None of it guesses. A dirty field becomes a safe, honest null or a normalized string, deterministically, every time.

The principle, and why it pays

There is one more place the pattern shows up, and it captures the whole philosophy. Our answer verifier runs in two phases, and the first phase is deterministic: exact substring and fuzzy matching that resolves most claims with no model call at all. Only the genuinely uncertain middle, and anything carrying a number, is escalated to a model reading the claim against its source. The measurement architecture behind that split is the subject of our first post, What Our Citation Verifier Actually Checks.

Put the boundaries together and the general rule is clear. Reach for the probabilistic tool when the question is a language question, one with no crisp right answer, where judgment and synthesis are the whole point. Reach for deterministic code when the question has a definite answer: is this index in range, is this string in that string, is this year possible, does this request forbid the route it is about to take. Do not use a model to answer a question that arithmetic or string search can answer, because a model can only make that answer less certain.

This is not a compromise we accept reluctantly. It is faster, because a substring check runs in microseconds where a model call runs in seconds. It is cheaper, because the deterministic gates cost nothing per request. It is testable, because you can write a unit test that proves strip removes exactly the fabricated markers and nothing else, and that test will still be green next year. And it is more trustworthy at the edges, precisely because the trust does not depend on a prompt holding or a model behaving. A model sits at the center of this system and does the work only it can do. The reason you can rely on the edges is that we did not put a model there.

Test it yourself, and one question for any vendor

You can probe for this from the outside in a few minutes.

Ask a tool for three cases supporting an unusual proposition, each with a citation, then check every citation against a free source. A system with a deterministic citation floor either retrieves real authority or removes what it cannot stand behind. The tell of a weak one is a perfectly formatted citation that points at nothing.

Then upload a short document and ask it to quote an exact clause verbatim, and compare the returned quote character for character. A system that verifies quotes by substring reproduces the words or declines. The tell is a smooth paraphrase presented inside quotation marks as if it were the real text.

And carry one question into any vendor conversation. Which of your safety checks are deterministic, and which are a model judging another model. A deterministic check can be described exactly, unit tested, and proven to have no false positives in the direction that matters. A model judging a model is one probabilistic system grading another, and it inherits the uncertainty of both. A vendor who can point to a deterministic layer under the language model is telling you where their guarantees actually live. A vendor who answers that the model checks itself is telling you they have confidence, not a floor.

New legal AI guides, weekly.

Priyansh Khodiyar

Priyansh Khodiyar

Co-Founder & CTO

Priyansh leads engineering and AI at Vaquill, from the matter workbench to drafting, document comparison, document matrix, and citation-verified research.

Research, review, and draft, with a source on every answer.

Vaquill AI reads your documents and knows the law. Every answer shows where it came from. 7-day free trial.