Sign inContact usStart free
Reliability and RoutingAugust 4, 2026Flatkey Team

Model Fallback Strategy: A 3-Workflow Playbook

A production model fallback playbook with policy as code, failure drills, a 60-minute game day, release gates, rollback triggers, and safe recovery rules.

Model Fallback Strategy: A 3-Workflow Playbook

Model fallback is not one behavior. It is a set of recovery decisions with different safety limits.

A production model fallback strategy should separate three workflows:

  1. Retry or equivalent failover when the request is still safe to replay.
  2. Cross-model fallback when another model can satisfy the same capability and quality contract.
  3. Stop, reconcile, or escalate when output has already reached the user or a tool side effect may have happened.

That separation matters because the fastest recovery action is not always the safest one. Replaying a failed classification request is usually low risk. Silently switching models halfway through a streamed answer or after an uncertain payment tool call is not.

This playbook turns fallback policy into three operational workflows your team can implement, test, observe, and release through a controlled production rollout.

The model fallback decision in one table

Start with the request state, not the provider name.

Request state Preferred workflow Typical action Do not do
No response bytes, transient transport error Workflow 1 Bounded retry, then equivalent endpoint failover Retry without a deadline or budget
No response bytes, rate limit or overload Workflow 1 Honor retry guidance, apply jitter, then move to equivalent capacity Create a synchronized retry storm
Primary target unavailable, compatible model exists Workflow 2 Check the fallback contract, then route to the approved alternate Assume every model supports the same tools, schema, or context
Structured response fails validation Workflow 2 Repair once or try an approved model that meets the schema contract Treat HTTP 200 as task success
Partial stream already delivered Workflow 3 Stop, mark partial, offer an explicit restart Splice a second model into the same answer invisibly
Write-side tool may have executed Workflow 3 Reconcile tool state using an idempotency record Replay the entire model-and-tool workflow automatically
Safety or policy classification is uncertain Workflow 3 Escalate or fail closed according to product policy Lower the safety bar to preserve availability

The core rule is simple: retry preserves the target, equivalent failover preserves the model contract, and cross-model fallback changes the contract risk. Each step needs a stronger eligibility check.

For a deeper treatment of circuit breakers, error normalization, and a provider-neutral controller, see the LLM API fallback routing playbook.

Before the workflows: define one fallback envelope

Every request should enter the routing layer with a bounded envelope. The envelope tells the system how much recovery is allowed before the request must stop.

type FallbackEnvelope = {
  requestId: string;
  deadlineMs: number;
  maxAttempts: number;
  maxAddedLatencyMs: number;
  maxCostUsd?: number;
  allowEquivalentFailover: boolean;
  allowCrossModelFallback: boolean;
  allowAfterPartialOutput: false;
  sideEffectMode: "none" | "read_only" | "write_possible";
  requiredCapabilities: string[];
  requiredSchemaVersion?: string;
};

The values should come from the product workflow, not from a global default. A background summarization job can tolerate more latency than an interactive coding assistant. A chat answer with no tools can tolerate different recovery behavior than an agent that can deploy code or send email.

The envelope also prevents nested retries. If the SDK, application, gateway, and provider adapter all retry independently, a small incident can multiply into a large attempt burst. Pick one layer to own the total attempt budget and require every lower layer to report what it already consumed.

Turn the fallback envelope into policy as code

A type definition documents intent, but production routing needs a versioned policy that operators can review without changing application code. Keep the policy small enough to audit and specific enough to prevent a generic fallback chain from leaking into high-risk workflows.

This starter configuration separates three common route classes:

policy_version: 2026-08-02

routes:
  interactive_chat:
    deadline_ms: 12000
    max_attempts: 2
    max_added_latency_ms: 2500
    allow_equivalent_failover: true
    allow_cross_model_fallback: true
    allow_after_partial_output: false
    side_effect_mode: none
    required_capabilities: [streaming]

  structured_extraction:
    deadline_ms: 30000
    max_attempts: 3
    max_added_latency_ms: 8000
    allow_equivalent_failover: true
    allow_cross_model_fallback: true
    allow_after_partial_output: false
    side_effect_mode: none
    required_capabilities: [structured_output]
    required_schema_version: invoice-v4

  tool_agent_write:
    deadline_ms: 45000
    max_attempts: 2
    max_added_latency_ms: 5000
    allow_equivalent_failover: true
    allow_cross_model_fallback: false
    allow_after_partial_output: false
    side_effect_mode: write_possible
    required_capabilities: [tool_use]

The values above are examples, not universal thresholds. Set them from your user-facing latency objective, task economics, evaluation results, and side-effect risk. The important design choice is that the write-capable agent cannot silently switch to a behaviorally different model.

At runtime, the router should combine the policy with request state and observed failure state. A compact decision function can make the boundary testable:

