Konfiguracja serwera inferencyjnego: vLLM, llama.cpp, SGLang

Sprzęt dociera, sterownik działa, nvidia-smi pokazuje wszystkie karty. Teraz pytanie brzmi: co właściwie będzie serwować tokeny. Odpowiedzią jest jeden z czterech lub pięciu otwartych stosów serwujących, a zły wybór kosztuje 2× przepustowości, 3× opóźnienia albo trzy dni debugowania. Ten artykuł uczciwie wybiera między nimi i przeprowadza przez konfigurację tego, po który większość klientów Kentino powinna sięgnąć najpierw: vLLM w Dockerze, z obrazem zwalidowanym przez NGC, na endpoincie zgodnym z OpenAI.

Dla kogo: dla osoby, która przeczytała L02, potrafi uruchomić docker run --gpus all nvidia-smi, a teraz potrzebuje warstwy wyżej.

Macierz decyzyjna

Pięć stosów wartych rozważenia w maju 2026 roku. Wszystko inne to albo nakładka na jeden z nich, albo projekt badawczy.

Stos Najlepszy w Najsłabszy w Kiedy wybrać
vLLM Produkcyjne serwowanie jednego modelu, API zgodne z OpenAI, przepustowość na Blackwell PCIe Heterogeniczne obciążenia wielomodelowe, MoE w ekstremalnej skali Domyślny wybór. 90% instalacji Kentino.
SGLang Ustrukturyzowane wyjście (JSON), przepływy agentowe, wielotura z długim prefiksem, duże MoE Najmniejsze wdrożenia, niszowe architektury modeli RAG, agenci, API zwracające JSON, klasa DeepSeek-V3.
llama.cpp Jeden użytkownik, GGUF, mieszane CPU/GPU, Jetson i Mac, małe maszyny deweloperskie Wielu równoczesnych użytkowników, kernele natywne dla FP8/Blackwell Laptop deweloperski, Jetson Orin, urządzenie dla jednego użytkownika, pojedyncza 5090 bez walki z Linuksem.
TensorRT-LLM + Triton Serwowanie wielu modeli, potoki zespołowe, najniższe opóźnienie w stanie ustalonym na H100/B200 Czas konfiguracji, tempo iteracji, wszystko, co szybko się zmienia Wielomodelowa produkcja przez wiele miesięcy. Duży nakład operacyjny.
NVIDIA NIM Gotowe od ręki, przetestowane przez NVIDIA, wsparcie korporacyjne Otwarte wagi spoza katalogu, potrzeba pełnej kontroli Zakup NVIDIA AI Enterprise, najszybsze uruchomienie.

Wersja krótka i subiektywna: w razie wątpliwości należy uruchomić vLLM w kontenerze NGC. Jeśli obciążenie opiera się na ustrukturyzowanym wyjściu lub współdzielonych promptach systemowych — SGLang. Na Jetsonie albo pojedynczej maszynie deweloperskiej z 4090 — llama.cpp. Wszystko inne to przypadek brzegowy.

vLLM jest domyślnym wyborem — i dlaczego

vLLM (v0.20+ według stanu na maj 2026) to najczęściej wdrażany otwarty stos serwujący dla transformerowych LLM i VLM. Przewagę dają mu trzy rzeczy:

  1. Ciągłe batchowanie — przychodzące żądania dołączają do batcha w locie przy kolejnym przebiegu naprzód. Wykorzystanie GPU na endpoincie z mieszanym ruchem rośnie z 40% do ponad 85% w porównaniu z naiwnym batchowanym wnioskowaniem HuggingFace.
  2. PagedAttention i cache prefiksów — cache KV jest zarządzany w blokach o stałym rozmiarze, jak strony pamięci wirtualnej systemu operacyjnego. Dwa żądania współdzielące prompt systemowy współdzielą bloki KV tego prefiksu. Przy przepływach agentowych z promptami systemowymi o rozmiarze 2 KB trafienia w cache prefiksów sięgają 80–95%.
  3. Kernele pisane pod Blackwella — FlashAttention 3, atencja FP8, kwantyzacja MXFP4 tylko wag oraz ścieżka mnożenia macierzy oparta na CUTLASS celują natywnie w sm_120 (5090, RTX Pro 6000 Blackwell) i sm_100 (B200).

