I learned this the annoying way.
I had an automation stack that looked clean on a diagram and messy in production:
- one expensive model
- one API path
- one prompt style
- one giant assumption that the “best” model would stay best under load
For about a week, it felt smart.
Then the weirdness started.
A planning step got slower. An extraction step that had been boring and stable started timing out. A review step began returning perfectly fluent nonsense right when I needed it to be conservative.
Nothing was fully broken, which somehow made it worse.
The real upgrade was not a fancier model.
It was routing.
More specifically: task-specific model routing with fallback only when it actually helps.
The mistake: using one genius for every job
A lot of us do this first.
We find one model we trust — GPT-5.4, Claude Opus 4.6, Grok 4.20, whatever — and then we run everything through it:
- planning
- extraction
- classification
- review
- tool calling
- retries
That feels elegant until your "app" turns out to be 5 different workloads pretending to be one.
Here’s how I think about it now:
| Job | What it actually needs |
|---|---|
| Planning | Reasoning quality, tool compatibility |
| Extraction | Structured output, consistency, low cost |
| Review | Conservative pass/fail behavior |
| Fallback path | Compatibility more than brilliance |
| Background jobs | Cheap async throughput, not low latency |
Once I split the workflow that way, the architecture got uglier and the results got better.
That trade was worth it immediately.
What breaks first in production
Usually not intelligence.
What breaks first is:
- availability
- latency
- rate limits
- cost drift
That’s why routing infrastructure matters more than benchmark screenshots.
If your n8n flow is processing invoices at 2 a.m., it does not care who won a cherry-picked reasoning test on X.
It cares about:
- whether the request clears
- whether the provider is throttling
- whether the fallback still supports your schema
- whether the bill stays predictable
OpenRouter made me think differently about failover
OpenRouter already does provider routing and load balancing across providers, and that’s more useful than it sounds.
The interesting part is that you can keep an OpenAI-style request shape while adding routing controls under it.
Example:
{
"model": "openai/gpt-4o",
"messages": [
{"role": "user", "content": "Summarize this invoice"}
],
"provider": {
"order": ["openai", "anthropic"],
"allow_fallbacks": true,
"sort": "price"
}
}
That’s a small change to the request body.
Operationally, it’s a big change.
You can route for:
- price
- throughput
- latency
- provider preference
That is boring infrastructure.
Boring infrastructure is exactly what you want when agents are running all day.
The real trick: task-specific fallback
The thing I got wrong was treating fallback like one giant emergency switch.
I thought:
- if Provider A fails
- send everything to Provider B
That’s too blunt.
A better pattern is task-specific fallback:
- planning fails over one way
- extraction fails over another way
- review maybe does not fail over at all
That design is much saner.
Planning should fail over to something strong and compatible
Planning is where I care about:
- reasoning quality
- tool use compatibility
- context handling
- not getting creatively weird
If GPT-5.4 is your primary planner, a Claude backup can work.
But only if your tool schema, output expectations, and token limits line up.
Otherwise the fallback "works" right up until the agent silently takes the wrong branch.
That is the worst kind of failure.
Extraction should only fail over on real provider problems
This is where Portkey gets practical.
Portkey lets you define fallback chains and trigger them only for specific status codes like 429 or 503.
That is much better than rerouting on every random error.
Example:
{
"strategy": {
"mode": "fallback",
"on_status_codes": [429, 503]
},
"targets": [
{"provider": "@openai-prod"},
{"provider": "@azure-prod"}
]
}
That means:
- keep the main extraction path stable
- fail over only when the provider is rate-limiting or unavailable
That is exactly the kind of behavior I want in production.
Review should be strict, not clever
Review is where expensive mistakes happen.
You do not need the most dazzling model for review.
You need a model that is:
- predictable
- strict about schema
- willing to say "fail"
- not eager to rewrite the answer
If your review layer gets too fancy, it stops judging and starts improvising.
That’s not review.
That’s sabotage.
Where the money actually goes
This is where routing stops being an architecture discussion and becomes a billing discussion.
Model pricing still varies by multiples, not tiny percentages.
For non-urgent work, Google’s Gemini 3.7 Flash Batch API is one of the clearest examples. Batch pricing is 50% cheaper than the standard path.
That makes it a strong fit for:
- async extraction
- classification
- back-office review
- reprocessing old jobs
If the work does not need immediate latency, it should probably not be running on your most expensive real-time path.
That was my mistake.
I was paying luxury-model prices for assembly-line work.
The stack I wish I had started with
Here’s the routing setup I’d recommend now:
| Job | What I’d optimize for |
|---|---|
| Planning | Strong reasoning, tool compatibility, backup to another strong reasoning model |
| Extraction | Low cost, structured output, fallback only on 429/503 |
| Review | Conservative judgment, schema reliability |
| Backlog jobs | Batch pricing, not latency |
And here’s how the main tooling maps to those needs:
| Option | What it’s actually good at |
|---|---|
| OpenRouter | Provider routing, fallback control, provider order, sorting by price/throughput/latency, OpenAI-compatible request path |
| Portkey AI Gateway | Explicit fallback policies, status-code-based rerouting, more complex gateway logic |
| Gemini Batch API | Cheap async processing for non-urgent workloads |
| Standard Compute | Flat-rate OpenAI-compatible access with dynamic routing across GPT-5.4, Claude Opus 4.6, and Grok 4.20 for teams that want predictable cost instead of per-token billing |
That last category matters more than people admit.
A lot of teams do eventually build better routing, then run face-first into the next problem:
"Cool, the system is more reliable now. Why is the bill still chaotic?"
That’s where flat-rate compute gets interesting.
If you’re running agents in n8n, Make, Zapier, OpenClaw, or custom workers all day, per-token pricing turns every routing improvement into a finance conversation.
Standard Compute is interesting because it keeps the OpenAI-compatible interface but removes the constant token math. For agent-heavy workloads, that’s a real operational advantage.
Yes, more routing can create a debugging mess
Absolutely.
If one request can hit multiple providers and multiple models, debugging gets harder.
Latency gets harder to reason about.
Spend gets harder to reason about.
Output drift gets harder to reason about.
So don’t build fallback carelessly.
These are the rules I follow now:
- Add fallback only where the workflow can tolerate model differences
- Trigger fallback on specific conditions, not vague disappointment
- Log the final provider and model for every step
- Keep prompts and schemas compatible across primary and backup paths
- Use batch paths only for work that is truly non-urgent
If you skip those rules, fallback routing turns into a haunted house.
Requests succeed, but:
- outputs drift
- latency spikes move around
- your cost model gets weird
- nobody knows what actually happened
Not all backups are safe backups
This is where a lot of routing advice gets way too casual.
A backup model can succeed technically while still breaking the workflow.
Things that can differ enough to matter:
- tool use support
- max token limits
- parameter support
- JSON / schema behavior
- context handling
- retention or compliance constraints
That’s why I’m skeptical when someone claims they found a universal replacement for every task.
Maybe for a narrow path, sure.
For a real agent with:
- tool calls
- retries
- long context
- structured outputs
- multiple failure modes
...you need to test each step separately.
A practical Python sketch
If you’re building your own worker, the simplest pattern is to route by task before you even think about fancy orchestration.
TASK_MODELS = {
"planning": "gpt-5.4",
"extraction": "gemini-3.7-flash",
"review": "claude-opus-4.6"
}
TASK_FALLBACKS = {
"planning": ["claude-opus-4.6"],
"extraction": ["gpt-5.4-mini"],
"review": []
}
def pick_model(task_name: str):
return TASK_MODELS[task_name], TASK_FALLBACKS.get(task_name, [])
Then log every decision:
import time
def run_step(task_name, payload):
primary, fallbacks = pick_model(task_name)
started = time.time()
try:
result = call_llm(primary, payload)
log_event(task=task_name, model=primary, fallback_used=False, latency_ms=int((time.time() - started) * 1000))
return result
except RateLimitError:
for model in fallbacks:
try:
result = call_llm(model, payload)
log_event(task=task_name, model=model, fallback_used=True, latency_ms=int((time.time() - started) * 1000))
return result
except Exception:
continue
raise
This is not glamorous.
It is also the kind of code that survives production better than "just send everything to the smartest model."
If you use OpenAI-compatible SDKs, keep the integration boring
That’s another lesson here.
You do not need to rewrite your whole app to get better routing.
If your stack already speaks the OpenAI API, you can often swap the base URL and keep moving.
Example:
pip install openai
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.standardcompute.com/v1"
)
resp = client.chat.completions.create(
model="gpt-5.4",
messages=[
{"role": "user", "content": "Extract invoice number and total as JSON"}
]
)
print(resp.choices[0].message.content)
That matters for automation teams.
If you’re already running flows in n8n, Make, Zapier, or custom Python workers, the best infrastructure upgrade is usually the one that does not force a rewrite.
The practical setup I’d recommend now
If I were rebuilding an agent stack today, I’d do this:
1. Pick a primary model per task, not per app
One for planning.
One for extraction.
One for review if needed.
2. Add fallback only where failure is expensive
If a planning miss can ruin the whole run, give it a strong backup.
If extraction is cheap to retry later, keep it simple.
3. Use routing infrastructure before rewriting your app
OpenRouter and Portkey both let you add resilience underneath an OpenAI-style interface.
That is the fastest path to reliability.
4. Push repetitive async work into batch pricing
Cheap batch paths are not exciting, but they move the bill a lot.
5. Fix cost predictability after reliability
Once agents run 24/7, per-token billing becomes its own operational problem.
If you want a drop-in OpenAI-compatible path with flat monthly pricing, Standard Compute is worth a look. It fits the exact use case where teams are tired of watching token spend while automations run continuously.
The punchline
I started this thinking I needed the single best model.
What I actually needed was a workflow that could survive:
- provider slowdowns
- rate-limit spikes
- random model weirdness
- cost drift from always using the premium path
One expensive model for everything feels sophisticated.
Routing by task feels boring.
Boring won.
Top comments (0)