type RecoveryAction =
  | "retry_same_target"
  | "failover_equivalent"
  | "fallback_approved_model"
  | "reconcile_side_effect"
  | "restart_required"
  | "stop";

function chooseRecovery(input: {
  errorClass: string;
  attemptsUsed: number;
  deadlineRemainingMs: number;
  partialOutput: boolean;
  sideEffectState: "none" | "safe" | "uncertain";
  equivalentAvailable: boolean;
  approvedAlternateAvailable: boolean;
  policy: FallbackEnvelope;
}): RecoveryAction {
  if (input.sideEffectState === "uncertain") return "reconcile_side_effect";
  if (input.partialOutput) return "restart_required";
  if (input.attemptsUsed >= input.policy.maxAttempts) return "stop";
  if (input.deadlineRemainingMs <= 0) return "stop";

  const transient = [
    "transport_transient",
    "rate_limited",
    "provider_overloaded",
    "provider_server_error",
  ].includes(input.errorClass);

  if (transient && input.attemptsUsed === 0) return "retry_same_target";
  if (transient && input.equivalentAvailable) return "failover_equivalent";

  if (
    input.policy.allowCrossModelFallback &&
    input.approvedAlternateAvailable
  ) {
    return "fallback_approved_model";
  }

  return "stop";
}

Keep candidate selection separate from the recovery decision. chooseRecovery decides which workflow is allowed; a candidate selector then filters targets by capability, context, region, cost, and quality policy. This separation makes incident review easier because the team can distinguish “we chose the wrong recovery workflow” from “we chose the wrong alternate model.”

Version the policy and attach that version to every attempt trace. When a fallback regression appears, operators should be able to answer which policy made the decision, which candidates were eligible, and which budget remained at that moment.

Workflow 1: retry, then equivalent failover

Use this workflow when the operation is replayable and the system has not exposed partial output or entered an uncertain side-effect state.

An equivalent target is another route that preserves the important contract: same model behavior class, required capabilities, schema expectations, safety configuration, and compatible context limits. It may be a different region, deployment, provider endpoint, or capacity pool.

Step 1: normalize the failure

Map provider-specific responses into a small internal taxonomy:

  • transport_transient
  • rate_limited
  • provider_overloaded
  • provider_server_error
  • authentication_or_permission
  • invalid_request
  • deadline_exhausted
  • contract_failure
  • partial_output
  • side_effect_uncertain

Only the first four normally qualify for automatic replay. Authentication, permission, and invalid-request errors should stop because a different endpoint is unlikely to repair the request. Contract failures belong in Workflow 2. Partial output and uncertain side effects belong in Workflow 3.

Step 2: calculate the remaining budget

Before every attempt, check:

remaining time > estimated next-attempt latency + response safety margin
remaining attempts > 0
remaining added latency > 0
remaining cost budget > estimated attempt cost, when a cost ceiling exists

If any required budget is exhausted, exit instead of trying one more provider.

Step 3: retry with backoff and jitter

Use provider retry guidance when available. Otherwise, apply exponential backoff with jitter and keep the delay inside the request deadline.

function retryDelayMs(attempt: number, retryAfterMs?: number): number {
  if (retryAfterMs !== undefined) return retryAfterMs;

  const base = Math.min(250 * 2 ** attempt, 4_000);
  const jitter = Math.random() * base * 0.3;
  return Math.round(base + jitter);
}

Jitter matters because many simultaneous clients can otherwise retry on the same schedule and prolong an overload event. Your LLM rate limits guide should define how RPM, TPM, queues, concurrency, and retry budgets interact.

Step 4: move to equivalent capacity

If the same target remains unhealthy, route to an equivalent endpoint only after checking:

  • The circuit is closed or half-open for a probe.
  • The target supports the required input and output modes.
  • The target can accept the request within its context limit.
  • The target uses the expected safety and data-handling configuration.
  • The attempt still fits the deadline and cost envelope.

Equivalent failover is normally less risky than changing models because it aims to preserve the response contract.

Step 5: record the recovery reason

Return a route outcome such as:

{
  "workflow": "retry_equivalent_failover",
  "primary_attempts": 2,
  "equivalent_failover_attempts": 1,
  "recovered": true,
  "recovery_reason": "provider_overloaded",
  "added_latency_ms": 684
}

Do not expose internal provider details to end users unless your product promises that transparency. Do preserve them in traces and operational logs.

Workflow 2: controlled cross-model fallback

Cross-model fallback is appropriate only when the alternate model has been pre-approved for the task. A model returning text is not enough; it must satisfy the workflow contract.

Step 1: create a capability contract

Define the non-negotiable requirements for each route class.