CUDA 13 jest domyślna dla kół PyPI w wersji v0.20+ oraz dla obrazu vllm/vllm-openai:latest. Koła dla CUDA 12.8 są nadal dostarczane jako wariant zapasowy dla sm_120.

Instalacja vLLM: pip czy Docker

Dwie ścieżki instalacji. Należy wybrać Docker, chyba że istnieje konkretny powód, by zrobić inaczej.

Ścieżka A — pip w venv (tylko do developmentu)

python3.12 -m venv ~/venvs/vllm && source ~/venvs/vllm/bin/activate
pip install --upgrade pip && pip install vllm   # CUDA 13.0 wheels by default

vllm serve meta-llama/Llama-3.3-70B-Instruct-FP8 --tensor-parallel-size 4 --port 8000

Pip działa i jest szybszy przy iterowaniu po flagach silnika. Przypina jednak interpreter Pythona, runtime CUDA i zgodność sterownika z runtime do jednej konfiguracji hosta. Nadaje się do developmentu, nie na produkcję.

Ścieżka B — Docker z obrazem upstream (domyślna produkcyjna)

docker run --gpus all --runtime nvidia \
  --ipc=host \
  -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  -e HUGGING_FACE_HUB_TOKEN=$HF_TOKEN \
  vllm/vllm-openai:latest \
  --model meta-llama/Llama-3.3-70B-Instruct-FP8 \
  --tensor-parallel-size 4 \
  --gpu-memory-utilization 0.92 \
  --max-model-len 8192 \
  --enable-prefix-caching

Uwagi, które mszczą się na tych, którzy je pominą:

  • --ipc=host jest wymagane przy wielu GPU. Workery vLLM komunikują się przez pamięć współdzieloną, a domyślna przestrzeń nazw IPC Dockera ma 64 MB i nie pomieści buforów NCCL.
  • Trzeba zamontować cache HuggingFace. Inaczej każde docker run pobiera 75 GB wag od nowa.
  • Na produkcji należy przypiąć tag: vllm/vllm-openai:v0.20.2, nie :latest.

Obraz NGC nvcr.io/nvidia/vllm:25.09-py3 zawiera CUDA 13.0, przetestowaną kompilację vLLM, NCCL oraz pieczątkę QA od NVIDIA. Jest większy (~12 GB) i o miesiąc lub dwa opóźniony względem upstreamu. Warto po niego sięgnąć, gdy na tym samym hoście działa też TensorRT-LLM lub Triton i potrzebny jest jeden stos CUDA/NCCL dla wszystkich. W przeciwnym razie obraz z Docker Huba jest mniejszy, świeższy i równoważny.

Flagi, które naprawdę mają znaczenie

vLLM udostępnia mniej więcej dwieście flag CLI. Większość jest sytuacyjna. Te, których używa się za każdym razem:

Flaga Co robi Rozsądna wartość domyślna
--tensor-parallel-size N Dzieli każdą warstwę na N GPU w węźle. 4 na maszynie z 4 GPU, 1 jeśli model się mieści.
--pipeline-parallel-size M Dzieli warstwy na M etapów. 1, chyba że model rozciąga się na wiele węzłów.
--gpu-memory-utilization 0.92 Część VRAM, którą vLLM alokuje z góry na wagi, KV i aktywacje. 0.90–0.92. Więcej, jeśli nie ma innego najemcy.
--max-model-len 8192 Maksymalny kontekst. Ogranicza budżet cache KV na żądanie. Ustawić na to, co faktycznie się serwuje. Zawyżanie marnuje pamięć.
--max-num-seqs 64 Maksymalna liczba równoczesnych żądań w locie. 32–128. Strojenie przez vllm bench serve.
--enable-prefix-caching Automatyczne ponowne użycie cache prefiksów między żądaniami. Włączone. Darmowy zysk przy współdzielonych promptach systemowych.
--quantization fp8 / awq / gptq Informuje vLLM o formacie wag. Często wnioskowany z nazwy modelu, ale jawne ustawienie jest bezpieczniejsze. Ustawić, jeśli karta modelu tak mówi.
--swap-space 4 GiB pamięci RAM CPU na GPU do wykorzystania jako wyrzucone z pamięci KV. Domyślnie 0 = brak offloadu. 4–8, jeśli pod obciążeniem dochodzi do wywłaszczeń.
--port 8000 Endpoint zgodny z OpenAI. 8000, chyba że dochodzi do kolizji.
--api-key sk-... Uwierzytelnianie tokenem bearer. Trzeba je ustawić. Albo zakończyć uwierzytelnianie na proxy. Ustawić jeden. Nie wystawiać surowego vLLM.

