Building directly against one vendor's SDK (say, the OpenAI Python client) works fine until you need to add a second provider — for redundancy if one has an outage, for cost comparison, or because a customer requires a specific model family for compliance reasons. At that point, every call site in your codebase that assumed OpenAI's exact response shape becomes a migration problem. LiteLLM exists specifically to avoid that: write against its unified interface once, and vendor switching becomes a config change.
Adopting a vendor-neutral interface
1. Replace direct vendor SDK calls with LiteLLM's completion(). The function signature mirrors the OpenAI chat completions API, so migrating existing OpenAI-based code is usually a light touch, not a rewrite.
2. Set the model string per-provider using LiteLLM's naming convention. Most providers are addressed as provider/model-name or a bare model name LiteLLM recognizes — check the current provider list before hardcoding a string, since naming conventions vary slightly by vendor.
3. Keep response-handling code vendor-agnostic. Since LiteLLM normalizes every response to the same shape, avoid writing any parsing logic that assumes a vendor-specific response field — that's the abstraction you're paying for.
# pip install litellm
from litellm import completion
def ask(model: str, prompt: str) -> str:
response = completion(
model=model, # swap this string to switch vendors
messages=[{"role": "user", "content": prompt}]
)
# Same response shape regardless of which vendor answered
return response.choices[0].message.content
# Same function, three different vendors:
ask("gpt-4o", "Explain vendor lock-in in one sentence.")
ask("claude-sonnet-5", "Explain vendor lock-in in one sentence.")
ask("gemini/gemini-2.0-flash", "Explain vendor lock-in in one sentence.")
| Approach | Effort to Add a Second Vendor |
|---|---|
| Direct vendor SDK integration | High — every call site needs vendor-specific request/response handling |
LiteLLM unified completion() interface |
Low — change the model string, response-handling code stays the same |
This kind of abstraction has a real cost: you're depending on LiteLLM to keep its provider mappings current as vendors change their APIs, and vendor-specific features that don't map cleanly to the unified interface (a provider's unique parameter, say) may need vendor-specific handling anyway. For the common case — text generation across mainstream providers — the trade is usually worth it.
Practical Challenge
Take an existing script that calls one provider's SDK directly, rewrite it using LiteLLM's completion(), and confirm it produces the same output — then swap the model string to a second provider and run it again with zero other code changes.
Concept Check
completion() interface actually normalize across providers?Sources & Further Reading
- LiteLLM Docs: Getting Started — the official documentation for the SDK's unified
completion()interface. - LiteLLM Docs: Supported Providers — the current list of 100+ supported providers and their model-string naming conventions.
- LiteLLM (GitHub) — the open-source repository referenced throughout this article.
AI