{
  "route_class": "support_ticket_triage_v3",
  "required": {
    "input": ["text"],
    "output": ["json_schema"],
    "tools": [],
    "minimum_context_tokens": 24000,
    "schema": "triage-result-v3",
    "languages": ["en", "es", "de"],
    "safety_profile": "customer-support-standard"
  },
  "fallback_models": [
    "approved-model-b",
    "approved-model-c"
  ]
}

For tool-using routes, include tool-choice behavior, parallel tool support, argument schema handling, and whether the model reliably follows “do not call” conditions. For structured outputs, validate the actual response against the schema after every attempt.

Step 2: separate transport success from task success

An HTTP success response can still fail the product workflow. Evaluate at least three layers:

  1. Transport success: the provider returned a complete response.
  2. Contract success: the response parsed, matched the schema, and used supported tools correctly.
  3. Task success: the output actually completed the user’s job at an acceptable quality level.

This distinction is essential when comparing fallback candidates. A model with a high response rate but frequent schema or tool failures is not a reliable fallback.

Step 3: rank approved candidates by policy

A production router can score eligible targets using operational signals without pretending that one model is universally best.

type Candidate = {
  id: string;
  capabilitiesPass: boolean;
  circuitOpen: boolean;
  estimatedLatencyMs: number;
  estimatedCostUsd: number;
  recentContractSuccess: number;
  recentTaskSuccess: number;
};

function eligible(candidate: Candidate, envelope: FallbackEnvelope): boolean {
  return (
    candidate.capabilitiesPass &&
    !candidate.circuitOpen &&
    candidate.estimatedLatencyMs <= envelope.maxAddedLatencyMs &&
    (envelope.maxCostUsd === undefined ||
      candidate.estimatedCostUsd <= envelope.maxCostUsd)
  );
}

Avoid a static “primary, backup, backup” list for every task. The best fallback set for code generation may differ from the best set for extraction, translation, vision, or tool execution.

Step 4: validate the fallback output

Apply deterministic checks first:

  • JSON or schema validation
  • Required field checks
  • Tool argument validation
  • Citation or URL format checks
  • Length and language constraints
  • Forbidden output patterns

Then add workflow-specific quality checks. These may be lightweight rules, a task evaluator, sampled human review, or a validated judge model. If the quality gate fails, do not label the fallback as recovered.

Step 5: canary policy changes

Before expanding a new fallback model:

  1. Replay an offline evaluation set.
  2. Run shadow traffic where policy allows it.
  3. Enable the candidate for a small percentage of eligible failures.
  4. Compare contract success, task success, latency, and cost.
  5. Expand only if the recovery value outweighs the regression risk.

Track these measurements with an LLM API observability schema that records one route and one span per attempt.

Workflow 3: stop, reconcile, or escalate

Some failures should not trigger another model call. The correct fallback is a controlled stop.

Case 1: partial streaming output

Once response tokens have reached the user, silently switching models can create contradictions, duplicate content, broken code blocks, or a sudden style change. It also makes the final response difficult to attribute and debug.

Use one of these explicit outcomes instead:

  • End the stream with a recoverable error and a “retry” action.
  • Offer to restart the answer from the beginning.
  • Continue only if the application has a designed resume protocol and the new model receives the exact accepted prefix.

The default should be allowAfterPartialOutput: false.

Case 2: uncertain tool side effects

Suppose a model selected a payment, email, deployment, ticket, or database-write tool. The tool may have succeeded even if the connection failed before your orchestrator recorded the result. Replaying the full workflow can duplicate the side effect.

Protect write-side tools with:

  • An idempotency key based on the user operation, not the provider attempt.
  • A durable execution record with planned, started, succeeded, failed, and unknown states.
  • Deduplication at the tool boundary.
  • A reconciliation query before any replay.
  • Human review for high-impact actions that remain uncertain.
type ToolExecution = {
  operationId: string;
  toolName: string;
  state: "planned" | "started" | "succeeded" | "failed" | "unknown";
  externalReference?: string;
};

function nextAction(execution: ToolExecution): "continue" | "reconcile" | "stop" {
  if (execution.state === "succeeded") return "continue";
  if (execution.state === "failed") return "stop";
  return "reconcile";
}

Keep provider credentials and tool credentials separate. The secure API key management guide covers the surrounding secret and access-control model.

Case 3: safety, permission, or policy uncertainty

Availability should not weaken a safety or authorization decision. If the fallback candidate does not support the required policy controls, the route is ineligible. If the system cannot determine whether an operation is allowed, fail closed or escalate according to the product’s risk model.

Case 4: no candidate satisfies the contract

Return a typed failure that the application can handle:

{
  "status": "unavailable",
  "reason": "no_eligible_fallback",
  "retryable": true,
  "retry_after_ms": 30000,
  "request_id": "req_123"
}

A clear degraded response is better than a successful-looking answer that violates the schema, uses the wrong tools, or performs the wrong side effect.

Put the three workflows into one state machine

The orchestration layer should make the transition explicit.