--gpu-memory-utilization to najczęściej strojona flaga. vLLM używa jej do ustalenia, ile VRAM zarezerwować po załadowaniu wag; reszta staje się pulą cache KV. Za mało → przedwczesne wywłaszczanie KV pod obciążeniem. Za dużo → OOM przy pierwszym żądaniu z długim kontekstem. 0.92 to rozsądny punkt wyjścia dla dedykowanej maszyny inferencyjnej. Przy współdzieleniu GPU warto zejść do 0.85.

Trzy konkretne komendy uruchomieniowe

To są konfiguracje, których faktycznie używają klienci Kentino. Wszystkie zakładają CUDA 13.0, sterownik 570+, obraz Dockera oraz --ipc=host.

Qwen 2.5 72B Instruct INT4 (AWQ) na 4× RTX Pro 6000 Blackwell

docker run --gpus all --runtime nvidia --ipc=host \
  -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  -e HUGGING_FACE_HUB_TOKEN=$HF_TOKEN \
  vllm/vllm-openai:v0.20.2 \
  --model Qwen/Qwen2.5-72B-Instruct-AWQ \
  --quantization awq \
  --tensor-parallel-size 4 \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.92 \
  --enable-prefix-caching \
  --max-num-seqs 64 \
  --port 8000

Około 36 GB wag przy INT4, 4× karty 96 GB. Przy TP=4 każda karta widzi 1/4 KV na żądanie, więc kontekst 32 K przy 64 równoczesnych użytkownikach mieści się spokojnie w budżecie. Można oczekiwać 40–60 tok/s na żądanie przy niskiej współbieżności i łącznie ~600–900 tok/s przy 32 równoczesnych.

Llama 3.3 70B Instruct FP8 na 8× RTX 5090

docker run --gpus all --runtime nvidia --ipc=host \
  -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  -e HUGGING_FACE_HUB_TOKEN=$HF_TOKEN \
  vllm/vllm-openai:v0.20.2 \
  --model meta-llama/Llama-3.3-70B-Instruct-FP8 \
  --quantization fp8 \
  --tensor-parallel-size 4 \
  --pipeline-parallel-size 2 \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.90 \
  --enable-prefix-caching \
  --max-num-seqs 64 \
  --swap-space 4 \
  --port 8000

Uwaga: TP=4 × PP=2, a nie TP=8. Karty 5090 mają po 32 GB; wagi FP8 dla modelu 70B to ~75 GB, czyli spokojnie poniżej 128 GB na czterech kartach. Podział potokowy pozwala uniknąć eksplozji all-reduce, którą kosztowałoby TP=8 po PCIe (zob. K03, N03). TP=8 po PCIe skaluje się gorzej niż TP=4 × PP=2 przy ciągłym batchowaniu i współbieżności powyżej 8.

Qwen 2.5 VL 32B na dwóch 5090

docker run --gpus all --runtime nvidia --ipc=host \
  -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  vllm/vllm-openai:v0.20.2 \
  --model Qwen/Qwen2.5-VL-32B-Instruct-AWQ \
  --quantization awq \
  --tensor-parallel-size 2 \
  --max-model-len 16384 \
  --limit-mm-per-prompt '{"image": 4, "video": 0}' \
  --gpu-memory-utilization 0.90 \
  --enable-prefix-caching \
  --port 8000

Dwie karty 5090, ~20 GB wag INT4, miejsce na enkoder wizyjny i KV. Wariant 72B VL nie mieści się na dwóch 5090 nawet przy INT4; do tego potrzeba 4× 5090 albo jednej Pro 6000. --limit-mm-per-prompt ogranicza liczbę obrazów na żądanie — pojedyncze żądanie z 20 obrazami potrafi wywołać OOM enkodera wizyjnego na 5090. Endpoint jest zgodny z OpenAI (POST /v1/chat/completions z częściami image_url).

