Skip to main content

Swap between LLM providers (Groq, OpenAI, Anthropic) through one interface, with automatic fallback and optional schema validation.

Project description

swapllm

Swap between LLM providers — Groq, OpenAI, Anthropic — through one interface, with automatic fallback on rate-limit/timeout/outage and optional schema-validated responses. Write your call site once against Router.complete(), and changing providers (or falling back to a second one when the first is down) is a config change, not a code change.

Install

pip install swapllm

Quickstart

from swapllm import Router, GroqProvider, OpenAIProvider, AnthropicProvider

router = Router(
    providers=[
        GroqProvider(api_key=..., model="llama-3.1-70b"),
        OpenAIProvider(api_key=..., model="gpt-4o-mini"),
        AnthropicProvider(api_key=..., model="claude-haiku-4-5"),
    ],
    fallback_order=["groq", "openai", "anthropic"],
)

response = router.complete(
    messages=[{"role": "user", "content": "..."}],
    schema=MyPydanticSchema,   # optional — validates before returning
)

Fallback behavior

Router.complete() tries each provider in fallback_order, in order, and returns the first successful completion.

Triggers fallback to the next provider:

  • Rate limit (429)
  • Timeout, or the request never reaching the provider at all
  • A 5xx from the provider
  • A response that fails schema validation (when schema= is given) — a provider "responding" with unusable content isn't success

Does not trigger fallback — propagates immediately instead:

  • ProviderRequestError (e.g. 400/401/403, a malformed request, a bad API key) — this is almost always a caller misconfiguration, and switching providers would silently mask it rather than surface it
  • A plain ValueError from malformed input (e.g. multiple or misplaced system messages) — same reasoning: a different provider won't fix bad input

There is also no same-provider retry: a rate-limited or 5xx-ing provider won't un-limit itself in the next few seconds, so a failure always advances to the next provider, never the same one again. If every provider in fallback_order fails, Router.complete() raises AllProvidersFailedError with every provider's individual failure reason attached — it never silently returns None or an empty string.

Schema validation

schema= is optional. Pass a Pydantic model and Router.complete() parses the winning provider's text as JSON, validates it against the schema, and returns the validated model instance instead of a raw string. A leading/trailing markdown code fence (```json ... ```) is stripped first, since providers without strict JSON mode routinely wrap structured output that way.

Validation failure is treated as a provider failure, not a caller error — it triggers fallback to the next provider like any other retryable failure, since a provider returning malformed JSON isn't meaningfully different from a provider returning nothing at all.

Skip schema= entirely for the common case of just wanting a chat reply back as a string.

Testing / contributing

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest

Tests are contract tests against mocked provider HTTP responses — no real API calls are made, and none are required to run the suite.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

swapllm-0.1.0.tar.gz (20.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

swapllm-0.1.0-py3-none-any.whl (16.9 kB view details)

Uploaded Python 3

File details

Details for the file swapllm-0.1.0.tar.gz.

File metadata

  • Download URL: swapllm-0.1.0.tar.gz
  • Upload date:
  • Size: 20.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for swapllm-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1886c5ec204781313310cd7991adcb3cdac7b48776ed8c9223bbe475d4e4d46b
MD5 478f73d0b382d6a66144d55f3987116a
BLAKE2b-256 adabb440b4addf28fa047850621af62a712f3f68e56b3fe33229d62e8c7eefbb

See more details on using hashes here.

File details

Details for the file swapllm-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: swapllm-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for swapllm-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 941e8f97dfa7b4d33837d9fbfdd53faaad8859a549e7d9ffa6a5b986ae84ea78
MD5 03ae5510e28e8d82ca6cdc82c5d12403
BLAKE2b-256 e15d9f5fc06fdb9bd9e9607aca1f8e793061d284d1469da6f9ecd10535599f71

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page