START
  -> PRIMARY_ATTEMPT
     -> SUCCESS: validate and return
     -> TRANSIENT + replayable: WORKFLOW_1
     -> CONTRACT_FAILURE + approved alternate: WORKFLOW_2
     -> PARTIAL_OUTPUT or SIDE_EFFECT_UNCERTAIN: WORKFLOW_3

WORKFLOW_1
  -> retry inside budget
  -> equivalent failover inside budget
  -> if compatible alternate allowed: WORKFLOW_2
  -> otherwise: STOP

WORKFLOW_2
  -> capability check
  -> alternate attempt
  -> contract and task validation
  -> return only on validated success
  -> otherwise: STOP

WORKFLOW_3
  -> mark partial or uncertain state
  -> reconcile external side effects when possible
  -> offer explicit restart or human escalation
  -> never silently replay unsafe work

This is also the right boundary for a multi-model gateway. Centralizing model access behind an OpenAI-compatible endpoint can reduce integration duplication, but the application still needs to supply workflow intent: deadlines, side-effect mode, required tools, schema version, and whether cross-model fallback is allowed. Flatkey provides a unified API access layer for teams that want one key and one integration surface across model providers; the safest routing policy still starts with explicit application contracts.

Run five failure drills before enabling automatic fallback

A fallback path that has never handled a controlled failure is only a diagram. Test each route class against failures that exercise a different safety boundary.

Drill Injected condition Expected behavior Evidence to retain
1. Primary timeout Delay the primary beyond its per-attempt timeout Retry only if the total deadline and attempt budget remain Attempt timestamps, budget before and after, final route reason
2. Rate-limit burst Return a bounded series of rate-limit responses Apply jitter, respect retry guidance, and avoid synchronized retries Backoff distribution, queue depth, recovered and deadline-exhausted counts
3. Invalid structured output Return HTTP success with a schema-invalid body Mark contract failure, try only an approved schema-capable alternate, validate again Validation errors, candidate eligibility record, accepted-task result
4. Mid-stream disconnect End the connection after user-visible tokens Stop the stream and require an explicit restart Partial-output flag, user-facing state, confirmation that no silent splice occurred
5. Ambiguous tool result Drop the response after a write-side tool may have executed Reconcile by operation ID before any replay Idempotency record, external state lookup, duplicate-side-effect count

Run the drills first in a local or staging environment, then in a narrowly scoped production game day. The purpose is not to prove that every request survives. It is to prove that the system fails in the intended state, exposes enough evidence to diagnose the event, and does not spend more latency, money, or side-effect risk than the policy allows.

For each drill, verify four layers independently:

  1. Decision correctness: the router chose the intended workflow.
  2. Budget correctness: all attempts stayed inside the shared deadline, attempt, and cost envelope.
  3. Output correctness: the final result passed contract and task validation, or returned an explicit degraded state.
  4. Audit correctness: traces captured policy version, failure class, candidate eligibility, route reason, and user-visible outcome.

Repeat the drill whenever you change a provider adapter, retry owner, model candidate, schema version, tool contract, or streaming implementation. Those changes can alter replay safety even when the public API shape appears unchanged.

Use a fallback readiness scorecard before production

Passing a few happy-path tests is not enough to enable automatic fallback. A route should earn automation by passing five independent release gates.

Gate Pass condition Evidence Block automatic fallback when
Replay safety The team can prove whether the request is safe to repeat at every attempt boundary Side-effect classification, idempotency design, partial-output rules A write may have happened without a reconciliation key
Contract compatibility Every candidate supports the required context, tools, schema, modalities, and policy controls Versioned capability matrix and contract tests Compatibility is assumed from model family or marketing labels
Task quality The alternate produces acceptable outcomes for the route's real workload Route-specific evaluation set and reviewed failure cases Only transport success or generic benchmark scores are available
Budget control Retries and fallbacks share one deadline, attempt limit, and cost ceiling Failure-drill traces showing budget consumption Multiple layers can retry independently or exceed the caller deadline
Operational control On-call engineers can identify, disable, and explain a fallback decision Policy version, route reason, kill switch, dashboard, runbook The recovery path cannot be isolated without a full application deploy

Treat the scorecard as a release artifact. Record the route class, policy version, approved candidates, evaluator version, drill results, owner, and review date. A single global “fallback enabled” flag hides too much risk; approval should happen per workflow class.

Copyable readiness record

fallback_readiness:
  route_class: support_ticket_extraction
  policy_version: fallback-v4
  owner: ai-platform
  primary_target: primary-model
  approved_candidates:
    - equivalent-deployment
    - alternate-model

  gates:
    replay_safety: pass
    contract_compatibility: pass
    task_quality: pass
    budget_control: pass
    operational_control: pass

  evidence:
    capability_matrix: contracts/support-ticket-v3.yaml
    evaluation_set: evals/support-ticket-2026-08.jsonl
    failure_drill_run: drills/2026-08-03.json
    dashboard: ai-routing/support-ticket
    runbook: runbooks/support-ticket-fallback.md

  release:
    mode: canary
    rollback_owner: oncall-ai-platform
    next_review_at: 2026-09-03

