All posts
AI & ML/6 min read/Sep 7, 2026

Making AI Recommendations Citable: The Evidence Model

An AI that says your database has reliability issues, with no source, no rule, nothing to point to, isn't a co-pilot. It's a magic 8-ball with a confidence problem. The fix is structured metadata that makes every recommendation traceable back to what actually produced it.

Cover image for Making AI Recommendations Citable: The Evidence Model

Series: Building Backarch, engineering decisions from building backarch.com

"Your architecture has reliability issues." An AI that says this without explanation isn't a co-pilot. It's a magic 8-ball with a confidence problem. The difference between a tool engineers trust and one they quietly ignore is whether it shows the reasoning, not just the conclusion.

AI assertion vs evidence model comparison
AI assertion vs evidence model comparison

Engineers don't accept assertions in code reviews. They ask for evidence, the reasoning, and the cases where the answer might be wrong. The AI tool should meet the same bar.

Trust is an engineering problem

A recommendation without a source is an assertion. You can add a confidence percentage, but without something to point to (a rule that fired, a price that was checked, a pattern that matched) it's confident prose with nothing behind it.

The failure mode is subtle: engineers don't loudly reject unsourced AI recommendations. They accept them uncritically the first few times, then quietly stop using the tool after the third or fourth time something was wrong. Trust erodes silently. By the time you notice the adoption drop, you've already lost the users who would have been most valuable: the skeptical, rigorous ones who interrogate their tools.

The evidence model is the structured metadata that makes AI recommendations citable. Every response carries enough information to trace how each conclusion was reached:

{
  "answer": "Your database is a single point of failure.",
  "findings": [
    {
      "id": "f_spof_db",
      "title": "Database has no replica or backup configuration",
      "severity": "high",
      "category": "reliability",
      "affected_nodes": ["postgres_1"],
      "evidence": [
        {
          "source": "health_rule",
          "ref": "reliability.db_spof",
          "summary": "One database node present; no replica or backup marker exists."
        }
      ],
      "recommendation": "Add a read replica and a backup policy node.",
      "confidence": "high"
    }
  ],
  "sources_used": ["canvas", "constraints", "pricing_db", "health_rules", "pattern_library"],
  "tool_calls": [
    { "tool": "health_score", "status": "success", "duration_ms": 41 },
    { "tool": "price_lookup", "status": "success", "duration_ms": 88 }
  ],
  "assumptions": ["Traffic is read-heavy. No write ratio was provided."],
  "confidence": "medium"
}

This isn't surfaced in full by default. The default view shows the finding and the affected node. The expanded view shows sources, assumptions, and the tool trace. The breadcrumbs are there when the engineer wants to trace causality.

Three cooperating systems, separated by role

What makes this evidence credible is a strict separation of what each system is responsible for.

The deterministic engine (health rule checks, pricing lookups, constraint validations) produces facts. The numeric health score comes from here, not from the LLM. The same diagram always produces the same score, the same issues list, and the same action labels. Every rule is testable in a unit test with a plain Python dict.

The typed retrieval tools query the pattern library and past ADRs directly against Postgres, no embeddings pipeline involved, and produce context. The LLM doesn't guess what a circuit-breaker pattern recommends; it calls pattern_suggest and gets the actual document. The source is traceable.

The LLM: explains, prioritises, proposes actions, generates rationale. It never invents authoritative facts. If it needs a price, it calls price_lookup. If it needs a health score, it calls health_score. The LLM is the reasoning layer. Facts come from the other two.

The boundary is strict: the LLM cannot compute health scores. The rule engine cannot write explanations. Conflating these roles is where AI-first scoring goes wrong. Using an LLM to compute a score means you can't reproduce it, can't unit-test it, and can't explain it to a skeptical user.

This three-part separation is how the AI assistant at backarch.com produces findings that engineers can trace rather than just accept.

The SSE stream makes the tool trace visible in real time

The streaming response makes the reasoning visible as it happens:

data: {"type": "text", "delta": "I found two reliability risks in this diagram."}

data: {"type": "tool_use", "tool": "health_score", "input": {"diagram_id": "abc123"}}

data: {"type": "tool_result", "tool": "health_score", "output": {"score": 62, "issues": [...]}}

data: {"type": "text", "delta": "The most critical: your database has no replica configured."}

data: {"type": "finding", "finding": {"severity": "high", "title": "Database SPOF", ...}}

data: {"type": "action_preview", "actions": [{"type": "add_node", "node_type": "rds_replica"}]}

data: {"type": "done", "requires_user_confirmation": true}
SSE stream timeline showing tool calls in sequence
SSE stream timeline showing tool calls in sequence

The source chips in the UI (Canvas, Constraints, Pricing DB, Health Rules, Pattern Library, ADRs) represent systems that were actually consulted to produce this answer. Each chip corresponds to a tool_call in the sources_used array. Engineers debug by tracing causality; the chips are the trace made clickable.

Changes require confirmation; the version is the undo stack

Before any AI-suggested change touches the canvas, the user sees a preview: the before/after diff, the health score delta, the estimated cost impact. They click Apply. Then and only then does the mutation happen.

Every AI-applied change creates a named diagram_versions row:

"AI suggestion: add Redis cache"
"AI review: add queue and DLQ"
"AI optimisation: replace Kafka with SQS ($340/mo savings)"

The version history is the undo stack. The version name is the audit trail. Rolling back an AI change is exactly the same operation as rolling back a manual one: click the published version, discard the current draft.

The AI never has to be perfect.

It just has to be reviewable and reversible. The fear that "AI will make changes I can't undo" is a UI design problem, solved by making the confirmation and undo story explicit.

Assumptions surface when confidence is limited

Some constraints the system doesn't know. Write/read traffic ratio. Expected growth rate. Deployment frequency. When the AI makes an assumption about missing information, it surfaces it:

"Assumptions: Traffic is read-heavy. No write ratio was provided.
If your workload is write-heavy, the cache recommendation may not apply."

An assumption statement isn't a hedge. It's a signal about what additional context would improve the recommendation. Engineers can either accept the assumption or provide the missing constraint, at which point the recommendation updates.

This is different from a confidence percentage. A confidence of "87%" means nothing to an engineer who wants to understand the reasoning. An explicit assumption means: "here's what I don't know, and here's how it would change the answer."


The evidence model at backarch.com came from observing what happens when an AI gives a recommendation without sources: the engineer either accepts it uncritically (dangerous) or ignores it entirely (useless). The goal is a third option: evaluate it the same way you'd evaluate a suggestion in a code review, by looking at the reasoning.

An AI that shows its work earns trust incrementally, one cited recommendation at a time. An AI that asserts without evidence earns distrust the first time it's wrong.

PK
Piyush Kumar
CO-FOUNDER · BACKARCH

One engineering deep-dive,
every other week.

No fluff. Frontend, backend, infra, and AI — real post-mortems and walkthroughs from engineers shipping in production.