Keep the decision engine deterministic: separating scoring from LLM orchestration
When an AI system has to rank, score, or decide, don't let the LLM do the math. Separate a deterministic decision engine (weighted scoring, MCDA) from the probabilistic orchestration that handles messy input.
A recurring architecture mistake in AI systems: asking the LLM to do the final scoring, ranking, or arithmetic. LLMs are for handling ambiguity and unstructured language; deterministic code is for scoring and deciding. Separate those two layers and the system gets both more reliable and more explainable — pointing them at each other's jobs is how you get a system nobody can trust or audit.
Two layers, two jobs
Split the system in two. The orchestration layer (LLM-driven) takes messy, unstructured input — documents, emails, free text — and turns it into clean structured data through extraction, validation, and classification. The decision engine (plain deterministic code) takes that structured data and computes the outcome — the score, the ranking, the decision — with auditable logic. The LLM never does the final math; it just prepares the inputs the math runs on.
Why not let the LLM decide?
- Non-determinism — the same inputs can rank differently across two runs, which is disqualifying for a decision that has to be defensible.
- No auditability — you can't show why it ranked A above B; a decision you can't explain is a decision you can't stand behind.
- It's bad at arithmetic — weighted sums and threshold checks are exactly what code does perfectly and models do unreliably.
A deterministic engine is reproducible, explainable, and correct by construction — which is what a real decision requires.
MCDA: weighted multi-criteria scoring
The decision engine is often a multi-criteria decision analysis (MCDA). You score each option against defined criteria, apply section-level weightings because some criteria matter more than others, filter out anything that fails a mandatory constraint, and aggregate the weighted scores into a ranking. It's transparent, tunable decision math — you can point at the weights and the constraints and explain the result — and it belongs in code, not in a prompt.
Judgment at the leaves, arithmetic at the root
Sometimes a single criterion genuinely needs judgment — 'does this answer partially meet the requirement?'. That's fine: let the LLM produce the per-criterion classification (a Yes/No/Partially label with a justification), validated against a schema (the structured-outputs post). But the aggregation and ranking over those labels still happen deterministically. Judgment at the leaves where language lives, arithmetic at the root where the decision is made — which is the 'deterministic scaffolding around probabilistic steps' principle (the agents-vs-workflows post) applied to decisions.
Let the LLM read the messy input and judge the fuzzy calls. Never let it do the final sum. A ranking you can't reproduce or explain isn't a decision — it's a guess with extra steps.