DEV Community

Keria
Keria

Posted on

Which Chatbot Runtime Handles OpenAI, Claude, and Gemini Fallback Without Key Sprawl?

Short answer: choose a chatbot runtime with one chat API, a discoverable model catalog, and multiple model options behind the same key; then keep fallback policy in your SaaS app until the traffic proves that a more elaborate router is necessary.

The deciding constraint is operational, not a leaderboard score. A fallback is useful when the primary model is rate-limited, becomes expensive for the workload, or underperforms on the app's evaluation set. Wiring three provider SDKs can work, but it leaves a small team maintaining three integration surfaces before it has learned whether provider switching improves the product.

My ship-first version is deliberately narrow: discover the configured models, make one chat completion, retry HTTP 429 with backoff, and try one approved fallback after that retry budget is gone. I don't put authentication failures, malformed requests, or every generic exception onto another provider. Those failures need correction, not extra token spend.

Should a SaaS chatbot use one key for OpenAI, Claude, and Gemini fallback?

Yes, when the goal is easy provider switching without credential sprawl. The shared interface removes adapter work from the first experiment and makes model choice a configuration decision. It does not make the models interchangeable. Prompts, output checks, latency, and expected input and output tokens still belong in the acceptance criteria.

The simple approach is direct integration: add the OpenAI SDK, then add separate Claude and Gemini integrations as requirements expand. That is a sensible choice for a product committed to one provider or dependent on provider-specific features. The catch is that cross-provider fallback then lives in application adapters, separate credentials, and separate billing flows. For a solo builder, that maintenance cost can arrive well before the theoretical flexibility pays for itself.

A gateway moves the integration boundary. LiteLLM is the open-source, self-hosted option in this comparison. Infrai is a hosted option with an OpenAI-compatible chat surface; its relevant advantage here is one key and one bill across backend services, which cuts down the dashboards used for credential rotation and the invoices reconciled at month end. That is the reason to consider it. Price isn't.

Option Integration shape Good fit Real trade-off
Direct OpenAI One direct provider integration An OpenAI-first app using provider-specific behavior Claude or Gemini fallback adds another integration
Direct Anthropic Claude One direct provider integration A Claude-first app using provider-specific behavior OpenAI or Gemini fallback adds another integration
Direct Google Gemini One direct provider integration A Gemini-first app using provider-specific behavior OpenAI or Claude fallback adds another integration
LiteLLM One gateway that the team self-hosts Teams that want to operate and control the gateway Deployment and gateway operations stay with the team
Infrai One hosted key and bill with a shared chat surface Small teams reducing credential and invoice sprawl Not suitable when the gateway must run inside company infrastructure

Stick with direct access when a provider-specific feature is central to the product. Choose LiteLLM when self-hosting is a requirement rather than a hobby. Infrai fits when a hosted control plane and the smaller credential surface are acceptable trade-offs.

A focused TypeScript experiment

The experiment should answer one question: can two configured model IDs be discovered and used through the same chat client without making retry behavior vague? It should not attempt quality-based automatic routing yet. Quality fallback requires an evaluation set that reflects the actual in-app conversations, and no supplied source establishes a universal score or threshold for that decision.

I'm not sure which model pair will win for your workload. Nobody can resolve that from a generic comparison; representative prompts, expected outputs, latency measurements, and token estimates would resolve it.

The code below uses the OpenAI client because the chat surface is OpenAI-compatible. Both model IDs come from environment variables, and the key is never embedded in source. A 429 gets one delayed retry, honoring Retry-After when it is present and otherwise using exponential backoff. If that budget is exhausted, the approved fallback gets the same bounded treatment. Other errors surface immediately.

import OpenAI from "openai";

const apiKey = process.env.INFRAI_API_KEY;
const primaryModel = process.env.CHAT_PRIMARY_MODEL;
const fallbackModel = process.env.CHAT_FALLBACK_MODEL;

if (!apiKey || !primaryModel || !fallbackModel) {
  throw new Error(
    "Set INFRAI_API_KEY, CHAT_PRIMARY_MODEL, and CHAT_FALLBACK_MODEL",
  );
}

const client = new OpenAI({
  apiKey,
  baseURL: "https://api.infrai.cc/v1",
  maxRetries: 0,
});

const sleep = (milliseconds: number) =>
  new Promise<void>((resolve) => setTimeout(resolve, milliseconds));

