Skip to content

10 – Reliability and Deterministic Boundaries

LLM-based systems combine two different worlds:

probabilistic model behavior
          +
deterministic software behavior

Reliable AI applications work well when those boundaries are explicit.

The core rule is:

Use the LLM for interpretation, generation, ranking, and flexible reasoning. Use deterministic software for contracts, permissions, invariants, money, identity, persistence, and side effects.

Why this matters

A normal function is expected to follow its code path exactly.

result = calculate_vat(1000, 0.27)

Given the same inputs and code, the application expects the same result.

An LLM call is different:

same prompt
same model
same context
    ↓
possibly different wording or decision

Even when model behavior is very stable, treating it as perfectly deterministic creates fragile systems.

Decide what the model is allowed to decide

A useful architecture question is:

What requires judgment?
What requires guarantees?

Example: support-ticket routing.

Reasonable LLM responsibility:

classify message as:
- billing
- technical
- account
- other

Deterministic responsibility:

if category == "billing":
    assign billing queue

The LLM interprets language. The application performs the actual routing rule.

Do not encode critical invariants only in prompts

Weak design:

System prompt:
"Never approve refunds above 500 EUR."

This may help model behavior, but it should not be the real enforcement layer.

Better:

if refund.amount > 500:
    require_manager_approval()

The prompt can explain policy to the model, but deterministic code enforces it.

Structured output is a boundary

Suppose the model classifies a request.

Instead of:

"This seems quite urgent and probably related to billing."

prefer a contract such as:

{
  "category": "billing",
  "priority": "high"
}

Then validate it before using it.

LLM
 ↓
structured result
 ↓
schema validation
 ↓
business validation
 ↓
application logic

This limits the amount of free-form model behavior entering the deterministic core.

Validation has multiple layers

Consider:

{
  "currency": "EUR",
  "amount": 1000000
}

It may be valid JSON and valid against a schema.

But business logic can still reject it.

Think in layers:

1. Syntax / transport validity
2. Schema / type validity
3. Business-rule validity
4. Authorization validity
5. Side-effect execution

Do not collapse these into one prompt.

Retries

Retries are useful for transient failures, but dangerous when used blindly.

Possible retryable failures:

  • model timeout,
  • provider 5xx,
  • temporary rate limit,
  • network error,
  • temporary tool outage.

Not automatically retryable:

  • invalid user input,
  • permission denied,
  • business-rule violation,
  • repeated malformed logic caused by a bad prompt,
  • a non-idempotent side effect that may already have succeeded.

A useful retry policy distinguishes failure classes.

failure
  ↓
classify
  ├── transient → retry
  ├── permanent → stop
  └── ambiguous side effect → reconcile before retry

Idempotency

Idempotency becomes essential when agents or tool-enabled systems can repeat actions.

Imagine:

LLM → create_payment(100 EUR)
network timeout
application does not know whether payment succeeded
retry

Without idempotency, the customer might be charged twice.

A safer pattern:

create_payment(
    amount=100,
    idempotency_key="order-123-payment"
)

The external system can recognize the repeated request as the same logical operation.

This is not specifically an AI principle. AI systems simply make it more important because retries and loops are common.

Timeouts and budgets

Every model or tool call needs limits.

Examples:

  • request timeout,
  • maximum tool-call count,
  • maximum loop iterations,
  • maximum total elapsed time,
  • maximum token usage,
  • maximum cost per task.

Without explicit limits:

agent
 ↓
retry
 ↓
search
 ↓
retry
 ↓
tool
 ↓
search
 ↓
...

can become an unbounded process.

Stop conditions

Agentic workflows need deterministic stop conditions around probabilistic reasoning.

Examples:

stop if task completed
stop if max_steps == 10
stop if cost > budget
stop if tool returns terminal error
stop if human approval is required

Do not rely only on the model deciding that it has done enough.

Fallbacks

Fallbacks can exist at several levels.

Model fallback

primary model unavailable
       ↓
secondary model

Behavior fallback

AI classification confidence/evaluation check fails
       ↓
manual queue

Tool fallback

semantic search unavailable
       ↓
keyword search

Product fallback

AI answer cannot be supported safely
       ↓
show source documents or escalate to human

A fallback should be intentionally designed, not random emergency code.

Confidence is tricky

Do not assume that a model-generated number such as:

{
  "confidence": 0.98
}

is a calibrated probability.

The model can produce a confidence field because you asked for one, but that does not automatically mean requests labeled 0.98 are correct 98% of the time.

If confidence matters, calibrate it empirically using evaluation data or derive confidence from more reliable signals.

Example: invoice extraction

Goal: extract invoice data from uploaded text.

Model output:

{
  "invoice_number": "INV-2026-991",
  "currency": "EUR",
  "total": 1250.50
}

Reliable flow:

uploaded document
      ↓
LLM extraction
      ↓
schema validation
      ↓
check currency against allowed list
      ↓
check total >= 0
      ↓
check invoice number uniqueness
      ↓
possibly verify against source text
      ↓
persist domain object

The model performs fuzzy extraction. The application protects invariants.

Example: code-generation agent

The agent proposes a code change.

Weak flow:

LLM writes code
 ↓
merge

Better flow:

LLM writes code
 ↓
formatter
 ↓
compiler / type checker
 ↓
unit tests
 ↓
integration tests
 ↓
static analysis
 ↓
review / policy checks
 ↓
merge

The more deterministic verification you can put after generation, the more safely you can automate.

This is one of the strongest patterns in AI-assisted software engineering:

Let the model generate candidates. Let deterministic systems verify what can be verified.

Failure recovery

Reliable systems make failure state explicit.

Instead of:

something failed → ask model to try something else

track structured state:

{
  "step": "create_ticket",
  "attempt": 2,
  "status": "failed",
  "error_code": "RATE_LIMIT",
  "retryable": true
}

This lets orchestration logic, not just model intuition, determine what happens next.

Observability

For production systems, record enough data to understand failures and cost without leaking sensitive content.

Useful signals:

  • model name/version,
  • prompt/template version,
  • request latency,
  • input/output token counts,
  • tool calls,
  • tool latency,
  • retry count,
  • finish reason,
  • validation failures,
  • evaluation metrics,
  • total task cost.

Without observability, AI reliability problems often look like random anecdotes.

Reliability is system-level

Do not ask only:

"How accurate is the model?"

Ask:

What happens when the model is wrong?

A model with imperfect accuracy can support a highly reliable application if mistakes are bounded, detected, validated, or safely recoverable.

A stronger model does not remove the need for good system design.

Practical boundaries

Good LLM candidates:

  • summarize text,
  • classify ambiguous language,
  • extract fuzzy information,
  • generate drafts,
  • rank candidates,
  • propose plans,
  • interpret user intent.

Good deterministic-code candidates:

  • authorization,
  • monetary calculations,
  • schema validation,
  • database constraints,
  • retry policy,
  • workflow limits,
  • rate limiting,
  • state transitions,
  • final safety checks.

Mental model

Probabilistic intelligence
        ↓
controlled interface
        ↓
deterministic guardrails
        ↓
real side effects

The goal is not to make the LLM deterministic.

The goal is to design a system where probabilistic behavior is used where it creates value and deterministic boundaries protect everything that requires guarantees.