CodeWorlds
Powrót do kolekcji
Przewodnik14 min czytaniaZespół CodeWorlds

LiteLLM, jedna brama do stu dostawców modeli

LiteLLM daje jeden interfejs zgodny z OpenAI do wielu dostawców. Wersja 1.97.0, proxy z kluczami i budżetami oraz podzielona licencja MIT plus enterprise.

LiteLLM, jedna brama do stu dostawców modeli

LiteLLM to warstwa pośrednicząca, która sprowadza interfejsy wielu dostawców modeli językowych do jednego kształtu, tego znanego z OpenAI. Występuje w dwóch postaciach: biblioteki Pythona wpinanej wprost do kodu oraz serwera proxy, który wystawia bramę z kluczami, limitami i budżetami rozliczanymi per zespół.

Bieżąca stabilna wersja pakietu litellm w PyPI to 1.97.0 z 16 sierpnia 2026 roku, przy czym gałąź główna deklaruje już 1.99.0, a wydania rozwojowe wychodzą co kilka dni. Repozytorium BerriAI/litellm powstało w lipcu 2023 roku, ma około 56,9 tysiąca gwiazdek, 10,7 tysiąca rozgałęzień i blisko 5 tysięcy otwartych zgłoszeń. Nie jest zarchiwizowane, ostatnia zmiana pochodzi z dnia pisania tego tekstu.

Co LiteLLM właściwie robi

Dwie postacie tego samego projektu rozwiązują dwa różne problemy i mylenie ich ze sobą jest najczęstszym źródłem nieporozumień przy pierwszym kontakcie.

Postać pierwsza to biblioteka. Wywołujesz litellm.completion() z nazwą modelu poprzedzoną prefiksem dostawcy, a biblioteka tłumaczy Twoje parametry na format docelowego interfejsu, wysyła żądanie i normalizuje odpowiedź do kształtu obiektu z biblioteki OpenAI. Zmiana dostawcy sprowadza się do zmiany łańcucha znaków w polu model. Pakiet ma niewielki zestaw zależności, między innymi openai, httpx, tiktoken, pydantic, tokenizers i boto3, i wymaga Pythona w wersji od 3.10 do 3.14 włącznie.

Postać druga to proxy, nazywane w dokumentacji bramą. Jest to serwer oparty o FastAPI, domyślnie na porcie 4000, który wystawia te same ścieżki co interfejs OpenAI, czyli /chat/completions, /embeddings i pozostałe. Twoje aplikacje używają zwykłego klienta OpenAI, podmieniasz jedynie api_base i klucz. Po stronie bramy siedzi konfiguracja z listą modeli, klucze wirtualne wydawane zespołom, limity zapytań i tokenów na minutę, budżety kwotowe oraz zapis wydatków do bazy PostgreSQL.

Czego LiteLLM nie robi, też trzeba wiedzieć. Nie uruchamia modeli, więc do pracy lokalnej i tak potrzebujesz Ollamy albo serwera wnioskowania, a LiteLLM tylko doda przed nimi wspólny interfejs. Nie jest platformą obserwowalności, choć potrafi wysyłać ślady do Langfuse czy Helicone. Nie jest też frameworkiem agentowym ani warstwą orkiestracji promptów.

Licencja, czyli dlaczego GitHub pokazuje NOASSERTION

Interfejs programistyczny GitHuba raportuje dla tego repozytorium licencję NOASSERTION o nazwie „Other". Nie jest to błąd wykrywacza ani niedopatrzenie autorów. Repozytorium naprawdę ma licencję mieszaną i to jest informacja, którą trzeba mieć przed wdrożeniem, a nie po audycie.

Plik LICENSE w katalogu głównym zaczyna się od klauzuli dzielącej kod na dwie części. Cała zawartość katalogu enterprise/ podlega osobnej licencji zdefiniowanej w tym katalogu, a wszystko poza nim jest dostępne na licencji MIT z prawami autorskimi Berri AI z 2023 roku. Ponieważ pierwsze zdanie pliku nie pasuje do wzorca czystego MIT, automatyczny wykrywacz odmawia rozpoznania i zwraca NOASSERTION. Drobna niekonsekwencja: klauzula odsyła do pliku enterprise/LICENSE, a plik nazywa się w rzeczywistości enterprise/LICENSE.md.

