Provider Migration
Switch between LLM providers — wrapping different clients, gradual migration, and cross-provider failover
import os
from anthropic import Anthropic
from openai import OpenAI
from solwyn import Solwyn
# OpenAI primary, with Anthropic as a cross-provider fallback
client = Solwyn(
OpenAI(),
model="gpt-4o",
api_key=os.environ["SOLWYN_API_KEY"],
fallback=[(Anthropic(), "claude-sonnet-4-5", {"max_tokens": 1024})],
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
client.close()Solwyn auto-detects the provider from the client you wrap, which makes it straightforward to switch between LLM providers, run side-by-side evaluations, or build a failover chain that spans providers.
Same-provider model fallback
To retry a failed call on a cheaper or more available model on the same provider, add a fallback entry that reuses the provider client with a different model:
import os
from openai import OpenAI
from solwyn import Solwyn
client = Solwyn(
OpenAI(),
model="gpt-4o",
api_key=os.environ["SOLWYN_API_KEY"],
fallback=[(OpenAI(), "gpt-4o-mini")],
)If gpt-4o fails — a 429 from rate limits, a model-specific outage — the SDK retries on gpt-4o-mini using the same OpenAI client. A success on this hop is tagged is_model_fallback=true.
Cross-provider failover
Unlike earlier versions, cross-provider failover is now built in: list a fallback entry on a different provider and Solwyn translates the request automatically when it fails over.
import os
from anthropic import Anthropic
from openai import OpenAI
from solwyn import Solwyn
client = Solwyn(
OpenAI(),
model="gpt-4o",
api_key=os.environ["SOLWYN_API_KEY"],
fallback=[
(OpenAI(), "gpt-4o-mini"), # same-provider first
(Anthropic(), "claude-sonnet-4-5", {"max_tokens": 1024}), # then cross-provider
],
)You no longer need to construct multiple Solwyn clients and route between them by hand. See Provider Failover for translation limits, selection policies, and tuning. Amazon Bedrock entries participate in both directions — for example Bedrock-hosted Claude with direct Anthropic as the fallback, or the reverse.
Migrating between OpenAI-dialect providers
Migrating from OpenAI to an OpenAI-compatible provider (or between two of them) is the smallest possible migration: the call surface stays chat.completions.create, and only the client construction changes — point the openai.OpenAI client at the new endpoint via base_url. Solwyn detects the real provider from the URL, so attribution, budgets, and the dashboard switch to the new provider name automatically:
import os
from openai import OpenAI
from solwyn import Solwyn
client = Solwyn(
OpenAI(), # primary: OpenAI
model="gpt-4o",
api_key=os.environ["SOLWYN_API_KEY"],
fallback=[
(
OpenAI(
base_url="https://api.groq.com/openai/v1",
api_key=os.environ["GROQ_API_KEY"],
),
"llama-3.3-70b-versatile", # fallback: Groq — detected from base_url
),
],
)Failover hops between providers that share the Chat Completions dialect are native passthrough — tools, JSON mode, and streaming survive the hop. For an endpoint auto-detection cannot name (a vLLM server on a non-default port, a private gateway), set the identity explicitly with provider= on the constructor or as the 4th element of a fallback spec. See Provider Failover.
Switching primary providers
To switch your primary provider, change the client you pass to Solwyn():
Before: OpenAI primary
import os
from openai import OpenAI
from solwyn import Solwyn
client = Solwyn(
OpenAI(),
model="gpt-4o",
api_key=os.environ["SOLWYN_API_KEY"],
fallback=[(OpenAI(), "gpt-4o-mini")],
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Summarize this document."}],
)
print(response.choices[0].message.content)
client.close()After: Anthropic primary
import os
from anthropic import Anthropic
from solwyn import Solwyn
client = Solwyn(
Anthropic(),
model="claude-sonnet-4-5",
api_key=os.environ["SOLWYN_API_KEY"],
default_params={"max_tokens": 1024},
fallback=[(Anthropic(), "claude-haiku-4-5-20251001")],
)
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Summarize this document."}],
)
print(response.content[0].text)
client.close()The change is the import/client construction and the call surface (chat.completions.create vs messages.create). The Solwyn configuration, budget tracking, and reporting all carry over.
Comparing providers with separate tracking
To evaluate providers side-by-side, use separate project keys so costs and latency are tracked independently:
import os
from anthropic import Anthropic
from openai import OpenAI
from solwyn import Solwyn
prompt = "Explain the CAP theorem in three sentences."
# Track OpenAI costs under one project key
openai_client = Solwyn(
OpenAI(),
api_key=os.environ["SOLWYN_OPENAI_EVAL_KEY"],
)
# Track Anthropic costs under another project key
anthropic_client = Solwyn(
Anthropic(),
api_key=os.environ["SOLWYN_ANTHROPIC_EVAL_KEY"],
)
oai_response = openai_client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
)
ant_response = anthropic_client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
print("OpenAI:", oai_response.choices[0].message.content)
print("Anthropic:", ant_response.content[0].text)
openai_client.close()
anthropic_client.close()The Solwyn dashboard shows per-project cost breakdowns, making it easy to compare providers on the same workload.
Environment-based provider selection
Use environment variables to control which provider is active without code changes:
import os
from solwyn import Solwyn
provider = os.environ.get("LLM_PROVIDER", "openai")
if provider == "openai":
from openai import OpenAI
llm_client = OpenAI()
elif provider == "anthropic":
from anthropic import Anthropic
llm_client = Anthropic()
elif provider == "google":
from google import genai
llm_client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
elif provider == "bedrock":
import boto3
llm_client = boto3.client("bedrock-runtime", region_name="us-east-1")
elif provider == "groq":
from openai import OpenAI
llm_client = OpenAI(
base_url="https://api.groq.com/openai/v1",
api_key=os.environ["GROQ_API_KEY"],
)
elif provider == "together":
from together import Together
llm_client = Together() # reads TOGETHER_API_KEY itself
elif provider == "zai":
from openai import OpenAI
llm_client = OpenAI(
base_url="https://api.z.ai/api/paas/v4",
api_key=os.environ["ZAI_API_KEY"],
)
else:
raise ValueError(f"Unknown provider: {provider}")
client = Solwyn(
llm_client,
api_key=os.environ["SOLWYN_API_KEY"],
)This pattern lets you switch providers per deployment environment (staging uses one provider, production uses another) while maintaining consistent cost tracking.