n4nAI

Using LangChain's fallback chains with n4n.ai's model routing

Set up LangChain fallback chains model routing with an OpenAI-compatible gateway to keep LLM pipelines resilient when providers rate-limit or degrade.

n4n Team4 min read789 words

Audio narration

Coming soon — every post will get a voice note here.

LangChain fallback chains model routing lets you keep a pipeline alive when a model endpoint throws rate limits, 5xx errors, or hangs. By pointing ChatOpenAI at an OpenAI-compatible gateway and attaching fallbacks via with_fallbacks, you get graceful degradation without rewriting prompt logic. This guide builds a runnable chain that tries a primary model, then falls back to two alternatives, and shows how to verify which model actually served the request.

Step 1: Install dependencies

Use langchain-openai and langchain-core (LangChain 0.2+). The fallback behavior relies on LCEL runnables, not the legacy LLMChain class. Do not mix the old FallbackChain from langchain.chains with the new RunnableWithFallbacks pattern; they serialize differently and the old one is deprecated.

pip install langchain-openai langchain-core python-dotenv

Load your API key from environment. The gateway expects a bearer token; treat it like an OpenAI key.

import os
from dotenv import load_dotenv

load_dotenv()
API_KEY = os.environ["N4N_API_KEY"]  # or OPENAI_API_KEY if you mirror that var
GATEWAY_BASE = "https://api.n4n.ai/v1"  # single OpenAI-compatible endpoint

Step 2: Configure primary and fallback models

Define three ChatOpenAI instances against the same base URL but with different model strings. When you point LangChain at n4n.ai’s OpenAI-compatible endpoint, one base URL covers 240+ models and the gateway already does provider-level automatic fallback on degradation. We still add application-level fallbacks because we want control over which models stand in for which tasks, and because we may want to fall back to a cheaper model before an expensive one.

from langchain_openai import ChatOpenAI

primary = ChatOpenAI(
    model="openai/gpt-4o-mini",
    api_key=API_KEY,
    base_url=GATEWAY_BASE,
    temperature=0,
    timeout=10,
    max_retries=1,
)

secondary = ChatOpenAI(
    model="anthropic/claude-3-5-sonnet",
    api_key=API_KEY,
    base_url=GATEWAY_BASE,
    temperature=0,
    timeout=10,
    max_retries=1,
)

tertiary = ChatOpenAI(
    model="mistral/mistral-large",
    api_key=API_KEY,
    base_url=GATEWAY_BASE,
    temperature=0,
    timeout=10,
    max_retries=1,
)

Model names follow the gateway’s provider/model convention. Swap them for any of the 240+ available; the code does not change. Setting timeout and max_retries low is important—otherwise a hung primary blocks the fallback for minutes.

Step 3: Build the fallback chain

LangChain fallback chains model routing is implemented with with_fallbacks, which returns a RunnableWithFallbacks. The first runnable is the primary; the list passed to with_fallbacks is tried in order on exception. Only exceptions trigger fallback, not low-quality output.

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "Answer concisely."),
    ("user", "{question}")
])

# Attach fallbacks at the model layer
model_with_fallback = primary.with_fallbacks([secondary, tertiary])

chain = prompt | model_with_fallback | StrOutputParser()

You can also wrap the whole chain: (prompt | primary).with_fallbacks([prompt | secondary, prompt | tertiary]). Wrapping the model is cleaner when the prompt is static. If you need async, the same runnables expose ainvoke:

async def run_chain(question: str) -> str:
    return await chain.ainvoke({"question": question})

Step 4: Pass routing directives and cache hints

The gateway honors client routing directives and forwards provider cache-control hints. If you want to bias the primary call toward a specific upstream or enable Anthropic prompt caching, pass extra_body or model_kwargs. This does not affect LangChain’s fallback order; it only influences the gateway’s model selection and upstream headers.

primary_routed = ChatOpenAI(
    model="anthropic/claude-3-5-sonnet",
    api_key=API_KEY,
    base_url=GATEWAY_BASE,
    temperature=0,
    extra_body={
        "routing": {"prefer": "anthropic"},
        "cache_control": {"type": "ephemeral"}
    }
)