Treść tej drugiej licencji jest wyraźna. Nosi nazwę BerriAI Enterprise License, prawa autorskie od 2024 roku należą do Berrie AI Inc. Oprogramowanie z tego katalogu wolno używać produkcyjnie wyłącznie wtedy, gdy zgodziłeś się na warunki subskrypcji BerriAI i utrzymujesz ważną licencję na odpowiednią liczbę stanowisk. Kopiowanie i modyfikowanie na potrzeby rozwoju i testów jest dozwolone bez subskrypcji, ale prawa do wszelkich Twoich modyfikacji i łatek pozostają przy BerriAI, a korzystanie z nich również wymaga licencji. Kopiowanie, scalanie, publikowanie, dystrybuowanie, sublicencjonowanie i sprzedaż są wprost zabronione.

Do tego dochodzi szczegół, który wymyka się pobieżnemu sprawdzeniu. Pole licencji pakietu litellm w PyPI ma wartość MIT i to prawda dla samej biblioteki. Ale plik pyproject.toml w gałęzi głównej definiuje dodatkowy zestaw zależności o nazwie proxy, a w nim znajdują się dwie własne paczki projektu: litellm-proxy-extras w wersji 0.4.88, objęta licencją MIT, oraz litellm-enterprise, którego pole licencji brzmi LicenseRef-Proprietary. Wydanie stabilne 1.97.0 przypina go w wersji 0.1.54, gałąź główna w 0.1.58, ale numer nie ma tu znaczenia: polecenie pip install "litellm[proxy]" w każdym z tych wariantów ściąga na dysk pakiet objęty warunkami komercyjnymi, nawet jeśli nie zamierzasz korzystać z żadnej płatnej funkcji.

Rozbieżność między jednym a drugim źródłem jest zresztą typowa dla projektów o otwartym rdzeniu i płatnej obwódce. Metadane pakietu opisują to, co znajduje się w opublikowanej paczce, a nie warunki obowiązujące pakiety wciągane razem z nim jako zależności. Narzędzie zbierające licencje po samym polu z rejestru pokaże więc czyste MIT, choć w środowisku wyląduje coś jeszcze.

Praktyczny wniosek dla zespołu jest trzystopniowy. Sama biblioteka jest czystym MIT i nie stwarza problemu. Instalacja proxy dokłada do środowiska pakiet zastrzeżony, którego funkcje odblokowuje dopiero klucz licencyjny, więc samo jego obecność nie jest naruszeniem, ale skaner licencji w firmie to wychwyci i trzeba mieć na to gotową odpowiedź. Jeśli natomiast planujesz produkcyjnie używać funkcji z katalogu enterprise, potrzebujesz umowy. Wyjątkiem jest logowanie jednokrotne, które według dokumentacji jest darmowe do pięciu użytkowników.

Biblioteka: jedno wywołanie, wielu dostawców

Instalacja i pierwsze uruchomienie wyglądają tak, przy czym pierwsze polecenie daje część czysto MIT, a drugie dokłada wspomniany pakiet komercyjny.

Code
Bash
# sama biblioteka, licencja MIT
pip install litellm

# brama razem z pakietem litellm-enterprise na licencji komercyjnej
pip install "litellm[proxy]"

# uruchomienie bramy na porcie 4000
litellm --config config.yaml

# to samo z pelnymi logami diagnostycznymi
litellm --config config.yaml --detailed_debug

# wariant kontenerowy z rejestru GHCR
docker run -p 4000:4000 \
  -v "$(pwd)/config.yaml:/app/config.yaml" \
  ghcr.io/berriai/litellm:main-stable --config /app/config.yaml

Wywołanie modelu w kodzie sprowadza się do jednej funkcji. Nazwa modelu składa się z prefiksu dostawcy i identyfikatora, a klucze biblioteka odczytuje ze zmiennych środowiskowych.

Code
Python
import os
import litellm
from litellm import completion, completion_cost

os.environ["ANTHROPIC_API_KEY"] = "..."
os.environ["OPENAI_API_KEY"] = "..."