The file does not need to live in this exact format. What matters is that the release decision is reviewable and tied to the same policy version recorded in production traces.

Roll out a model fallback strategy in four stages

Automatic fallback should not jump from an offline test to every production request. Use four stages that expose decision errors before they become user-visible.

Stage 1: shadow the decision

Run the fallback controller in observe-only mode. The primary path still determines the user response, while the controller records what it would have done.

Review:

  • How often the policy labels a failure as retryable.
  • How often a candidate is eligible.
  • Which budget would have stopped recovery.
  • Whether the policy proposes fallback after partial output or uncertain side effects.
  • Whether provider-normalized errors preserve enough detail for incident diagnosis.

Shadow mode is especially useful for finding overly broad rules such as “fallback on every 429” or “try another model after any schema error.” Those rules can look reasonable in code review but behave badly against real request states.

Stage 2: canary low-risk workflows

Enable fallback for a narrow share of replay-safe traffic such as read-only classification, extraction, or background summarization. Exclude write-side tools, safety-sensitive decisions, and routes with user-visible streaming.

Compare the canary against the primary-only path using route-level outcomes:

  • Accepted-task rate, not only HTTP success.
  • Added latency from recovery.
  • Cost delta per accepted task.
  • Contract-validation failures by candidate.
  • Deadline exhaustion and no-eligible-fallback rate.
  • User cancellation or explicit restart rate.

Do not widen the canary because the provider error rate fell. Widen it only when the final user outcome remains acceptable and the recovery path stays inside its envelope.

Stage 3: constrain automatic recovery by risk class

Expand only the workflow classes that passed the readiness scorecard. Keep policy differences explicit:

Risk class Default automation Required safeguard
Read-only, no streamed output Retry, equivalent failover, approved cross-model fallback Contract and task validation
Read-only with streamed output Recovery only before first user-visible byte Partial-output state and explicit restart
Tool use with read-only tools Retry before tool execution; validate alternate tool contract Tool schema and tool-choice tests
Tool use with writes Stop and reconcile after ambiguous execution Durable operation ID and external state lookup
Safety, permission, or compliance decision Fail according to the product's approved policy No availability-driven policy downgrade

This stage is where a gateway and application contract meet. The gateway can normalize errors, enforce budgets, and select eligible capacity. The application must still state whether output has escaped, whether a side effect is possible, and which quality or policy checks are mandatory.

Stage 4: widen gradually and re-certify changes

Increase traffic in bounded steps. At each step, retain the ability to disable one policy version, one route class, one provider adapter, or one candidate without turning off the entire routing layer.

Re-run the relevant scorecard gates when any of these change:

  • Model or model version.
  • Provider adapter or endpoint.
  • Prompt template or system instruction.
  • Tool definition or permission scope.
  • Structured-output schema.
  • Retry ownership or timeout configuration.
  • Streaming transport or client behavior.
  • Safety policy or quality evaluator.

Fallback readiness expires when its assumptions change. A candidate approved for a previous prompt, schema, or tool set should not remain automatically eligible by inertia.

Define rollback triggers before enabling the canary

A canary is only safe when the team agrees in advance what stops it. Use route-specific triggers rather than waiting for a broad incident.

Rollback or disable the affected policy when you observe:

  • Duplicate or uncertain write-side effects.
  • Cross-model contract success without acceptable task success.
  • A rise in partial-stream failures or invisible response splicing.
  • Repeated deadline exhaustion caused by recovery attempts.
  • Budget ceilings being exceeded or ignored.
  • Candidate selection that violates a required capability or safety policy.
  • An unexplained change in fallback reason distribution after a deploy.
  • Missing policy-version or attempt-level trace data during an incident.

The rollback action should be as narrow as the failure. Depending on the event, that may mean disabling one candidate, forcing a route to equivalent failover only, setting allowCrossModelFallback to false, opening a circuit for one provider, or returning the workflow to primary-only mode.

Avoid a rollback mechanism that requires rebuilding the application. Recovery policy changes frequently during incidents, and the safest response is often a configuration change with an auditable version rather than an emergency code patch.

Use one incident worksheet for every fallback event

Fallback incidents become hard to diagnose when each provider exposes a different error shape and each application logs a different request state. Capture one provider-neutral worksheet.