SGLang — kiedy jego router wygrywa z vLLM

Atutem SGLang jest RadixAttention: ponowne użycie cache prefiksów zaimplementowane jako drzewo radix obejmujące wiele żądań, a nie tylko dopasowanie równości bloków. Przy obciążeniach, w których większość żądań współdzieli długie prompty systemowe, współczynnik trafień przewyższa cache prefiksów vLLM. Publiczne benchmarki pokazują SGLang na poziomie ~16k tok/s wobec ~12k tok/s vLLM na H100 przy obciążeniach ze współdzielonym prefiksem, z dużo większą różnicą przy ruchu z ustrukturyzowanym wyjściem.

Gdzie SGLang wygrywa:

  • Ustrukturyzowany JSON przez xGrammar. Szybszy i bardziej zgodny niż dekodowanie z ograniczeniami w vLLM. Dla API zwracającego JSON przy milionach żądań ma to znaczenie.
  • DeepSeek-V3 i inne duże MoE. Szeroka równoległość ekspertów oraz rozdzielenie prefill/decode pojawiły się wcześniej; nadal mają przewagę w skali wielowęzłowej.
  • Przepływy agentowe ze współdzielonymi promptami systemowymi. Endpointy RAG, copiloty, prompty systemowe 2–4 KB współdzielone przez większość żądań.

Gdzie wygrywa vLLM: przetwarzanie wsadowe z unikalnymi promptami (przewaga RadixAttention znika), szerokość wsparcia modeli (więcej architektur od ręki) oraz czas do pierwszego działającego endpointu.

docker run --gpus all --runtime nvidia --ipc=host \
  -p 30000:30000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  lmsysorg/sglang:latest \
  python3 -m sglang.launch_server \
    --model-path Qwen/Qwen2.5-72B-Instruct-AWQ \
    --quantization awq \
    --tp 4 \
    --port 30000 \
    --host 0.0.0.0

SGLang udostępnia endpoint zgodny z OpenAI na własnym porcie (domyślnie 30000). Jest wymienny dla tego samego kodu klienta, a dodatkowo oferuje natywne endpointy generacji ustrukturyzowanej. Uczciwa rekomendacja: najpierw warto spróbować vLLM. Jeśli współczynnik trafień współdzielonego prefiksu przekracza ~60% i liczy się opóźnienie ogona, należy przetestować ponownie SGLang i wybrać zwycięzcę.

llama.cpp — kiedy wygrywa małe i pojedyncze

llama.cpp to wnioskowanie w C++ bez runtime'u Pythona, bez zależności od CUDA, z formatem wag GGUF, który pakuje metadane kwantyzacji do samego pliku. Działa na CPU, pojedynczym GPU, Macu z serii M, Jetsonie albo częściowo na każdym z nich. Nie realizuje równoległości tensorowej w taki sposób jak vLLM. Jeden model, jedna pętla wnioskowania, szybko.

Kiedy llama.cpp jest właściwą odpowiedzią:

  • Jetson Orin. vLLM słabo celuje w Jetsona; llama.cpp robi to dobrze. Dla modelu pokładowego na Unitree G1 to standardowa odpowiedź.
  • Pojedyncza maszyna deweloperska z 5090 / 4090. Jeden programista iterujący, brak współbieżności, najszybsza ścieżka instalacji.
  • Mieszany podział CPU+GPU. Model 70B nie mieści się na 5090 (32 GB). Z -ngl 40 40 z 80 warstw trafia na GPU, a reszta liczy się na CPU z prędkością akceptowalną dla jednego użytkownika.
  • Urządzenie wbudowane. Bez Dockera, bez bólu z niezgodnością sterowników, bez Pythona.

Opcje kwantyzacji GGUF, w kolejności rozmiar kontra jakość:

