Przewodnik po serwowaniu LoRAX: adaptery LoRA w Kubernetes na dużą skalę
Tłumaczenie automatyczne Ten artykuł został automatycznie przetłumaczony z angielskiego oryginału.
Jeden model bazowy i wiele adapterów LoRA tworzą nietypowy problem z serwowaniem. Wagi bazowe są współdzielone, ale każde żądanie może wymagać innego zestawu wag adaptera. Konwencjonalny model wdrażania osobnego deploymentu dla każdego wariantu marnuje pamięć GPU, gdy większość wariantów pozostaje bezczynna.
LoRAX rozwiązuje problem long tail. Ładuje adaptery na żądanie, tworzy batche żądań dla różnych adapterów oraz przenosi wagi adapterów między pamięcią GPU i CPU. Atrakcyjne hasło brzmi: „tysiące fine-tuned modeli na jednym GPU”. Pytanie inżynieryjne jest węższe: biorąc pod uwagę aktywny zestaw adapterów, wzorzec napływu żądań i docelowe opóźnienie, czy harmonogramowanie wymiany zapewnia wystarczające korzyści, aby uzasadnić użycie kolejnego runtime’u do serwowania?
Ten przewodnik jest przeznaczony dla inżynierów zajmujących się inferencją i platformą, którzy muszą serwować wiele wariantów LoRA z jednego modelu bazowego. Pokazuje, jak przetestować udokumentowane API, oszacować rozmiar working setu i przekształcić początkowy Helm chart w jawnie zdefiniowany plan produkcyjny.
Podsumowanie. Wybierz LoRAX, gdy wiele kompatybilnych adapterów LoRA współdzieli jeden model bazowy, a ruch jest rzadki lub ma rozkład long-tail. Pojemność zależy od aktywnego working setu, a nie od rozmiaru katalogu. Przypnij wersję runtime’u, uwierzytelniaj i allowlistuj identyfikatory adapterów, dodaj trwały cache artefaktów i probe’y, routuj z uwzględnieniem lokalności cache oraz mierz osobno ścieżki cold i warm.
Problem z serwowaniem dotyczy working setu
LoRA zamraża model bazowy i uczy niskorangowych aktualizacji dla wybranych macierzy wag. Powstały adapter jest zwykle znacznie mniejszy niż pełny checkpoint, ale jego rozmiar nadal zależy od rangi, modułów docelowych, liczby warstw i dtype. Stałe założenia, takie jak „każdy adapter ma 100 MB”, są słabymi danymi wejściowymi do planowania pojemności.
W kontekście serwowania rozróżnij trzy wielkości:
- Rozmiar katalogu: każdy adapter, który platforma może rozwiązać ze storage’u
- Aktywny working set: adaptery otrzymujące żądania w oknie utrzymywania cache
- Zestaw współbieżny: adaptery reprezentowane w batchach w tej samej chwili
Katalog może zawierać tysiące adapterów, nie oznacza to jednak, że tysiące zmieszczą się w VRAM. Znaczenie ma częstotliwość zmian aktywnego zestawu, rozmiar tych adapterów oraz to, czy żądania dla różnych adapterów mogą współdzielić użyteczne batche.
LoRAX łączy cztery mechanizmy:
- Model bazowy pozostaje załadowany dla wszystkich kompatybilnych adapterów.
- Żądanie wskazuje adapter, który może zostać znaleziony w Hugging Face, Predibase lub systemie plików.
- Harmonogramowanie wymiany adapterów wykonuje prefetch i offload wag między pamięcią GPU i CPU.
- Heterogeniczne continuous batching grupuje żądania kierowane do różnych adapterów.
Projekt LoRAX podaje, że w jego benchmarkach heterogeniczne batching utrzymuje przepustowość i opóźnienie niemal na stałym poziomie wraz ze wzrostem liczby współbieżnych adapterów. Traktuj ten wynik dostawcy jako hipotezę dla własnego workloadu. Długość promptu, długość wyjścia, ranga, moduły docelowe, zajętość batcha, churn cache i generacja GPU mogą zmienić rezultat.
Odtworzony poniżej wykres pochodzi z raportu Predibase z premiery LoRAX z listopada 2023 roku. Predibase przeprowadziło benchmark modelu Llama 2 7B z zapytaniami rozłożonymi na od 1 do 128 adapterów na jednym NVIDIA A10G. Wykres pokazuje porównanie kosztu dla od 1 do 32 adapterów przy przetwarzaniu miliona tokenów, podzielonych równomiernie między adaptery.