fallback_incident:
  incident_id: inc-2026-08-03-001
  route_class: support_ticket_extraction
  request_id: req_123
  policy_version: fallback-v4

  request_state:
    output_started: false
    side_effect_mode: none
    tool_execution_state: not_started
    deadline_remaining_ms: 1820
    attempts_remaining: 1

  primary_failure:
    normalized_class: overloaded
    provider_status: 529
    retry_guidance_present: true

  recovery_decision:
    workflow: cross_model_fallback
    candidate: alternate-model
    reason: equivalent_capacity_unavailable

  validation:
    transport_success: true
    contract_success: true
    task_success: false
    failure_reason: required_field_omitted

  user_outcome:
    state: explicit_failure
    partial_output: false
    duplicate_side_effect: false

  containment:
    action: disable_candidate_for_route
    owner: oncall-ai-platform

The most important distinction is between recovery success and user success. A fallback request can return a valid HTTP response and still fail the schema, choose the wrong tool, omit a required fact, or violate the route's quality threshold. Incident review should follow the outcome all the way to the user-visible task.

Run a 60-minute model fallback game day

Unit tests prove that individual branches execute. A fallback game day proves that the whole recovery system behaves correctly while deadlines, retries, streams, validation, tools, telemetry, and operator controls interact.

Run the exercise against one workflow class at a time. Do not begin with a global provider outage simulation. A narrow route such as read-only extraction or internal summarization produces clearer evidence and limits the blast radius if the policy is wrong.

Define the game-day charter

Write a one-page charter before anyone injects a failure. The charter prevents the exercise from turning into an improvised outage.

game_day:
  id: fallback-gd-2026-08-04-extraction
  route_class: structured_extraction
  policy_version: fallback-v4
  environment: staging
  exercise_owner: ai-platform
  incident_commander: reliability

  primary_target: primary-model
  approved_fallbacks:
    - equivalent-deployment
    - alternate-schema-capable-model

  traffic_scope:
    synthetic_requests: 100
    production_percentage: 0

  safety_limits:
    stop_after_minutes: 60
    max_error_rate_percent: 5
    max_duplicate_side_effects: 0
    max_unexplained_route_decisions: 0

  success_definition:
    - every request ends accepted, explicitly degraded, or safely stopped
    - no request exceeds the shared attempt budget
    - no partial stream is silently continued by another model
    - every fallback decision includes a policy version and route reason

Use synthetic or replay-safe traffic first. If the route can trigger writes, replace the tool with a controlled test double or a sandbox that supports idempotency lookup. A game day should test recovery controls, not gamble with customer state.

Assign four roles

Keep the team small enough to make decisions quickly, but separate observation from execution.

Role Responsibility during the exercise Must not do
Exercise lead Starts scenarios, controls the timeline, and calls stop conditions Change the fallback policy mid-scenario without recording it
Operator Watches route health, disables candidates, and uses the kill switch Inject failures or edit evidence
Observer Records timestamps, screenshots, traces, and user-visible outcomes Help the router “pass” by correcting requests manually
Application owner Judges task quality and workflow-specific degradation Approve a result based only on HTTP success

For a very small team, one person can cover two roles, but the person injecting the fault should not be the only person evaluating whether the system responded correctly.

Build a scenario ladder

Start with the least ambiguous failure and add risk only after the route passes the previous rung.

Rung Injection What the router should prove Promotion requirement
1. Clean equivalent failover Make the primary endpoint unavailable before response bytes It can move to equivalent capacity without changing the application contract Accepted result, one route reason, shared budget respected
2. Retry pressure Return a bounded burst of retryable errors Backoff and jitter work without attempt multiplication No nested retry amplification; deadline remains authoritative
3. Semantic contract failure Return a transport-successful but invalid structured result Validation, not status code, controls acceptance Alternate is eligible and its result passes the same validator
4. Partial stream Disconnect after visible output The system stops and marks the answer partial No silent model splice; restart is explicit
5. Uncertain tool completion Lose the model response after a write may have executed The workflow reconciles external state before replay Operation ID lookup completes; duplicate writes remain zero
6. Fallback degradation Make the approved alternate slower or lower quality Stop-loss and rollback rules override availability pressure Candidate is removed or automation is disabled at the predefined threshold

Do not skip directly to a complicated cross-model scenario. If equivalent failover cannot preserve the budget and trace contract, adding a behaviorally different model will make the diagnosis harder, not more realistic.

Inject faults at explicit boundaries

Label the exact boundary where the fault enters the request lifecycle. “Provider failed” is too vague for a useful test record.

type InjectionPoint =
  | "before_connect"
  | "after_connect_before_headers"
  | "after_headers_before_body"
  | "after_partial_stream"
  | "after_tool_dispatch_before_ack"
  | "after_tool_ack_before_model_response"
  | "after_transport_success_before_validation";

The boundary determines which recovery actions are safe. A timeout before connection can often be retried. A disconnect after a user has seen output requires an explicit restart. A lost acknowledgement after a write-side tool call requires reconciliation. Treating all three as the same timeout class is how duplicate actions and incoherent responses enter production.