Kwantyzacja Rozmiar wobec FP16 Jakość Kiedy wybrać
Q2_K ~2.5 bita Widocznie pogorszona Tylko na demo.
Q3_K_M ~3.5 bita Zauważalne pogorszenie Najmniejsza sensowna dla użytecznego wyjścia.
Q4_K_M ~4.5 bita Dobra do bardzo dobrej Domyślny punkt wyjścia.
Q5_K_M ~5.5 bita Bardzo blisko FP16 Jeśli jest zapas VRAM, warto ją wziąć.
Q6_K ~6.5 bita Nie do odróżnienia od FP16 Do pracy wymagającej jakości.
Q8_0 ~8.5 bita Praktycznie bezstratna Maksymalna jakość.
IQ4_XS / IQ3_M i-kwanty Lepsza jakość na bit przy małych rozmiarach Gdy trzeba zmieścić się w ciasnym VRAM.

Q4_K_M to właściwa wartość domyślna. Q5_K_M, jeśli jest zapas. Q8_0 tylko po to, by zweryfikować „brak strat kwantyzacji”. I-kwanty (IQ4_XS i pokrewne) to ewolucja lat 2025/2026, którą warto wypróbować przy wciskaniu modelu 70B na pojedynczą kartę 32 GB.

git clone https://github.com/ggml-org/llama.cpp && cd llama.cpp
cmake -B build -DGGML_CUDA=ON && cmake --build build --config Release -j

./build/bin/llama-server \
  --model models/qwen2.5-72b-instruct-q4_k_m.gguf \
  --n-gpu-layers 99 --ctx-size 32768 \
  --host 0.0.0.0 --port 8080 --api-key sk-localdev

-ngl 99 przenosi na GPU tyle warstw, ile się zmieści. Endpoint jest zgodny z OpenAI pod adresem :8080/v1/chat/completions. Przy obciążeniu wielu użytkowników to złe narzędzie — wtedy lepszy jest vLLM. Dla jednego użytkownika na jednej 5090 albo na Jetsonie jest właściwe.

TensorRT-LLM i Triton — opcja ciężka

TensorRT-LLM to optymalizujący kompilator NVIDIA do wnioskowania LLM. Buduje model w silnik TensorRT z wyprzedzeniem, łączy kernele i dobiera najlepszy układ dla danego GPU. Zwykle daje 10–25% lepszą przepustowość i 15–30% niższe opóźnienie niż vLLM na tym samym sprzęcie, a jeszcze więcej na H100/B200. Kosztem jest krok budowania (od minut do godzin na model i konfigurację GPU), silniki nieprzenośne między generacjami CUDA / sterowników / GPU oraz obsługa trudniejsza niż docker run.

Triton Inference Server to warstwa serwująca wiele modeli, która hostuje silniki TensorRT-LLM (a także PyTorch, ONNX, TensorFlow, Python i vLLM jako backend) w jednym serwerze. Wzorzec repozytorium modeli pozwala załadować LLM A, LLM B, model wizyjny, model ASR i potok w Pythonie pod jednym adresem URL, z wersjonowaniem, routingiem A/B i grafami zespołowymi.

Warto ponieść ten koszt, gdy: na jednym serwerze serwuje się wiele heterogenicznych modeli; produkcja w stanie ustalonym trwa miesiącami przy stabilnym wyborze modelu; wyciska się ostatnie milisekundy opóźnienia p99 na GPU centrum danych Hopper/Blackwell.

Nie warto, gdy: model wciąż jest wybierany (każda zmiana to nowa budowa silnika); używa się GPU konsumenckich lub ze stacji roboczych (przewaga TRT-LLM maleje wobec H100, a vLLM wypuszcza model z przyszłego tygodnia sześć tygodni przed TRT-LLM); zespół jest mały i nie ma zasobów operacyjnych.

NVIDIA NIM — ścieżka gotowa

NIM (NVIDIA Inference Microservices) pakuje „Triton + TensorRT-LLM + optymalną konfigurację dla tego konkretnego modelu + licencję korporacyjną” w jeden kontener. docker pull nvcr.io/nim/meta/llama-3.3-70b-instruct:latest, ustawienie klucza NGC, uruchomienie — i gotowy jest przetestowany endpoint zgodny z OpenAI, bez wybierania kwantyzacji i strojenia flag.