litellm.drop_params = True

odpowiedz = completion(
    model="anthropic/claude-sonnet-5",
    messages=[{"role": "user", "content": "Streszcz ten raport w pieciu punktach."}],
    max_tokens=1024,
)

print(odpowiedz.choices[0].message.content)
print(odpowiedz.usage.total_tokens)
print(completion_cost(completion_response=odpowiedz))
print(odpowiedz._hidden_params["response_cost"])

Ustawienie litellm.drop_params zasługuje na osobne zdanie, bo rozstrzyga o tym, czy przenośność w ogóle działa. Dostawcy różnią się zestawem przyjmowanych parametrów i wysłanie do jednego z nich pola, którego nie zna, kończy się błędem. Włączony przełącznik każe bibliotece po cichu odrzucić parametry nieobsługiwane przez cel. Wygoda jest realna, ale cena też: przełączasz się na innego dostawcę, Twój parametr znika bez komunikatu, a odpowiedzi zaczynają wyglądać inaczej, niż się spodziewasz. Do pracy produkcyjnej lepiej trzymać ten przełącznik wyłączony i świadomie obsługiwać różnice.

Funkcja completion_cost liczy koszt wywołania w dolarach na podstawie zliczonych tokenów i cennika modelu, a cost_per_token rozbija to na wejście i wyjście. Cennik pochodzi z listy utrzymywanej przez społeczność, dostępnej pod adresem api.litellm.ai. To wygodne i zarazem najsłabsze ogniwo całego śledzenia wydatków, bo lista może odbiegać od faktycznych stawek dostawcy, zwłaszcza tuż po zmianach cennika albo przy modelu świeżo wydanym. Liczby z LiteLLM traktuj jako oszacowanie do porównań między zespołami, a nie jako podstawę fakturowania.

Proxy: klucze wirtualne, budżety i limity

Konfiguracja bramy mieści się w jednym pliku YAML o czterech głównych sekcjach: model_list, router_settings, litellm_settings i general_settings. Poniżej układ pokrywający typowy przypadek, czyli dwa wdrożenia tego samego modelu do rozłożenia ruchu, model zapasowy u innego dostawcy i jeden model lokalny.

Code
YAML
model_list:
  - model_name: gpt-4o
    litellm_params:
      model: azure/gpt-4o-eu
      api_base: https://moj-punkt-europa.openai.azure.com/
      api_key: os.environ/AZURE_API_KEY_EU
      rpm: 600
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
      rpm: 600
  - model_name: claude
    litellm_params:
      model: anthropic/claude-sonnet-5
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: lokalny
    litellm_params:
      model: ollama/llama3
      api_base: http://127.0.0.1:11434

router_settings:
  routing_strategy: least-busy
  num_retries: 2
  allowed_fails: 3
  cooldown_time: 30
  fallbacks: [{ "gpt-4o": ["claude"] }]

litellm_settings:
  drop_params: false
  success_callback: ["langfuse"]

general_settings:
  master_key: sk-1234
  database_url: "postgresql://uzytkownik:haslo@host:5432/litellm"

Rozdzielenie model_name od litellm_params.model jest sednem całej konstrukcji. Pierwsze pole to nazwa widziana przez klienta, drugie to faktyczny model przekazywany do wywołania. Dwa wpisy o tej samej nazwie widocznej na zewnątrz tworzą grupę, między którą brama rozkłada ruch. Klucze podaje się zapisem os.environ/NAZWA, który każe odczytać zmienną środowiskową zamiast trzymać sekret w pliku. Klucz główny lepiej ustawić zmienną LITELLM_MASTER_KEY niż wpisywać go w konfiguracji, jak w powyższym przykładzie zostawionym dla czytelności.

Klucze wirtualne wydaje się przez punkt końcowy /key/generate, autoryzując się kluczem głównym. Każdy klucz ma własną listę dozwolonych modeli, przypisanie do zespołu, budżet z okresem odnowienia oraz limity przepustowości.