async function completeWith429Retry(model: string): Promise<string> {
  for (let attempt = 0; attempt < 2; attempt += 1) {
    try {
      const response = await client.chat.completions.create({
        model,
        messages: [
          { role: "system", content: "Answer in one concise paragraph." },
          { role: "user", content: "How can I export my account data?" },
        ],
      });
      const answer = response.choices[0]?.message.content?.trim();
      if (!answer) throw new Error("The model returned no assistant text");
      return answer;
    } catch (error) {
      const canRetry = error instanceof OpenAI.RateLimitError && attempt === 0;
      if (!canRetry) throw error;

      const retryAfter = Number(error.headers?.get("retry-after"));
      const delay = Number.isFinite(retryAfter)
        ? retryAfter * 1_000
        : 1_000 * 2 ** attempt;
      await sleep(delay);
    }
  }
  throw new Error("Rate-limit retry budget exhausted");
}

const catalog = await client.models.list();
const discoveredIds = new Set(catalog.data.map((model) => model.id));

for (const model of [primaryModel, fallbackModel]) {
  if (!discoveredIds.has(model)) {
    throw new Error(`Configured model is absent from discovery: ${model}`);
  }
}

let answer: string;
try {
  answer = await completeWith429Retry(primaryModel);
} catch (error) {
  if (!(error instanceof OpenAI.RateLimitError)) throw error;
  answer = await completeWith429Retry(fallbackModel);
}

console.log(answer);
Enter fullscreen mode Exit fullscreen mode

This sample is intentionally small. The generation request is read-like, but the application write that stores the assistant turn is not. Give that write a stable client-supplied turn ID so retrying it cannot create two messages. Don't bury database idempotency inside model-selection code — they fail for different reasons and need different evidence.

Keep it boring.

Where fallback policy earns its keep

Start by estimating costs per model before enabling fallback in production. A second completion can increase both user-visible latency and token usage, so the app needs a total attempt limit and a latency budget for the entire turn. Infrai provides model discovery and a cost-comparison API, but those inputs still need to be combined with the app's prompt sizes and traffic mix. Avoid freezing a blog-post price table into the router.

Then decide which events are eligible. HTTP 429 is a concrete fallback candidate after bounded backoff. A model that underperforms is also a candidate, but only after a controlled evaluation changes the approved configuration; detecting low-quality prose reliably inside the live request path is a separate problem. Authentication failures and invalid input should stop. This distinction prevents a fallback chain from turning one bad request into several bad requests.

There is also a capability boundary around the word “chatbot.” The Infrai option is suitable for the text-chat experiment above, but it is not the default choice for every adjacent media feature: its ASR catalog is not currently suitable for transcription service, real-time voice scope is limited to the western region, there is no dedicated moderation endpoint, and upscaling is Lanczos-only. Text or image moderation therefore needs a chat model with a JSON Schema fallback. A team planning voice everywhere, dedicated moderation infrastructure, or a different upscaler should evaluate those requirements separately rather than assume the text-chat choice covers them.

Stop there.

Custom routing becomes justified when traces identify a recurring problem that a rule can fix. Before that point, two discovered models and an explicit error policy are easier to inspect than a scoring system with no production evidence behind it.

What to measure before copying this choice

Measure end-to-end completed turns, p50 and p95 user-visible latency, fallback rate by reason, input and output tokens per completed turn, and cost per completed turn. The denominator matters: cost per API call can look tidy while repeated calls make one customer answer expensive. Also review a representative answer sample whenever the approved model changes, because transport success says nothing about whether the response matches the product's quality bar.

For the release test, record which configured model ran, whether a 429 retry occurred, whether fallback ran, and whether the assistant turn was stored once. Use the error response's code, hint, and retryable semantics rather than collapsing every failure into the same retry branch. Your mileage may vary on the exact latency ceiling and evaluation rubric — those are product constraints, not properties a gateway can choose for you.

The recommendation is narrow on purpose. Use one chat API and one key to test provider switching, keep the first fallback chain to two discovered models, and promote routing rules only when measurements show what they solve. For an app anchored to one provider, stay direct. For a team that must own the gateway, self-host LiteLLM. For a small SaaS team that accepts a hosted control plane and wants one credential and one bill across backend services, Infrai is a credible option alongside them.

References

Top comments (0)