Pasuje, gdy: kupiono NVIDIA AI Enterprise (albo wymaga tego klient); zależy na najszybszym dotarciu do sprawdzonego endpointu (godziny, nie dni); potrzebny model jest w katalogu (Llama, Mistral, Mixtral, Gemma, Nemotron i rosnący zestaw partnerski). Po GTC 2026 darmowy poziom obejmuje do 16 GPU dla członków Developer Program — wystarczająco, by przetestować większość pojedynczych instalacji serwerowych Kentino; przed postawieniem na to warto zweryfikować aktualne warunki licencyjne.

Nie pasuje, gdy: modelu nie ma w katalogu (otwarte wagi trafiają tam z tygodniami opóźnienia); potrzebne jest strojenie (NIM z założenia ukrywa większość pokręteł).

Reverse proxy, uwierzytelnianie, limity zapytań

Nie należy wystawiać vLLM bezpośrednio do publicznego internetu. Przed nim powinien stanąć nginx (albo Caddy, albo Traefik). Minimalna konfiguracja nginx:

upstream vllm_backend {
    server 127.0.0.1:8000;
    keepalive 32;
}

limit_req_zone $binary_remote_addr zone=vllm:10m rate=20r/s;

server {
    listen 443 ssl http2;
    server_name infer.example.com;

    ssl_certificate     /etc/letsencrypt/live/infer.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/infer.example.com/privkey.pem;

    location /v1/ {
        if ($http_authorization != "Bearer sk-yourlongrandomtoken") {
            return 401;
        }
        limit_req zone=vllm burst=40 nodelay;

        proxy_pass http://vllm_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_buffering off;             # streaming SSE
        proxy_read_timeout 600s;
        chunked_transfer_encoding on;
    }
}

Trzy rzeczy, które najczęściej robi się źle:

  • proxy_buffering off jest wymagane dla odpowiedzi strumieniowych. Inaczej tokeny gromadzą się w proxy, a klient dostaje je jednorazowo.
  • proxy_read_timeout domyślnie wynosi 60 s. Długie prefille multimodalne przy 4 tok/s wyjdą daleko poza ten limit. Należy ustawić 5–10 minut.
  • Blok if działa na dokładne dopasowanie. Do prawdziwego uwierzytelniania należy użyć Lua, oauth2-proxy albo bramy pokroju Kong.

Monitoring

Dwa źródła metryk, dwa cele scrapowania.

  • Endpoint /metrics w vLLM. Zgodny z Prometheusem, na tym samym porcie co API OpenAI (:8000/metrics). Publikuje vllm:num_requests_running, vllm:num_requests_waiting, vllm:gpu_cache_usage_perc, vllm:time_to_first_token_seconds, vllm:time_per_output_token_seconds. Wykorzystanie cache KV to ta metryka, która wychwytuje wywłaszczanie, zanim zabije opóźnienia.
  • Eksporter DCGM (nvcr.io/nvidia/k8s/dcgm-exporter, port 9400). Eksportuje wykorzystanie SM GPU, wykorzystanie pamięci, moc, temperaturę, pasmo PCIe i liczniki ECC.

Oba do Prometheusa, oba do Grafany. Pierwszy dashboard: requests-running, KV-cache-usage, GPU-util, GPU-temp, P95 TTFT, P95 TPOT. Jeśli KV-cache-usage się nasyca, a requests-waiting rośnie, dochodzi do wywłaszczania — należy obniżyć --max-num-seqs, podnieść --gpu-memory-utilization albo dodać replikę.

Pułapka rozgrzewania modelu

Pierwsze żądanie do świeżo uruchomionego vLLM jest 5–30× wolniejsze niż w stanie ustalonym. Grafy CUDA są przechwytywane dla każdego kształtu batcha, cache prefiksów jest pusty, scheduler się kalibruje. Przed włączeniem instancji do load balancera warto wysłać przy starcie małe żądanie /v1/chat/completions; bez tego pierwszy prawdziwy użytkownik dostanie 15-sekundową odpowiedź od modelu, który normalnie odpowiada w sekundę. Przy wdrożeniach blue/green trzeba rozgrzać nową replikę przed wygaszeniem starej. Pominięcie rozgrzewki to najczęstsza przyczyna sytuacji „wdrożenie wyglądało dobrze, ale użytkownicy narzekali przez dziesięć minut”.

Wiele modeli na jednym serwerze

