LiteLLM în Python: Un Singur API pentru Claude, OpenAI și 100+ LLM-uri (2026)
LiteLLM abstrahează 100+ furnizori de LLM într-un singur API compatibil OpenAI. Vezi cum îl integrezi în Python cu fallback automat, load balancing, cost tracking și proxy server pentru echipe.
LiteLLM este o bibliotecă Python open-source care traduce apelurile către peste 100 de furnizori de LLM-uri (Claude, OpenAI, Gemini, Bedrock, Vertex AI, Ollama, Groq) într-un singur format compatibil cu API-ul openai.chat.completions. În loc să scrii un client separat pentru fiecare provider, apelezi litellm.completion(model="...", messages=[...]) și schimbi modelul printr-un string. În ghidul ăsta îți arăt cum îl integrez într-un pipeline real, cu fallback automat, router pentru load balancing, tracking de costuri și proxy server pentru echipe.
LiteLLM 1.7x expune un singur SDK compatibil cu openai pentru 100+ modele; schimbi providerul printr-un string precum anthropic/claude-sonnet-4-5 sau gemini/gemini-2.5-pro.
Funcția completion() este sincronă, acompletion() este async, iar ambele suportă stream=True cu format identic pentru toți providerii.
Clasa Router face load balancing între mai multe chei API și adaugă fallback-uri când un model dă rate limit sau eroare tranzitorie.
Callback-urile pentru cost și tokens (litellm.success_callback = ["langfuse"]) permit observability fără cod suplimentar în handler.
LiteLLM Proxy Server rulează ca serviciu HTTP și centralizează chei, budget-uri și guardrails pentru toată echipa, iar clienții tăi rămân cu SDK-ul OpenAI standard.
Ce este LiteLLM și când merită folosit
LiteLLM (proiect BerriAI, licență MIT) rezolvă o problemă mică, dar enervantă: fiecare furnizor de LLM are propriul SDK, propriile chei, propriile formate de răspuns și propriile particularități la streaming. Când vrei să compari două modele pe același prompt, ajungi să scrii două integrări. Când vrei fallback de la Claude la GPT-4o pentru că Anthropic a returnat 529, ajungi să scrii orchestrare manuală. LiteLLM abstractizează exact acest strat.
Din experiența mea de „recovering ops engineer", merită introdus în trei situații concrete: (1) trebuie să evaluezi mai multe modele pe același dataset fără să dublezi codul, (2) construiești un serviciu multi-tenant care oferă „LLM as a feature" și vrei să comuți providerul fără să atingi codul aplicației, (3) ai nevoie de failover între providere pentru SLA. Dacă folosești un singur model, cu un singur cont, fără cerințe de failover, SDK-ul oficial e suficient. LiteLLM adaugă complexitate care nu se plătește.
Piesa cheie e că formatul de răspuns este identic cu openai.chat.completions. Dacă mâine adaugi un model Bedrock, codul din aval (parserul de răspuns, structured outputs, function calling) nu se schimbă. Complementar, când vrei să reduci facturile pentru mesaje repetitive, urmărește ghidul nostru despre prompt caching cu Claude și OpenAI. LiteLLM propagă header-ele de caching către provider fără intervenție manuală.
Instalare și primul apel unificat
Instalarea e standard, dar îți recomand să fixezi versiunea în producție. LiteLLM iterează rapid și API-ul de router s-a schimbat între minor releases. La momentul scrierii, versiunea stabilă este 1.75.x.
pip install "litellm==1.75.*" python-dotenv
Cheia sub care se aleargă modelul se ia din variabile de mediu specifice fiecărui provider: OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, GROQ_API_KEY etc. LiteLLM le citește automat, așa că nu trebuie să le pasezi manual la fiecare apel.
import os
from dotenv import load_dotenv
from litellm import completion
load_dotenv() # încarcă OPENAI_API_KEY și ANTHROPIC_API_KEY din .env
messages = [
{"role": "system", "content": "Ești un asistent tehnic concis."},
{"role": "user", "content": "Rezumă în 2 propoziții ce face LiteLLM."},
]
# Același apel, doi provideri diferiți: schimbi doar stringul de model.
gpt = completion(model="openai/gpt-4o-mini", messages=messages, temperature=0.2)
claude = completion(model="anthropic/claude-haiku-4-5", messages=messages, temperature=0.2)
print("GPT:", gpt.choices[0].message.content)
print("Claude:", claude.choices[0].message.content)
print("Cost GPT (USD):", gpt._hidden_params["response_cost"])
Trei detalii care contează: prefixul openai/ sau anthropic/ e opțional pentru modele „canonice", dar te scutește de ambiguități când adaugi Bedrock (care are propriile ID-uri pentru Claude). Apoi, response_cost apare deja calculat în _hidden_params pe baza tabelei interne de prețuri. Și choices[0].message.content funcționează identic indiferent de provider.
Ce furnizori LLM suportă LiteLLM
La 100+ integrări active, o listă completă e inutilă, dar categoriile mari și modul de identificare al modelului sunt lucrurile utile în practică. Tabelul de mai jos rezumă providerii pe care îi întâlnesc cel mai des în workflow-uri reale.
Categorie
Exemple de string de model
Variabile de mediu
Note
OpenAI / Azure
openai/gpt-4o, azure/deployment-name
OPENAI_API_KEY, AZURE_API_BASE
Azure cere și api_version.
Anthropic direct
anthropic/claude-sonnet-4-5
ANTHROPIC_API_KEY
Suportă prompt caching prin flag-uri.
Google
gemini/gemini-2.5-pro, vertex_ai/gemini-2.5-flash
GEMINI_API_KEY sau credentials JSON
Vertex AI trece prin ADC.
AWS Bedrock
bedrock/anthropic.claude-sonnet-4-5-v1:0
AWS credentials + AWS_REGION
Bun pentru compliance/VPC.
Groq / together / Fireworks
groq/llama-3.3-70b, together_ai/...
Cheia providerului
Latență foarte mică (Groq).
Local (Ollama, vLLM)
ollama/llama3.1, openai/<model> + api_base
—
Ideal pentru dev fără cost.
Sursa oficială pentru string-urile exacte și feature-urile pe provider este lista de providers din documentația LiteLLM, actualizată aproape zilnic. Îți recomand să o verifici înainte să adaugi un provider nou. De exemplu, function calling și structured outputs nu sunt suportate uniform, iar poți vedea codul sursă direct în repo-ul BerriAI/litellm de pe GitHub dacă vrei să înțelegi cum se face translația între providere.
Streaming și apeluri async
Când construiesc UI-uri care afișează token cu token, folosesc acompletion() cu stream=True. Formatul chunk-urilor imită SSE-ul de la OpenAI, așa că același parser funcționează pentru Claude, Gemini sau Groq. Câmpul relevant este chunk.choices[0].delta.content, care poate fi None la primul chunk (rol) și la ultimul (finish reason), deci verificarea e obligatorie.
import asyncio
from litellm import acompletion
async def stream_answer(model: str, prompt: str) -> str:
buffer = []
response = await acompletion(
model=model,
messages=[{"role": "user", "content": prompt}],
stream=True,
max_tokens=400,
)
async for chunk in response:
piece = chunk.choices[0].delta.content
if piece:
buffer.append(piece)
print(piece, end="", flush=True)
return "".join(buffer)
asyncio.run(stream_answer(
"anthropic/claude-sonnet-4-5",
"Explică diferența dintre RAG și fine-tuning în 3 fraze.",
))
Un lucru care mă prinde des pe picior greșit: pe Gemini, chunk-urile pot conține blocuri mari deodată (Gemini flush-uiește pe propoziție, nu pe token), deci UI-ul poate să pară „stroboscopic". Nu e un bug LiteLLM, e comportament nativ. Dacă vrei o experiență granulară uniformă, plafonează dimensiunea chunk-ului în UI printr-un scheduler propriu, nu forța din LiteLLM.
Router: load balancing între chei și modele
Când ai două chei OpenAI (una pe „org A", una pe „org B") sau vrei să distribui traficul între GPT-4o și un Llama pe Groq în funcție de latență, folosești Router. Fiecare intrare este un model deployment, adică un mapping între un nume logic și un provider concret cu cheia lui.
Strategiile disponibile (simple-shuffle, least-busy, usage-based-routing-v2, latency-based-routing) sunt utile în ordine crescătoare a complexității. Pentru trafic mic pornesc cu simple-shuffle. Când începi să vezi rate limits (429), treci pe usage-based-routing-v2, care ține evidența token-urilor per minut per deployment.
Fallback-uri și retry între providere
Ăsta e feature-ul care mi-a salvat cel mai des noaptea. Când Anthropic dă 529 („overloaded") sau OpenAI cade pentru 4 minute, vrei ca cererea să treacă automat la alt provider. LiteLLM permite fallback-uri la nivel de router și retry-uri exponențiale cu jitter.
router = Router(
model_list=[
{"model_name": "primary", "litellm_params": {"model": "anthropic/claude-sonnet-4-5"}},
{"model_name": "backup", "litellm_params": {"model": "openai/gpt-4o"}},
],
fallbacks=[{"primary": ["backup"]}], # dacă „primary" eșuează, încearcă „backup"
num_retries=2, # 2 retry-uri pe fiecare deployment
retry_after=2, # backoff de bază în secunde
allowed_fails=3, # circuit breaker: după 3 fail-uri, deployment-ul e „cooldown"
cooldown_time=30,
)
try:
r = router.completion(
model="primary",
messages=[{"role": "user", "content": "test failover"}],
)
except Exception as e:
# ambele providere au eșuat definitiv
print("Eșec total:", e)
Trei recomandări din experiență. Nu seta num_retries mai mare de 2 pe deployment (multiplicat cu fallback, ajungi la 6-8 apeluri per cerere și poți amplifica un incident). Folosește allowed_fails plus cooldown_time ca circuit breaker, altfel trimiți trafic într-un provider degradat. Și logează întotdeauna hop-urile de fallback, pentru că altfel debugging-ul devine ghicit. Pentru un cadru mai defensiv la nivel de payload, articolul despre guardrails pentru agenți AI în Python arată cum să oprești răspunsurile toxice sau off-topic înainte să iasă în UI.
Cost tracking și observability
Fiecare răspuns include _hidden_params["response_cost"], un float în USD calculat pe baza tabelei interne de prețuri din LiteLLM. Pentru o vizualizare centralizată, LiteLLM emite callback-uri către Langfuse, Helicone, Datadog, S3 și fișiere JSON.
Când construiesc pipeline-uri de evaluare (să spunem, rulând același prompt pe 5 modele), folosesc un callback custom care scrie într-un CSV: model, tokens_in, tokens_out, cost, latency. Așa pot decide pe date reale dacă merită să înlocuiesc GPT-4o cu Claude Haiku 4.5 pentru un anumit workload. Am pățit-o cu un client care avea 40% din trafic pe un model scump degeaba; datele din CSV au fost suficient argument. Pentru evaluări structurate ale calității răspunsurilor (nu doar cost), am scris separat despre evaluarea agenților AI cu DeepEval, care se combină natural cu callback-urile din LiteLLM.
LiteLLM Proxy Server pentru echipe
Când mai mult de 2-3 developeri lovesc aceleași modele, îmi mut logica în LiteLLM Proxy Server. Rulează ca un serviciu HTTP (compatibil cu API-ul OpenAI) și centralizează cheile, budget-urile, rate-limit-urile per user, guardrails și logging. Aplicațiile client rămân cu SDK-ul OpenAI standard, doar cu base_url îndreptat spre proxy.
# pornire
litellm --config config.yaml --port 4000
# apel din client, cu SDK OpenAI standard:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:4000", api_key="sk-team-alpha")
r = client.chat.completions.create(
model="chat-smart",
messages=[{"role": "user", "content": "salut"}],
)
Câștigul real e că poți emite chei virtuale per echipă (sk-team-alpha), setezi max_budget: 20 USD/lună pe fiecare și blochezi automat abuzul. Documentația oficială pentru configurare avansată este la LiteLLM Proxy Quick Start. Merită citită înainte să deployezi în producție.
LiteLLM vs LangChain: când alegi ce
Este o întrebare pe care o primesc săptămânal. Răspunsul scurt: LiteLLM este un abstraction layer peste API-uri de LLM, iar LangChain este un framework pentru orchestrare de agenți și chains. Nu concurează direct; ba chiar LangChain folosește LiteLLM în spate în unele integrări.
Aspect
LiteLLM
LangChain
Scop principal
Un singur API pentru 100+ modele
Orchestrare de chains, agenți, tools
Suprafață API
Mică: completion(), Router, callbacks
Mare: LCEL, agents, retrievers, tools, memory
Learning curve
Ore
Zile-săptămâni
Overhead runtime
Minim (thin wrapper)
Semnificativ pe chains complexe
Fallback / load balancing
Nativ (Router)
Prin cod custom sau LangSmith
Când îl alegi
Vrei portabilitate între provideri
Vrei orchestrare declarativă
În practică, le combin: LiteLLM face apelul de model (cu fallback plus cost tracking), iar LangChain sau LangGraph construiesc grafuri de decizii deasupra. Când vezi un tutorial care importă from langchain_openai import ChatOpenAI și tu ai nevoie de 3 provideri diferiți, îl înlocuiești cu ChatLiteLLM și continui.
Greșeli comune și cum le eviți
Am adunat cinci greșeli care apar la echipele care adoptă LiteLLM pentru prima dată. Le pun în ordinea în care mușcă cel mai tare.
Chei pierdute în cod. Nu pasa api_key literal în cod versionat. Folosește os.environ sau, pentru proxy, sintaxa api_key: os.environ/OPENAI_API_KEY în YAML.
Fallback fără logging. Dacă nu emiți un event când happen fallback-ul, n-o să știi niciodată că providerul primar era jos 4 ore. Setează un callback pe failure_callback și trimite un warning în Slack/Sentry.
Retry-uri agresive care amplifică incidente. Cu num_retries=5 pe 3 deployment-uri ajungi la 15 apeluri per cerere pentru o singură eroare. Pornește de la 1-2 și crește doar dacă e nevoie.
Prețuri incorecte după update. Vezi callout-ul din secțiunea de cost tracking. Pin la versiune și verifică litellm.model_cost după fiecare upgrade.
Formate diferite la function calling. Deși completion e uniform, tool calling are subtilități între provideri (Claude cere tool_choice într-un format ușor diferit de OpenAI). Testează pe fiecare provider înainte de producție.
Întrebări frecvente
Este LiteLLM gratuit?
Da. Biblioteca Python și serverul Proxy sunt open-source sub licență MIT. BerriAI (compania din spate) oferă și o versiune Enterprise cu SSO, audit logs și support, dar pentru majoritatea echipelor versiunea gratuită acoperă tot ce ai nevoie inclusiv în producție.
Cum apelezi Claude prin LiteLLM?
Setezi ANTHROPIC_API_KEY și apelezi litellm.completion(model="anthropic/claude-sonnet-4-5", messages=[...]). Formatul răspunsului e identic cu OpenAI, deci resp.choices[0].message.content funcționează la fel. Pentru Bedrock, folosești bedrock/anthropic.claude-sonnet-4-5-v1:0 cu credentials AWS.
Ce diferență e între LiteLLM SDK și LiteLLM Proxy?
SDK-ul este o bibliotecă pe care o importezi în aplicația ta Python. Proxy-ul este un serviciu HTTP separat (deploy-uit ca container) care expune un API compatibil OpenAI și centralizează chei, budget-uri și logging pentru toată echipa. Poți folosi SDK direct sau prin proxy; proxy-ul devine util când mai mulți developeri sau microservicii lovesc aceleași modele.
Suportă LiteLLM streaming și async?
Da, ambele. Folosești litellm.completion(..., stream=True) pentru sync sau litellm.acompletion(..., stream=True) pentru async. Chunk-urile respectă formatul SSE al OpenAI, ceea ce înseamnă că același cod de parsare funcționează pentru Claude, Gemini, Groq și restul provider-ilor suportați.
Cum urmăresc costurile LLM cu LiteLLM?
Fiecare răspuns are _hidden_params["response_cost"], un float USD calculat automat. Pentru dashboarding centralizat, activezi callback-uri: litellm.success_callback = ["langfuse"] trimite trace-urile în Langfuse, iar Proxy Server-ul agregă costurile per cheie virtuală și le expune în UI.
Cum activezi prompt caching cu Claude și OpenAI în Python: cod complet, reguli de invalidare, benchmark real cu numere din producție și când NU merită.
Ghid practic pentru Structured Outputs cu OpenAI și Pydantic în Python: JSON garantat, exemple de cod și comparație cu Claude tool use, plus capcanele întâlnite în producție.
Ghid practic pentru testarea agenților AI cu DeepEval în Python. Acoperă metrici LLM, tool correctness, tracing cu @observe, integrare pytest și CI/CD — cu cod funcțional verificat.