Jev recipe / reliability engineering
LLM Fallback Strategy: The Confidence-Gated Chain
Reliability engineering for LLM systems is more than retry. Gate every answer on calibrated confidence: auto-execute when high, re-ask a stronger model when borderline, escalate to a human when low.
Build the confidence-gated fallback chain in six steps
{
"fallback_action": {
"type": "choice",
"instructions": "Decide the next action for this proposed answer",
"criteria": {
"execute": "High confidence and reversible — act automatically",
"escalate_model": "Borderline confidence — re-ask a stronger model",
"human_review": "Low confidence or irreversible — route to a person"
}
},
"irreversible": {
"type": "noul",
"instructions": "Would acting on this answer be hard to undo (payment, email, deletion)?"
}
}Fallback strategy benchmark: confidence-gated chain vs retry, cascade, human-only
one number per answer picks the lane
retry watches 5xx/timeouts, cascade watches self-reported scores, human-only waits for complaints
only the 0.60–0.85 middle band adds a ~2–4s stronger-model re-ask
retry adds 2^n backoff, cascade re-generates at every hop, human queues take minutes to days
$0.042/M at the gate; the premium model bills only for the middle band
retry re-bills output tokens for the same wrong answer, cascade pays premium prices per hop, human time dwarfs both
sub-threshold confidence routes to a human, never to a wrong auto-action
retry repeats the identical wrong answer, cascade degrades quality silently, human-only drowns the queue
every hop emits answer + confidence + lane; thresholds live in code
failures hide inside latency graphs and quality drift, with no per-decision confidence trail
Side-by-side code: blind retry vs confidence-gated chain
import time
import requests
def generate_with_retry(prompt: str, max_retries: int = 5) -> str:
# Blind retry: the ONLY signal is transport health. A confidently
# wrong answer passes on attempt 1 and never enters the retry path.
for attempt in range(max_retries):
try:
resp = requests.post(
"https://api.vendor-llm.example/v1/chat/completions",
json={
"model": "cheap-model",
"messages": [{"role": "user", "content": prompt}],
},
timeout=30,
)
resp.raise_for_status()
return resp.json()["choices"][0]["message"]["content"]
except (requests.Timeout, requests.HTTPError):
time.sleep(2 ** attempt) # 1s, 2s, 4s, 8s ... up to ~31s wasted
return "" # silent empty-string failure after the storm
# Typical path: 1500-3000ms of generation, output tokens billed per attempt,
# and zero protection against a well-formatted wrong answer.import requests
JEV_ENDPOINT = "https://api.typesafe.ai/v1/jev/evaluate"
AUTO_EXECUTE_CONFIDENCE = 0.85 # >= 0.85 -> act automatically
QUESTIONS = {
"fallback_action": {
"type": "choice",
"instructions": "Decide the next action for this proposed answer",
"criteria": {
"execute": "High confidence and reversible - act automatically",
"escalate_model": "Borderline confidence - re-ask a stronger model",
"human_review": "Low confidence or irreversible - route to a person",
},
},
"irreversible": {
"type": "noul",
"instructions": "Would acting on this answer be hard to undo (payment, email, deletion)?",
},
}
def gate(state: dict) -> dict:
# The only thing worth retrying is a transport error - and the gate
# itself is one cheap, stateless call (~95ms, input tokens only).
resp = requests.post(
JEV_ENDPOINT,
json={"state": state, "questions": QUESTIONS},
timeout=3,
)
resp.raise_for_status()
return resp.json()
def fallback_chain(task: str, answer_model, strong_model) -> dict:
# Lane 1: the cheap model drafts; the calibrated gate decides.
draft = answer_model(task)
check = gate({"task": task, "proposed_answer": draft})
decision = check["fallback_action"]
if (
decision["answer"] == "execute"
and decision["confidence"] >= AUTO_EXECUTE_CONFIDENCE
and not check["irreversible"]["answer"]
):
return {"lane": "auto_execute", "answer": draft, "confidence": decision["confidence"]}
# Lane 2: 0.60-0.85 band - one re-ask with the stronger model.
stronger = strong_model(task)
recheck = gate({"task": task, "proposed_answer": stronger})
final = recheck["fallback_action"]
if (
final["answer"] == "execute"
and final["confidence"] >= AUTO_EXECUTE_CONFIDENCE
):
return {"lane": "escalated_model", "answer": stronger, "confidence": final["confidence"]}
# Lane 3: sub-threshold after escalation - human queue or safe default.
return {
"lane": "human_review",
"answer": stronger,
"confidence": final["confidence"],
"first_pass_confidence": decision["confidence"],
}
# Typical path: ~95ms per gate call, input tokens only. Lane 2 is the
# exception, not the default - most traffic never leaves lane 1.async function generateWithRetry(prompt: string, maxRetries = 5) {
// Blind retry: only transport errors trigger the loop, so a confidently
// wrong answer sails through untouched on the first attempt.
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const resp = await fetch("https://api.vendor-llm.example/v1/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "cheap-model",
messages: [{ role: "user", content: prompt }],
}),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
return (await resp.json()).choices[0].message.content as string;
} catch {
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
}
}
return ""; // silent failure after ~31s of backoff
}const JEV_ENDPOINT = "https://api.typesafe.ai/v1/jev/evaluate";
const AUTO_EXECUTE_CONFIDENCE = 0.85; // >= 0.85 -> act automatically
const QUESTIONS = {
fallback_action: {
type: "choice",
instructions: "Decide the next action for this proposed answer",
criteria: {
execute: "High confidence and reversible - act automatically",
escalate_model: "Borderline confidence - re-ask a stronger model",
human_review: "Low confidence or irreversible - route to a person",
},
},
irreversible: {
type: "noul",
instructions: "Would acting on this answer be hard to undo (payment, email, deletion)?",
},
} as const;
async function gate(state: Record<string, unknown>) {
const resp = await fetch(JEV_ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ state, questions: QUESTIONS }),
});
if (!resp.ok) throw new Error("Jev evaluate failed");
return (await resp.json()) as {
fallback_action: { answer: string; confidence: number };
irreversible: { answer: boolean };
};
}
export async function fallbackChain(
task: string,
answerModel: (t: string) => Promise<string>,
strongModel: (t: string) => Promise<string>,
) {
// Lane 1: cheap model drafts, calibrated gate decides (~95ms, input only)
const draft = await answerModel(task);
const first = await gate({ task, proposed_answer: draft });
if (
first.fallback_action.answer === "execute" &&
first.fallback_action.confidence >= AUTO_EXECUTE_CONFIDENCE &&
!first.irreversible.answer
) {
return { lane: "auto_execute", answer: draft, confidence: first.fallback_action.confidence };
}
// Lane 2: 0.60-0.85 band - one re-ask with the stronger model
const stronger = await strongModel(task);
const recheck = await gate({ task, proposed_answer: stronger });
if (
recheck.fallback_action.answer === "execute" &&
recheck.fallback_action.confidence >= AUTO_EXECUTE_CONFIDENCE
) {
return { lane: "escalated_model", answer: stronger, confidence: recheck.fallback_action.confidence };
}
// Lane 3: sub-threshold after escalation - human queue or safe default
return {
lane: "human_review",
answer: stronger,
confidence: recheck.fallback_action.confidence,
first_pass_confidence: first.fallback_action.confidence,
};
}