vLLM jest w swojej istocie serwerem jednego modelu. Trzy opcje, gdy potrzeba więcej:

  1. Jeden kontener na model, różne porty. Każdy trzyma własny VRAM. Model 70B i 7B dzielą maszynę z 4 GPU dzięki podziałowi CUDA_VISIBLE_DEVICES oraz dopasowanemu --gpu-memory-utilization. Zaplanowanie budżetu pamięci jest po stronie operatora.
  2. Ładowanie na żądanie. Front-end ładuje i zwalnia modele w miarę napływu żądań. Załadowanie modelu 70B trwa 30–120 s; opóźnienie pierwszego trafienia jest nie do przyjęcia przy pracy interaktywnej. Do przetwarzania wsadowego w porządku.
  3. Repozytorium modeli Tritona. Triton zarządza cyklem życia N modeli w jednym serwerze i routuje po nazwie modelu. To kolejny krok, gdy opcja 1 przestaje się skalować.

Dla większości instalacji Kentino opcja 1 jest właściwa, dopóki modeli nie będzie cztery lub więcej — wtedy podatek operacyjny Tritona zaczyna się opłacać.

Uczciwa ocena

Dziewięćdziesiąt pięć procent klientów Kentino powinno zacząć od vllm/vllm-openai w Dockerze, za nginxem, z jednym modelem, ze scrapowaniem Prometheus + eksporter DCGM, i przez pierwsze trzy miesiące nie patrzeć na nic innego. SGLang zasługuje na swoje miejsce przy ustrukturyzowanym wyjściu lub ruchu agentowym ze współdzielonym prefiksem w skali. llama.cpp zasługuje na swoje miejsce na Jetsonie, Macu albo maszynie deweloperskiej jednego użytkownika. Triton i TensorRT-LLM zasługują na swoje miejsce przy miesiącach stabilnej produkcji z wieloma modelami. NIM zasługuje na swoje miejsce, gdy model jest w katalogu, a licencja w ręku.

Koszt zaczynania od zbyt skomplikowanego rozwiązania jest realny. Widzieliśmy instalacje laboratoryjne, które spędziły trzy tygodnie na zmuszeniu Tritona + TensorRT-LLM do serwowania jednej Llamy 70B, którą vLLM postawiłby w dwadzieścia minut. Najpierw rzecz prosta. Złożoność warto dodawać, gdy pojawi się dowód, że jest potrzebna.

Co dalej

Dla nowego właściciela serwera AI Kentino oto ścieżka w pięciu krokach:

  1. Weryfikacja podstaw. docker run --rm --gpus all nvidia/cuda:13.0.0-base-ubuntu24.04 nvidia-smi powinno wylistować każde GPU. Jeśli tak nie jest, trzeba to naprawić w pierwszej kolejności (zob. L02).
  2. Pobranie obrazu vLLM i uruchomienie jednego modelu. Wystarczy wybrać jeden z trzech powyższych przepisów. Bind na localhost. Następnie odpytać /v1/models i /v1/chat/completions z curl na hoście.
  3. Postawienie nginxa z przodu. TLS przez Let's Encrypt, uwierzytelnianie tokenem bearer, limit zapytań, proxy_buffering off. Następnie sprawdzenie, czy strumieniowanie działa ze zdalnego klienta.
  4. Podpięcie Prometheusa + eksportera DCGM + Grafany. Zbudowanie czteropanelowego dashboardu: KV-cache-usage, requests-running, GPU-util, P95 czasu na token wyjściowy. Ustawienie alertu na utrzymujące się KV-cache > 95%.
  5. Test obciążeniowy. vllm bench serve na własnym endpoincie, z realistycznymi kształtami promptów i współbieżnością. Strojenie --max-num-seqs, --gpu-memory-utilization i --max-model-len, aż P95 opóźnienia i łączna przepustowość osiągną wymagane SLA.

Dalsze części tej serii: topologia sieci (I03), zasilanie i chłodzenie laboratorium robotyki (I04), budowa referencyjna (I05) oraz wdrożenie floty (I06). Matematyka klastrowania znajduje się w K03, a realia interkonektu w N03.


To część Kentino Wiki, serii referencyjnej o obliczeniach AI, robotyce i systemach, które je łączą. Komentarze i poprawki mile widziane pod adresem info@kentino.com.