Code
Bash
curl -X POST 'http://0.0.0.0:4000/key/generate' \
  -H 'Authorization: Bearer sk-1234' \
  -H 'Content-Type: application/json' \
  -d '{
    "models": ["gpt-4o", "claude"],
    "team_id": "zespol-wyszukiwarki",
    "max_budget": 50,
    "budget_duration": "30d",
    "tpm_limit": 200000,
    "rpm_limit": 300,
    "metadata": {"aplikacja": "wyszukiwarka-wewnetrzna"}
  }'

# biezacy stan wydatkow dla klucza
curl 'http://0.0.0.0:4000/key/info?key=sk-XXXX' \
  -H 'Authorization: Bearer sk-1234'

Wydatki trafiają do tabeli LiteLLM_VerificationTokenTable, a jeśli klucz ma przypisanego użytkownika albo zespół, dodatkowo do LiteLLM_UserTable i LiteLLM_TeamTable. Stan odczytasz przez punkty końcowe /key/info, /user/info i /team/info, a nowego użytkownika założysz przez /user/new. Kwota rośnie po każdym rozliczonym wywołaniu, więc budżet nie blokuje pojedynczego przekroczenia progu, tylko kolejne żądania po jego przekroczeniu.

Dziedziczenie uprawnień ma tu kilka niespodzianek. Klucz utworzony przez administratora bez jawnego pola user_id nie ma właściciela i nie dziedziczy niczego, bo automatyczne stemplowanie identyfikatora dotyczy tylko wywołań spoza roli administratora. W drugą stronę: klucz należący do administratora przechodzi obok ograniczeń tras zarządczych i może tworzyć kolejne klucze, użytkowników i zespoły. Ogranicza go dopiero pole allowed_routes ustawione bezpośrednio na kluczu.

Routing, fallbacki i liczenie kosztu

Ten sam mechanizm równoważenia obciążenia jest dostępny w bibliotece przez klasę Router, bez stawiania serwera. Bywa to sensowny punkt pośredni, gdy chcesz odporności na awarie dostawcy, ale nie potrzebujesz jeszcze wspólnej bramy dla wielu zespołów.

Code
Python
from litellm import Router

router = Router(
    model_list=[
        {
            "model_name": "gpt-4o",
            "litellm_params": {"model": "azure/gpt-4o-eu", "api_key": "..."},
        },
        {
            "model_name": "gpt-4o",
            "litellm_params": {"model": "openai/gpt-4o", "api_key": "..."},
        },
        {
            "model_name": "claude",
            "litellm_params": {"model": "anthropic/claude-sonnet-5", "api_key": "..."},
        },
    ],
    fallbacks=[{"gpt-4o": ["claude"]}],
    routing_strategy="latency-based-routing",
    num_retries=2,
    cooldown_time=30,
)

odpowiedz = await router.acompletion(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Czesc"}],
)

Strategie routingu obejmują między innymi simple-shuffle, czyli losowy wybór wdrożenia, least-busy, latency-based-routing oraz cost-based-routing, które kieruje ruch do najtańszego dostępnego wdrożenia w grupie. Fallbacki działają na poziomie nazw grup, a nie pojedynczych wdrożeń, i przechodzą po liście w podanej kolejności. Osobne pole default_fallbacks obsługuje przypadek, w którym cała grupa jest źle skonfigurowana. Parametry allowed_fails i cooldown_time decydują o tym, po ilu błędach wdrożenie wypada z puli i na jak długo.

Jedna zmiana zachowania potrafi zaskoczyć przy pisaniu testów. Flagi mock_testing_fallbacks, mock_testing_context_fallbacks i mock_testing_content_policy_fallbacks od wersji 1.85.0 są usuwane z żądań przychodzących do bramy i nie mają tam żadnego efektu. Działają wyłącznie przy bezpośrednich wywołaniach klasy Router. Weryfikacja fallbacków na proxy wymaga więc wywołania prawdziwego błędu dostawcy w środowisku nieprodukcyjnym.

Co dokłada Enterprise i ile to kosztuje

Podział między wersją otwartą a płatną jest opisany dość szczegółowo i przebiega wzdłuż granicy między działaniem a zarządzaniem. Wersja otwarta obejmuje bramę zgodną z OpenAI, klucze wirtualne, użytkowników i zespoły, śledzenie wydatków, budżety, limity, fallbacki, logowanie żądań i odpowiedzi oraz metryki dla Prometheusa.