n4n.ai forwards provider cache-control hints, so the cache_control block reaches Anthropic unchanged. If the request falls back to a provider that ignores it, the gateway strips or ignores it safely. You can also pass routing directives per-call via the config object if your runnable reads RunnableConfig:

from langchain_core.runnables import RunnableConfig

config = RunnableConfig(
    metadata={"routing": {"prefer": "openai"}}
)
chain.invoke({"question": "Hi"}, config=config)

Step 5: Invoke and handle failures

Call the chain inside a try/except to catch the case where all models fail (e.g., invalid key). On success, inspect response_metadata to see which model answered. Wrapping the model only gives you the parsed string; to get metadata, call the model-with-fallback directly before the parser.

from langchain_core.runnables import RunnableWithFallbacks

question = "What is the difference between TCP and UDP in one sentence?"

try:
    response = (prompt | model_with_fallback).invoke({"question": question})
    answer = StrOutputParser().invoke(response)
    print("ANSWER:", answer)
except Exception as e:
    print("All fallbacks exhausted:", repr(e))

For streaming, use stream on the runnable; fallback still works because the stream is opened only after the primary commits to a response.

for chunk in (prompt | model_with_fallback).stream({"question": question}):
    print(chunk.content, end="", flush=True)

Step 6: Verify success and metering

Success means you got a non-empty string and response.response_metadata.model matches one of your configured models. Because the gateway provides per-token usage metering, you can assert on token counts:

usage = response.response_metadata.get("usage", {})
assert usage.get("total_tokens", 0) > 0, "No tokens metered"
print(f"Metered {usage['total_tokens']} tokens on {response.response_metadata['model']}")

Run the script with the primary model intentionally broken (e.g., wrong model string) to confirm the fallback engages:

primary = ChatOpenAI(model="openai/does-not-exist", api_key=API_KEY, base_url=GATEWAY_BASE)
# re-build chain...

You should see the answer arrive from anthropic/claude-3-5-sonnet or mistral/mistral-large and the usage block reflect that model. A minimal pytest check:

def test_fallback_runs():
    resp = (prompt | primary.with_fallbacks([secondary, tertiary])).invoke(
        {"question": "ping"}
    )
    assert resp.content
    assert "model" in resp.response_metadata

Troubleshooting

  • 401 Unauthorized: Key not in env, or using wrong var name. The gateway expects the key in Authorization: Bearer.
  • 404 on model: Model string must use provider/model. List available models from the gateway’s /v1/models endpoint.
  • Fallback not triggering: with_fallbacks only catches exceptions, not empty responses or content-filter blocks that return 200. If you need to fallback on junk output, wrap the parser with a custom validator that raises.
  • Latency stacking: Each fallback adds full round-trip time. Set timeout on each ChatOpenAI instance to fail fast.
  • Wrong model in metadata: Some providers return a normalized name. Compare with in rather than exact equality.
  • Cache hint ignored: Ensure extra_body is supported by your langchain-openai version (0.1.15+).
primary = ChatOpenAI(
    model="openai/gpt-4o-mini",
    api_key=API_KEY,
    base_url=GATEWAY_BASE,
    timeout=10,
    max_retries=1
)

Scaling the pattern

Once this works, extend it: put the fallback runnable behind a RunnableParallel to call two models concurrently and pick the first valid response, or compose it with a RouterChain that selects the primary based on input complexity. The LangChain fallback chains model routing approach stays the same—you are just changing what sits upstream of with_fallbacks. Because the gateway already handles provider degradation and per-token metering, your application code focuses purely on model preference and order.

You now have a single LCEL chain that implements LangChain fallback chains model routing across heterogeneous providers through one OpenAI-compatible base URL. The application controls fallback priority; the gateway handles provider degradation and token metering underneath. Swap the prompt for a more complex sequence without touching the fallback wiring.

Tagslangchainfallbackroutingn4n-ai

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All langchain + openai-compatible gateway integration posts →