If your fault-injection layer cannot target those boundaries, add the boundary marker to the provider adapter or orchestration layer before the exercise. Coarse failure toggles are useful for availability tests but insufficient for replay-safety tests.

Capture one evidence row per request

The game day should produce a request-level ledger, not only dashboard screenshots. A compact row makes unexplained decisions visible.

Field Example Why it matters
request_id req_01J... Joins gateway, model, validator, and tool evidence
scenario_id partial-stream-01 Connects the outcome to the injected condition
policy_version fallback-v4 Proves which routing rules made the decision
failure_class stream_interrupted Separates transport, contract, policy, and tool uncertainty
injection_point after_partial_stream Establishes replay safety
attempts_used 1/2 Detects retry amplification
elapsed_ms 4830/12000 Shows remaining deadline budget
cost_budget_state within Prevents recovery from ignoring unit economics
selected_action restart_required Records the router's decision
candidate_id none Shows whether another model was considered
validator_result not_run Separates transport recovery from task acceptance
side_effect_state none Makes reconciliation requirements explicit
user_outcome partial_marked Captures what the customer experienced
operator_action none Distinguishes automatic recovery from manual containment

Store the ledger beside the policy snapshot, validator version, fault configuration, and dashboard export. Without those versions, a passing exercise cannot be reproduced after the next adapter or model change.

Score the exercise with promotion rules

Use three possible decisions: promote, fix and rerun, or stop automation. Avoid a vague “mostly passed” result.

Promote the route only when all of these are true:

  • Every request has an explained terminal state.
  • No attempt chain exceeds the shared deadline, attempt count, or configured cost ceiling.
  • Every accepted output passes the route's validator or evaluation rule.
  • Partial output and uncertain side effects enter explicit stop or reconciliation states.
  • Operators can disable one candidate or the whole policy without deploying application code.
  • Alerting identifies both recovery failures and harmful recoveries, such as fallback success with unacceptable task quality.

Choose fix and rerun when the safety model is correct but evidence or implementation is incomplete. Examples include a missing route reason, an alert that fires too late, or a candidate that passes the contract but misses the latency objective.

Choose stop automation when the exercise finds replay ambiguity, duplicate side effects, silent stream splicing, unexplained routing, policy bypass, or a failure mode the current state machine cannot represent. Those are design gaps, not tuning issues.

Use a copyable game-day scorecard

game_day_result:
  game_day_id: fallback-gd-2026-08-04-extraction
  route_class: structured_extraction
  policy_version: fallback-v4
  evaluator_version: extraction-eval-v7
  started_at: 2026-08-04T09:00:00Z
  completed_at: 2026-08-04T10:00:00Z

  scenarios:
    equivalent_failover: pass
    retry_pressure: pass
    semantic_contract_failure: pass
    partial_stream: pass
    uncertain_tool_completion: not_applicable
    fallback_degradation: fix

  totals:
    requests: 100
    accepted: 94
    explicitly_degraded: 6
    unsafe_or_unexplained: 0
    duplicate_side_effects: 0
    deadline_violations: 0

  decision: fix_and_rerun
  blockers:
    - alternate p95 latency exceeded the route objective during degradation
  owner: ai-platform
  rerun_due: 2026-08-11

The sample values are illustrative. Use your own route objectives and evaluation thresholds. What matters is that the final decision points to retained evidence and a named owner.

Turn findings into release controls

Finish the game day by converting every finding into one of four durable controls:

  1. Policy change: candidate eligibility, attempt budget, deadline, or route-class rule.
  2. Contract test: capability, schema, tool, streaming, or safety compatibility check.
  3. Operational control: alert, dashboard, kill switch, candidate quarantine, or incident procedure.
  4. Product behavior: explicit restart, degraded-state message, manual confirmation, or reconciliation screen.

Do not close the exercise with a list of observations. A finding without an owner, control type, and rerun condition will reappear during a real incident.

For the telemetry layer behind these exercises, use the LLM API observability guide. For retry ownership and rate-limit behavior, pair the game day with the LLM rate limits and retry strategy. If your team is still defining the gateway boundary, start with the LLM gateway beginner guide.

A seven-day implementation sequence

Teams can use this order to move from an ad hoc model list to a controlled workflow playbook:

  1. Day 1 — Inventory routes: classify output mode, side-effect risk, tools, schemas, deadlines, and current retry owners.
  2. Day 2 — Define envelopes: set attempt, latency, cost, capability, and replay limits per route class.
  3. Day 3 — Build contracts: document approved candidates and test tool, schema, context, modality, and policy compatibility.
  4. Day 4 — Instrument decisions: record normalized failure, request state, policy version, candidate eligibility, budget, validation, and user outcome.
  5. Day 5 — Run failure drills: inject timeout, rate-limit burst, invalid output, mid-stream disconnect, and ambiguous tool execution.
  6. Day 6 — Shadow and canary: observe decisions first, then enable a narrow low-risk route with predefined rollback triggers.
  7. Day 7 — Review and widen: inspect accepted-task rate, added latency, cost delta, unsafe replay signals, and no-eligible-fallback events before expanding.