Warstwa płatna dokłada logowanie jednokrotne wraz z SCIM, uwierzytelnianie tokenami OIDC i JWT, dzienniki audytowe z politykami retencji, kontrolę dostępu opartą o role z organizacjami i administratorami zespołów, listy dostępu po adresach IP, rotację kluczy oraz integracje z menedżerami sekretów, między innymi AWS KMS, AWS Secrets Manager, Azure Key Vault, Google KMS, Google Secret Manager, HashiCorp Vault i CyberArk. Po stronie kontroli kosztów dochodzą budżety po znacznikach, budżety osobne dla każdego modelu w obrębie jednego klucza, czasowe podniesienia limitu i alerty przed przekroczeniem progu. Po stronie obserwowalności: kierowanie logów każdego zespołu do jego własnego projektu, wyłączanie logowania na poziomie zespołu i eksport do Google Cloud Storage albo Azure Blob.

Osobno wymieniono coś, co łatwo przeoczyć przy planowaniu zabezpieczeń. Framework guardraili w wersji otwartej obsługuje własne implementacje oraz Presidio do maskowania danych osobowych, natomiast siedem gotowych integracji wymaga licencji: llmguard_moderations, llamaguard_moderations, hide_secrets, openai_moderations, google_text_moderation, lakera_prompt_injection oraz aporia_prompt_injection. Jeśli Twój projekt zaczyna się od zdania „potrzebujemy moderacji treści i wykrywania wstrzykiwania promptów", to jesteś po płatnej stronie granicy.

Cennika publicznego nie ma. Strona z planami podaje mechanizm rozliczenia zamiast kwot: umowa roczna, wycena według rocznej pojemności zapytań bramy, architektury wdrożenia i zakresu wsparcia, wprost bez opłaty od tokena. Dostępny jest trzydziestodniowy klucz próbny wydawany bez rozmowy handlowej. Umowa wsparcia opisuje czasy reakcji: godzina dla awarii całkowitej, sześć godzin dla częściowej, doba dla spraw konfiguracyjnych i siedemdziesiąt dwie godziny dla podatności. Dostawca deklaruje SOC 2 Type 2 oraz ISO 27001, a wdrożenie odizolowane od sieci jest możliwe. Nazwy dwóch poziomów, Standard i SCALE, pojawiają się w odpowiedziach na pytania, bez przypisanych im kwot.

LiteLLM a alternatywy

CechaLiteLLMOpenRouterHeliconeOllamaSDK dostawcy
Rolabrama i bibliotekabrama jako usługaobserwowalność i bramauruchamianie modeli lokalnieklient jednego dostawcy
Gdzie działaTwoja infrastrukturainfrastruktura dostawcyusługa albo własny hostingTwój sprzętw Twoim procesie
Klucze i budżety per zespółtak, w wersji otwartejtak, po stronie usługitak, po stronie usługibrakbrak
Model licencyjnyMIT plus katalog enterprise na licencji komercyjnejusługa zamkniętaotwarty rdzeń plus usługaotwarte źródłabiblioteka klienta
Co płaciszhosting, opcjonalnie licencja rocznamarżę doliczaną do stawek modeliplan usługiprąd i sprzętstawki dostawcy

Wybór rozstrzyga się na pytaniu o to, gdzie mają leżeć klucze do modeli. Jeśli muszą zostać w Twojej infrastrukturze, a wiele zespołów potrzebuje rozliczanego dostępu, LiteLLM jest naturalnym kandydatem i wersja otwarta wystarcza na start. Jeśli wolisz nie utrzymywać kolejnego serwera z bazą PostgreSQL, brama jako usługa zdejmuje z Ciebie pracę operacyjną kosztem marży i zaufania do pośrednika. Jeśli natomiast korzystasz z jednego dostawcy i nie planujesz zmiany, warstwa pośrednia dokłada opóźnienie i punkt awarii bez wyraźnego zysku, a wywołanie OpenAI albo Claude wprost jest prostsze.

Typowe błędy