Zarchiwizowane porównanie projektów odtworzone na podstawie raportu Predibase dotyczącego LoRAX z 2023 roku. Koszty LoRAX i dedykowanych deploymentów wykorzystują liczbę godzin GPU z tego eksperymentu. Na poziomie szczegółowości źródła linia GPT-3.5 Turbo używa kosztu fine-tuned modelu w przeliczeniu na token.
Płaskie pomarańczowe słupki należy interpretować jako wynik tak zaprojektowanego benchmarku, a nie jako aktualną obietnicę cenową. Test wysyłał stałą łączną liczbę miliona tokenów i umożliwiał współdzielenie batcha przez różne adaptery. W baseline’ie dedykowanym przyjęto osobny hostowany compute dla każdego modelu, więc jego koszt rósł wraz z liczbą modeli.
Predibase nie ujawniło następujących danych wejściowych benchmarku:
- proporcji tokenów promptu do tokenów wyjściowych
- długości żądań
- rozmiaru batcha
- rangi adaptera
- ceny godziny GPU
- dokładnego modelu wykorzystania zasobów w dedykowanych deploymentach
- dokładnych historycznych cen wejścia i wyjścia GPT-3.5
W związku z tym raport nie zawiera wystarczających informacji, aby niezależnie odtworzyć przedstawione wartości w dolarach.
Wykres nie obejmuje również rzadkiego ruchu, cold downloadów, aktualnych cen cloud, nowszych GPU, innych modeli bazowych ani adapterów o innych rangach. Uzasadnia on potrzebę odtwarzania rzeczywistego workloadu. Nie może go zastąpić.
Kiedy LoRAX jest rozsądnym wyborem
LoRAX warto poddać benchmarkowi, gdy spełnione są wszystkie poniższe warunki:
- adaptery zostały wytrenowane względem tego samego obsługiwanego modelu bazowego i kontraktu tokenizera
- ruch obejmuje wiele adapterów, z istotnym long tail
- ładowanie cold adaptera na żądanie jest preferowane względem rezerwowania dla niego osobnego deploymentu
- routing po tenantach lub zadaniach już istnieje na granicy aplikacji
- zespół potrafi obsługiwać wyspecjalizowany runtime inferencyjny i jego zachowanie cache
Typowe przypadki obejmują asystentów specyficznych dla tenantów, wiele wariantów domenowych oraz eksperymenty online współdzielące jeden checkpoint bazowy.
LoRAX jest słabszym wyborem, gdy kilka adapterów obsługuje większość ruchu albo gdy modele nie współdzielą modelu bazowego. Jest również mniej odpowiedni, gdy restrykcyjne cele opóźnienia nie tolerują cold loadów lub gdy platforma nie może bezpiecznie kontrolować artefaktów ładowanych przez serwer. W takich przypadkach prostszy może być standardowy deployment vLLM lub TGI ze stałym zestawem adapterów.
Nie używaj Kubernetes wyłącznie dlatego, że katalog jest duży. Najpierw potwierdź działanie runtime’u i kompatybilność adapterów na jednym GPU.
Wypróbuj lokalnie jeden model bazowy i jeden adapter
README LoRAX zaleca użycie prebuilt containera. W rzeczywistym środowisku użyj niezmiennego digestu obrazu. main pojawia się tutaj wyłącznie dlatego, że jest udokumentowanym tagiem quick startu w repozytorium. Przykłady mają charakter ilustracyjny i nie zostały lokalnie zweryfikowane w tym checkoutcie. Potwierdź je względem wersji obrazu i zależności, które wdrażasz.
mkdir -p data
docker run --rm --gpus all --shm-size 1g \
-p 8080:80 \
-v "$PWD/data:/data" \
ghcr.io/predibase/lorax:main \
--model-id mistralai/Mistral-7B-Instruct-v0.1
Udokumentowane minimum to Linux, Docker, GPU NVIDIA generacji Ampere lub nowszej oraz sterowniki kompatybilne z CUDA 11.8. Licencje modeli i gated repositories mogą również wymagać tokenu Hugging Face.
Rozpocznij od modelu bazowego:
curl http://127.0.0.1:8080/generate \
-H 'Content-Type: application/json' \
-d '{
"inputs": "[INST] Give one reason to measure cold-adapter latency. [/INST]",
"parameters": {"max_new_tokens": 64}
}'
Następnie wyślij kompatybilny adapter:
curl http://127.0.0.1:8080/generate \
-H 'Content-Type: application/json' \
-d '{
"inputs": "[INST] Solve: Natalia sold 48 clips in April and half as many in May. What is the total? [/INST]",
"parameters": {
"max_new_tokens": 64,
"adapter_id": "vineetsharma/qlora-adapter-Mistral-7B-Instruct-v0.1-gsm8k"
}
}'
Pierwsze żądanie może pobrać i załadować adapter. Kolejne żądania mogą korzystać z cache’owanych artefaktów i rezydentnych wag. Zapisz wyniki dla obu ścieżek. Pojedyncze warm żądanie niewiele mówi o zachowaniu long tail.
Użyj klienta kompatybilnego z OpenAI
LoRAX udostępnia kompatybilny z OpenAI endpoint chat. Pole model identyfikuje adapter:
from openai import OpenAI
client = OpenAI(
api_key="EMPTY",
base_url="http://127.0.0.1:8080/v1",
)
response = client.chat.completions.create(
model="alignment-handbook/zephyr-7b-dpo-lora",
messages=[
{"role": "user", "content": "Explain cache locality in two sentences."},
],
max_tokens=100,
)
print(response.choices[0].message.content)
Serwer domyślnie nie wymaga klucza API. Jest to wygodne dla localhosta, ale niebezpieczne w konfiguracji wystawionej do Internetu. Umieść przed nim uwierzytelnianie, autoryzację tenantów, limity oraz allowlistę adapterów.
Zdefiniuj bramkę kompatybilności
Zanim adapter trafi do katalogu, sprawdź co najmniej:
- zadeklarowany model bazowy i revision
- kompatybilność tokenizera i chat template
- rangę LoRA oraz moduły docelowe obsługiwane przez runtime
- format artefaktu i kształty tensorów
- licencję, pochodzenie i digest integralności
- niewielki zestaw testów behawioralnych i regresyjnych
Odrzucaj niekompatybilne artefakty podczas rejestracji, a nie przy pierwszym żądaniu użytkownika.
Zrozum rezydencję przed wdrożeniem
Model bazowy zużywa największą stałą część pamięci GPU. Wagi adapterów, KV cache, przestrzeń robocza batcha i kernele runtime’u konkurują o pozostałe zasoby. Pamięć RAM CPU może przechowywać adaptery po offloadzie, a /data przechowuje pobrane artefakty.
Nie są to wymienne poziomy. Artefakt z dysku lub Huba musi zostać odczytany i zmaterializowany, zanim stanie się adapterem rezydującym w CPU lub GPU. Mierz przejścia osobno:
| Ścieżka | Co obejmuje | Metryka do rejestrowania |
|---|---|---|
| Trafienie w GPU | Adapter już rezyduje w pamięci | czas w kolejce i czas do pierwszego tokena |
| Trafienie w CPU | Transfer lub rematerializacja do GPU | opóźnienie ładowania adaptera i end-to-end latency |
| Trafienie w artefakt | Odczyt z lokalnego cache’a /data | opóźnienie odczytu/ładowania i liczba bajtów w cache |
| Zdalny miss | Pobranie oraz walidacja i ładowanie | czas pobierania, błędy i pełne cold latency |
Planowanie pojemności powinno odtwarzać rzeczywisty rozkład popularności adapterów. Jednostajnie losowe identyfikatory adapterów tworzą inny problem cache niż workload tenantów o rozkładzie zbliżonym do Zipfa.
Ostrożnie wdrażaj chart repozytorium
Repozytorium zawiera charts/lorax, więc powtarzalnym punktem wyjścia jest przypięta revision repozytorium i lokalny chart:
git clone https://github.com/predibase/lorax.git
cd lorax
git checkout <reviewed-commit-or-release>
helm dependency update charts/lorax
helm template lorax charts/lorax -f values.production.yaml
helm upgrade --install lorax charts/lorax \
--namespace inference \
--create-namespace \
-f values.production.yaml
Według przeglądu z 15 lipca 2026 roku, wartości chartu i template Deploymentu pokazują domyślne ustawienia wymagające uwagi:
- tag obrazu to
latest /datajest typuemptyDir, więc zastąpienie poda usuwa pobrane artefakty- probe’y liveness i readiness są puste
- token Hugging Face jest modelowany jako literalna wartość zmiennej środowiskowej
- domyślnie żądany jest jeden GPU
Chart jest użytecznym szkieletem. Nie stanowi polityki produkcyjnej.
Zacznij od rzeczywistej struktury wartości chartu
Chart umieszcza konfigurację runtime’u pod deployment, a argumenty launchera są listą par nazwa/wartość. Minimalny overlay wygląda tak:
deployment:
replicas: 1
image:
repository: ghcr.io/predibase/lorax
tag: "<tested-release-tag>"
args:
- name: "--model-id"
value: "mistralai/Mistral-7B-Instruct-v0.1"
- name: "--max-input-length"
value: "2048"
- name: "--max-total-tokens"
value: "3072"
- name: "--max-batch-total-tokens"
value: "8192"
- name: "--max-batch-prefill-tokens"
value: "4096"
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
env:
- name: HUGGING_FACE_HUB_TOKEN
valueFrom:
secretKeyRef:
name: lorax-hub
key: token
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
failureThreshold: 600
service:
serviceType: ClusterIP
port: 80
Powyższe limity tokenów są przykładowymi wartościami początkowymi, a nie rekomendacjami dotyczącymi sizingu. Wyprowadź je na podstawie reprezentatywnych promptów, oczekiwanej współbieżności, pamięci GPU i testów obciążeniowych.
Jawnie uzupełnij luki
Aktualny template chartu przekazuje deployment.env przez toYaml, więc zwykły overlay values może użyć valueFrom.secretKeyRef do poświadczeń Huba, jak powyżej. Template hardcoduje wolumeny emptyDir, nie ma hooka startupProbe i zawsze formatuje obraz jako repository:tag. Sam plik values nie może zatem zapewnić trwałego /data, startup probe’a ani przypięcia digestu obrazu; użyj przejrzanego forka chartu, patcha post-render albo warstwy manifestów wyższego poziomu. W tej warstwie produkcyjnej umieść:
- PersistentVolumeClaim lub lokalny dla noda cache artefaktów zamontowany w
/data - startup probe przed agresywnym probe’em liveness
- politykę disruption poda i rozłożenie topologiczne dla wielu replik
- NetworkPolicy, ograniczenia service account oraz uwierzytelniony gateway
- przypięcie digestu obrazu i sprawdzanie integralności artefaktów
Nie umieszczaj tokenu Huba bezpośrednio w zacommitowanym pliku values. Dwie repliki zapewniają użyteczną wysoką dostępność tylko wtedy, gdy obie mogą załadować model bazowy. Router musi również unikać wysyłania każdego cold adaptera do obu podów.
Routuj z uwzględnieniem lokalności cache
Balansowanie round-robin może zmienić każdą replikę w cold cache. Użyteczny router mapuje dozwolony identyfikator adaptera na jedną replikę za pomocą hasha lub innej stabilnej reguły. Zachowuje ścieżkę failover na wypadek niedostępności tej repliki.
Klucz routingu musi pochodzić z uwierzytelnionego stanu aplikacji, a nie z dowolnego publicznego parametru URL. W przeciwnym razie wywołujący może wymuszać zdalne pobrania, powodować churn cache lub badać prywatne nazwy adapterów.
LoRAX czy vLLM?
Aktualna dokumentacja vLLM opisuje moduły LoRA deklarowane podczas startu oraz dynamiczne ładowanie za pośrednictwem endpointów lub pluginów resolvera. Ostrzega, że aktualizowanie adapterów w runtime wiąże się z ryzykiem bezpieczeństwa i nie powinno być używane produkcyjnie poza izolowanym, zaufanym środowiskiem.
Użyteczne porównanie ma charakter operacyjny, a nie liczbowy:
| Pytanie | LoRAX | vLLM |
|---|---|---|
| Jak wykrywane są adaptery long-tail? | Identyfikator adaptera może na żądanie rozwiązać artefakty z Hugging Face, Predibase lub systemu plików | Moduły statyczne, endpointy dynamicznego zarządzania lub pluginy resolvera |
| Jak zarządzana jest rezydencja? | Jawne harmonogramowanie wymiany adapterów między GPU i CPU | Skonfigurowane limity aktywnych LoRA i LoRA w CPU oraz zachowanie resolvera |
| Jaki jest interfejs żądań? | TGI-style /generate, klient Python i kompatybilny z OpenAI chat | Serwowanie kompatybilne z OpenAI i natywne API Python |
| Co powinno decydować? | Cold/warm latency, churn cache, przepustowość heterogenicznego batcha i dopasowanie operacyjne | Ten sam replay workloadu i te same kryteria operacyjne |
Unikaj reguł takich jak „LoRAX dla 1000 adapterów, vLLM dla dziesięciu”. Sam rozmiar katalogu nie determinuje wydajności. Benchmarkuj oba rozwiązania przy użyciu tego samego modelu bazowego, adapterów, promptów, rang, trace’u napływu żądań i sprzętu.
Produkcyjny test akceptacyjny
Przed rozszerzeniem katalogu uruchom replay obejmujący:
- Stały hot set, aby ustalić warm throughput i latency.
- Rozkład long-tail do pomiaru trafień w CPU i cache artefaktów.
- Burst wcześniej nieznanych, ale allowlistowanych adapterów.
- Zastąpienie poda do pomiaru odtwarzania modelu bazowego i adapterów.
- Jeden niedostępny lub uszkodzony adapter w celu weryfikacji izolacji i fallbacku.
- Współbieżnych tenantów do weryfikacji uwierzytelniania, limitów i etykiet metryk.
Śledź następujące metryki:
- rate żądań
- czas w kolejce
- czas do pierwszego tokena
- opóźnienie między tokenami
- całkowite opóźnienie
- czas ładowania adaptera
- klasa trafienia w cache
- pamięć GPU
- pamięć CPU
- liczba pobranych bajtów
- błędy według przyczyny
Nie umieszczaj identyfikatorów adapterów w nieograniczonych etykietach metryk. Mapuj je na kontrolowane wymiary albo śledź w próbkowanych trace’ach.
Zdefiniuj progi akceptacji przed testem. Ustal maksymalny współczynnik błędów ścieżki cold oraz docelowe warm P99. Ustal także docelowy współczynnik trafień w cache dla obserwowanego rozkładu popularności oraz cel czasu odtwarzania po utracie poda.
Podsumowanie
LoRAX przekształca wiele kompatybilnych fine-tune’ów z floty kopii modelu bazowego w problem rozmieszczania adapterów. Może to być mocny projekt dla workloadów long-tail, ale z definicji nie sprawia, że koszt lub opóźnienie stają się stałe. Wynik nadal zależy od aktywnego working setu, ścieżki wymiany, składu batchy i warstwy storage.
Najpierw potwierdź te mechanizmy na jednym GPU. Następnie potraktuj Kubernetes poważnie: przypinaj artefakty, zachowuj cache, chroń poświadczenia, autoryzuj adaptery, routuj z uwzględnieniem lokalności i mierz każdą ścieżkę rezydencji. Jeśli LoRAX pokona aktualną konfigurację vLLM przy tym samym replayu, decyzja wdrożeniowa będzie oparta na dowodach.
Referencje
- Repozytorium i README LoRAX — obsługiwane funkcje, wymagania, API i Helm chart
- Raport z premiery LoRAX i benchmark z 2023 roku — źródło i warunki odtworzonego wykresu kosztów
- Wartości chartu LoRAX i template Deploymentu — aktualne wartości domyślne i zachowanie wolumenów
- Adaptery LoRA w vLLM — statyczne i dynamiczne serwowanie adapterów
- Artykuł LoRA — metoda adaptacji niskorangowej
- Dokumentacja Hugging Face PEFT — formaty adapterów i integracja z treningiem