The sequence is intentionally workflow-first. Choosing a ranked list of models is one small step. The production work is proving when the system may continue, when it must validate, and when it must stop.

Model fallback strategy rollout checklist

Policy

  • Every route class has a fallback envelope.
  • Fallback policy is versioned and reviewable as configuration.
  • Retryable errors are normalized across providers.
  • The total retry budget has one owner.
  • Equivalent endpoints are distinguished from alternate models.
  • Cross-model candidates have versioned capability contracts.
  • Partial output disables transparent fallback by default.
  • Write-side tools use durable idempotency records.

Validation

  • Transport, contract, and task success are measured separately.
  • Structured outputs are validated after fallback.
  • Tool arguments and tool-choice behavior are tested per model.
  • Fallback evaluation sets represent real route classes.
  • New candidates pass offline evaluation and a production canary.
  • All five failure drills pass for each applicable route class.

Operations

  • Each attempt records route reason, target, latency, and result.
  • Dashboards show primary, retry, equivalent failover, and cross-model recovery separately.
  • Alerts include deadline exhaustion and no-eligible-fallback rates.
  • Circuit breakers use controlled half-open probes.
  • Incident review includes user-visible quality and duplicate-side-effect risk.
  • Every attempt trace records the active fallback policy version.
  • Each route has a completed readiness scorecard and named owner.
  • Canary rollback triggers and narrow kill switches are tested.
  • Incident worksheets capture request state, validation, and user outcome.

Metrics that prove fallback is helping

Do not optimize only for provider error rate. Track the user outcome.

Metric Question answered
Retry recovery rate Are same-target retries worth their latency?
Equivalent failover recovery rate Does redundant capacity restore service safely?
Cross-model contract success Does the alternate response satisfy the required interface?
Cross-model task success Does the user still complete the intended job?
Added fallback latency How much delay does recovery add?
Fallback cost delta What is the cost of the recovery path?
Partial-stream failure rate How often does the system reach an unrecoverable presentation state?
Side-effect reconciliation rate How often must the system verify external state before continuing?
Duplicate-side-effect incidents Did replay protection fail?
No-eligible-fallback rate Are route contracts too strict, or is capacity insufficient?

Segment these metrics by route class. An aggregate recovery rate can hide that fallback works well for extraction but poorly for code generation or tool use.

During rollout, compare these metrics by policy version and release stage. That makes it possible to separate a provider incident from a controller change, candidate change, or widened canary.

Frequently asked questions

What is a model fallback strategy?

A model fallback strategy is a policy for deciding when an AI request should retry the same target, fail over to equivalent capacity, switch to an approved alternate model, or stop because replay would be unsafe.

What is the difference between retry and fallback?

A retry repeats the request against the same target or deployment. Equivalent failover moves the request to capacity intended to preserve the same model contract. Cross-model fallback changes the model and therefore requires capability and quality validation.

Should every 429 error trigger another model?

No. First classify the limit, honor retry guidance, check the remaining deadline, and use a bounded retry or queue. Switching models may help when approved alternate capacity exists, but it can also change output quality, tool behavior, or cost.

Can a streamed response fall back mid-answer?

It is usually safer not to switch transparently after tokens have reached the user. Stop the stream and offer an explicit restart unless the application has a tested resume protocol.

How many fallback models should a route have?

Use the smallest approved set that provides meaningful recovery. Each candidate adds evaluation, monitoring, and incident-response work. A long untested list is not resilience.

Where should fallback logic live?

Centralize provider normalization, routing, attempt budgets, and observability in a gateway or orchestration layer. Keep workflow-specific intent—side-effect risk, schema requirements, safety policy, and quality thresholds—close to the application.

How should a team roll out automatic model fallback?

Start in shadow mode, canary only replay-safe workflows, define rollback triggers before widening traffic, and re-certify the fallback policy whenever models, prompts, tools, schemas, retry ownership, or safety requirements change.

Build fallback around workflow risk

The best model fallback strategy is not “try the next model.” It is a bounded decision system:

  • Workflow 1 recovers replayable requests with retries and equivalent capacity.
  • Workflow 2 switches models only after capability and quality checks.
  • Workflow 3 stops automatic replay when output or side effects make recovery unsafe.

That design improves availability without hiding contract failures or duplicating user actions. If your team is standardizing access across model providers, use Flatkey’s unified OpenAI-compatible API layer as the integration surface, then attach these workflow-specific envelopes to every production route.

Sources and further reading