Pierwszy to potraktowanie całego repozytorium jako MIT na podstawie pola w PyPI. Katalog enterprise ma własną licencję komercyjną, a instalacja z dodatkiem proxy wciąga pakiet litellm-enterprise opisany jako zastrzeżony. Zapisz to w rejestrze zależności, zanim zrobi to za Ciebie audyt.

Drugi to drop_params włączone globalnie i zapomniane. Parametr nieznany dostawcy znika bez komunikatu, więc po przełączeniu modelu zachowanie zmienia się cicho i diagnostyka zaczyna się od złego tropu.

Trzeci to traktowanie kosztu liczonego przez LiteLLM jak danych rozliczeniowych. Cennik pochodzi z listy utrzymywanej przez społeczność i bywa nieaktualny, zwłaszcza dla modeli wydanych niedawno. Porównuj go okresowo z rachunkiem od dostawcy.

Czwarty to klucze administracyjne bez ustawionego pola allowed_routes. Klucz, którego właścicielem jest administrator, pomija ograniczenia tras zarządczych i może wydawać kolejne klucze oraz zmieniać zespoły.

Piąty to poleganie na flagach mock_testing_* przy testowaniu fallbacków na bramie. Od wersji 1.85.0 są one usuwane z żądań i test przechodzi, choć niczego nie sprawdza.

Szósty to niezapięta wersja obrazu albo pakietu. Wydania rozwojowe wychodzą co kilka dni, a tag main-stable przesuwa się razem z nimi. W środowisku produkcyjnym podaj numer wersji, tak jak robi to dokumentacja przy wykresie Helma.

Siódmy to uruchomienie bramy bez bazy danych i zdziwienie, że klucze nie działają. Punkt końcowy /key/generate wymaga skonfigurowanego database_url, bo wszystkie klucze, budżety i wydatki żyją w PostgreSQL, a nie w pliku konfiguracyjnym.

FAQ

Czy LiteLLM jest darmowy do użytku komercyjnego?

Biblioteka tak, na licencji MIT. Brama również, dopóki nie sięgasz po funkcje z katalogu enterprise, których produkcyjne użycie wymaga umowy subskrypcyjnej i licencji na liczbę stanowisk. Logowanie jednokrotne jest darmowe do pięciu użytkowników.

Dlaczego GitHub pokazuje dla tego repozytorium NOASSERTION?

Bo plik LICENSE nie jest czystym tekstem MIT. Zaczyna się od klauzuli, która wyłącza katalog enterprise spod MIT i przypisuje mu osobną licencję komercyjną. Automatyczny wykrywacz nie potrafi opisać takiego podziału i zwraca wartość „Other".

Czy potrzebuję proxy, czy wystarczy sama biblioteka?

Do jednej aplikacji wystarczy biblioteka, a odporność na awarie dostawcy załatwi klasa Router. Proxy ma sens wtedy, gdy wielu zespołom trzeba wydać osobne klucze z budżetami i limitami albo gdy klucze dostawców mają leżeć w jednym miejscu zamiast w każdym repozytorium z osobna.

Jak dokładne jest śledzenie kosztów?

Liczone jest z tokenów i cennika pobieranego z listy utrzymywanej przez społeczność pod adresem api.litellm.ai. Wystarcza do porównań i budżetów, ale przy nowych modelach albo świeżej zmianie cennika potrafi się rozjechać z rachunkiem, więc raz na jakiś czas zestaw obie liczby.

Czy dane przechodzą przez serwery LiteLLM?

Nie przy samodzielnym hostingu, a to domyślny i jedyny wariant wdrożenia. Ruch idzie z Twojej infrastruktury wprost do dostawców. Do sieci wychodzi natomiast zapytanie o listę cenników modeli.

Co się stanie, gdy dostawca zwróci błąd?

Brama ponawia żądanie zgodnie z num_retries, a po przekroczeniu allowed_fails wyłącza wdrożenie z puli na czas cooldown_time. Jeśli cała grupa jest niedostępna, ruch przechodzi na grupę wskazaną w fallbacks, w kolejności podanej na liście.

Dokumentację znajdziesz na stronie projektu, listę funkcji płatnych w dziale Enterprise, a treść licencji komercyjnej w pliku enterprise/LICENSE.md.

Czytaj dalej

Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie