
Implementează un LLM cu Modal: De la pip install la endpoint de producție
Majoritatea ghidurilor despre găzduirea proprie a LLM-urilor trec cu vederea cea mai dificilă parte: infrastructura. Te lupți cu driverele CUDA, gestionezi imagini Docker, configurezi autoscaling-ul și, cumva, tot ajungi să plătești pentru GPU-uri inactive la 3 dimineața. Modal elimină toate aceste probleme. Scrii cod Python, îl implementezi și primești un URL.
Acest ghid te va ghida prin procesul de implementare a unui LLM open-source pe Modal, folosind vLLM ca motor de inferență. La final, vei avea un endpoint API live, compatibil OpenAI, care rulează pe GPU-uri H100 și se reduce la zero (scale-to-zero) când nu este utilizat.
Ce este Modal (și de ce să-l folosești pentru LLM-uri)?
Modal este o platformă de calcul serverless construită special pentru sarcinile de lucru AI. Gândește-te la AWS Lambda, dar cu suport GPU, facturare pe secundă și o experiență de dezvoltare nativă Python. Nu există fișiere YAML, nu există Dockerfiles, nu există Kubernetes; îți definești întreaga infrastructură într-un script Python și o implementezi cu o singură comandă.
Iată de ce a devenit soluția preferată pentru implementarea LLM-urilor:
- Facturare scale-to-zero, nu plătești nimic când endpoint-ul tău nu gestionează cereri
- Prețuri GPU pe secundă, H100 la ~3,95 USD/oră, A100 80GB la ~2,50 USD/oră, facturate pe secundă
- Porniri la rece (cold starts) sub o secundă, containerele se inițializează rapid, mai ales cu snapshot-uri de memorie
- Credite gratuite de 30 USD/lună, suficient pentru a experimenta fără a introduce datele cardului de credit
- Fără DevOps, fără build-uri Docker, fără Terraform, fără gestionarea clusterelor
Dacă ai rulat LLM-uri local și vrei să le oferi un API propriu-zis fără a gestiona servere, Modal este calea cea mai scurtă spre acest obiectiv.
Modal vs. RunPod vs. Lambda
| Caracteristică | Modal | RunPod | Lambda |
|---|---|---|---|
| Model de facturare | Pe secundă, scale-to-zero | Pe secundă, taxă minimă | Pe oră, mereu activ |
| Cold start | 2-4 secunde | 6-12 secunde (mare) | N/A (persistent) |
| Disponibilitate GPU | H100, A100, L40S, T4 | A100, H100, A6000 | H100, A100 |
| Infrastructură | Python pur, fără fișiere de configurare | Bazat pe Docker, mai mult control | Acces VM complet |
| Nivel gratuit | Credite de 30 USD/lună | Niciunul | Niciunul |
| Cel mai potrivit pentru | Sarcini bursty/de dezvoltare | Trafic constant de inferență | Antrenament cu utilizare ridicată |
Concluzie: Modal câștigă pentru sarcinile de lucru variabile (bursty) și pentru dezvoltare. Dacă utilizarea GPU-ului va depăși constant 40%, o instanță dedicată pe RunPod sau Lambda este mai ieftină. Pentru orice altceva — prototipare, API-uri intermitente, demo-uri — modelul scale-to-zero al Modal economisește bani reali.
Cerințe preliminare
Înainte de a începe, ai nevoie de trei lucruri:
- Python 3.10+ instalat local
- Un cont Modal, înscrie-te gratuit pe modal.com
- Un cont Hugging Face, pentru accesul la modele (majoritatea modelelor sunt restricționate)
Atât. Nu ai nevoie de GPU pe mașina ta locală, nu ai nevoie de toolkit CUDA, nu ai nevoie de Docker.
Pasul 1: Instalează Modal și autentifică-te
Deschide un terminal și instalează pachetul Python Modal:
pip install modalApoi rulează comanda de configurare pentru a lega mediul local de contul tău Modal:
modal setupAceasta va deschide o fereastră de browser pentru autentificare. După confirmare, Modal stochează un token local. Nu va mai trebui să faci acest lucru din nou.
Pasul 2: Definește imaginea containerului
Containerele Modal sunt definite în Python. Specifici imaginea de bază, instalezi dependențele și setezi variabilele de mediu, totul sub formă de cod. Creează un fișier numit app.py:
import modal
# Define the container image with CUDA, Python, and vLLM
vllm_image = (
modal.Image.from_registry(
"nvidia/cuda:12.8.0-devel-ubuntu22.04", add_python="3.12"
)
.entrypoint([])
.pip_install(
"vllm==0.13.0",
"huggingface-hub==0.36.0",
)
)
app = modal.App("llm-endpoint", image=vllm_image)Câteva aspecte de remarcat. Nu există Dockerfile, lanțul modal.Image îl înlocuiește în totalitate. Imaginea de bază include NVIDIA CUDA 12.8 cu Ubuntu 22.04, iar peste aceasta instalăm vLLM și clientul Hugging Face Hub.
Pasul 3: Configurează stocarea modelului cu Volume
Greutățile LLM sunt mari (un model cu 7 miliarde de parametri are aproximativ 14 GB în fp16). Nu vrei să le descarci de fiecare dată când pornește un container. Volumele Modal îți oferă stocare persistentă care se montează direct în containerele tale:
# Persistent volumes for caching model weights
hf_cache = modal.Volume.from_name("huggingface-cache", create_if_missing=True)
vllm_cache = modal.Volume.from_name("vllm-cache", create_if_missing=True)
MODEL_NAME = "Qwen/Qwen3-4B-Thinking-2507-FP8"
MODEL_REVISION = "953532f942706930ec4bb870569932ef63038fdf"Aici folosim Qwen3-4B-Thinking (FP8), un model cuantizat de 4 miliarde de parametri care este rapid, capabil și se potrivește pe un singur GPU. Poți schimba acest model cu orice model de pe Hugging Face: Llama 3.1 8B, Mistral 7B sau orice suportă vLLM.
De ce FP8? Reduce utilizarea memoriei la aproximativ jumătate față de fp16, ceea ce înseamnă că poți rula modele mai mari pe același GPU sau modele mai mici pe GPU-uri mai ieftine. Dacă ești curios despre compromisurile cuantizării, ghidul nostru despre rularea LLM-urilor local acoperă detaliat formatele de precizie.
Pasul 4: Creează funcția server vLLM
Aici intervine magia Modal. Decorezi o funcție Python cu cerințele GPU, configurația de scalare și o adnotare de server web. Modal se ocupă de tot restul:
N_GPU = 1
MINUTES = 60
VLLM_PORT = 8000
@app.function(
gpu=f"H100:{N_GPU}",
scaledown_window=15 * MINUTES,
timeout=10 * MINUTES,
volumes={
"/root/.cache/huggingface": hf_cache,
"/root/.cache/vllm": vllm_cache,
},
)
@modal.concurrent(max_inputs=32)
@modal.web_server(port=VLLM_PORT, startup_timeout=10 * MINUTES)
def serve():
import subprocess
cmd = [
"vllm", "serve",
MODEL_NAME,
"--revision", MODEL_REVISION,
"--served-model-name", MODEL_NAME,
"--host", "0.0.0.0",
"--port", str(VLLM_PORT),
"--tensor-parallel-size", str(N_GPU),
"--enforce-eager", # Faster cold starts
]
subprocess.Popen(" ".join(cmd), shell=True)Să analizăm decoratorii cheie:
gpu="H100:1", solicită un singur GPU H100. Schimbă în"A100-80GB:1"pentru inferență mai ieftină sau"H100:2"pentru modele de 70B+scaledown_window=15 * MINUTES, menține containerul „cald” timp de 15 minute după ultima cerere, apoi se reduce la zero@modal.concurrent(max_inputs=32), permite până la 32 de cereri concurente per container (vLLM gestionează batch-ingul intern)@modal.web_server(port=8000), expune serverul HTTP vLLM direct ca un endpoint web Modal--enforce-eager, sare compilarea graficelor CUDA pentru porniri la rece mai rapide (compromis: throughput maxim ușor mai scăzut)
Parametrul scaledown_window este principala ta pârghie de control a costurilor. Setează-l la 5 minute pentru dezvoltare, 15-30 minute pentru API-urile de producție unde te aștepți la trafic regulat.
Pasul 5: Implementează în producție
O singură comandă. Asta e tot:
modal deploy app.pyModal construiește imaginea containerului, o împinge în registrul lor și returnează un URL live:
✓ Created objects.
├── 🔨 Created mount /app.py
├── 🔨 Created volume huggingface-cache
├── 🔨 Created volume vllm-cache
└── 🔨 Created web function serve => https://your-workspace--llm-endpoint-serve.modal.runPrima implementare durează câteva minute deoarece descarcă greutățile modelului în volum. Implementările ulterioare (și pornirile la rece) sunt mult mai rapide deoarece greutățile sunt stocate în cache.
Pentru dezvoltare, folosește modal serve app.py în schimb; acesta reîncarcă automat la modificările fișierelor și îți oferă un URL temporar.
Pasul 6: Apelează endpoint-ul tău (Compatibil OpenAI)
Serverul vLLM implementat expune un API compatibil OpenAI la /v1/chat/completions. Poți folosi SDK-ul oficial Python OpenAI pentru a-l apela, doar indică URL-ul de bază către endpoint-ul tău Modal:
from openai import OpenAI
client = OpenAI(
api_key="not-needed", # vLLM doesn't require auth by default
base_url="https://your-workspace--llm-endpoint-serve.modal.run/v1",
)
response = client.chat.completions.create(
model="Qwen/Qwen3-4B-Thinking-2507-FP8",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain what vLLM is in two sentences."},
],
temperature=0.7,
max_tokens=256,
)
print(response.choices[0].message.content)Acest lucru funcționează și cu curl:
curl -X POST https://your-workspace--llm-endpoint-serve.modal.run/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-4B-Thinking-2507-FP8",
"messages": [{"role": "user", "content": "Hello!"}],
"max_tokens": 128
}'Orice instrument care suportă un API compatibil OpenAI va funcționa: LangChain, LlamaIndex, propria ta aplicație. Dacă direcționezi cereri către multiple endpoint-uri LLM, un instrument gateway LLM te poate ajuta să gestionezi failover-ul și echilibrarea sarcinii.
Sfaturi pentru optimizarea costurilor
Facturarea pe secundă a Modal este deja mai eficientă decât facturarea pe oră, dar poți scoate și mai mult din ea:
1. Folosește cuantizarea FP8
Modelele FP8 folosesc aproximativ jumătate din VRAM-ul omologilor lor fp16. Un Qwen3-8B în FP8 se potrivește pe un singur H100, în timp ce versiunea fp16 necesită majoritatea celor 80 GB ai acelui GPU. Mai puțin VRAM înseamnă că poți folosi GPU-uri mai ieftine (A100 40GB, L40S) pentru modele mai mici.
2. Ajustează fereastra de reducere (Scaledown Window)
Parametrul scaledown_window controlează cât timp rămâne cald un container după ultima cerere:
| Scenariu | Fereastră recomandată | De ce |
|---|---|---|
| Dezvoltare/testare | 5 minute | Economisește bani, cold starts sunt acceptabile |
| API intern (ocazional) | 10-15 minute | Echilibru între cost și latență |
| Producție (trafic regulat) | 20-30 minute | Minimizează cold starts |
| Producție cu trafic ridicat | Folosește min_containers=1 | Menține unul cald mereu |
3. Alege GPU-ul potrivit
Nu alege implicit H100. Modelele mai mici nu au nevoie de el:
| Dimensiune model | GPU recomandat | Cost aprox./oră |
|---|---|---|
| 1-4B parametri | L4 sau T4 | 0,59 - 0,80 USD |
| 7-8B parametri | A10 sau L40S | 1,10 - 1,95 USD |
| 13-14B parametri | A100 40GB | 2,10 USD |
| 30-70B parametri | A100 80GB sau H100 | 2,50 - 3,95 USD |
| 70B+ parametri | H100 x2 | 7,90 USD |
4. Activează caching-ul prompt-urilor
Dacă sarcinile tale de lucru implică prompt-uri de sistem repetitive sau prefixe partajate, caching-ul automat de prefix al vLLM poate reduce semnificativ latența și consumul de calcul. Îl poți activa adăugând --enable-prefix-caching la comanda de servire vLLM. Pentru o explorare mai profundă a modului în care funcționează caching-ul la diferiți provideri, consultă ghidul nostru despre caching-ul prompt-urilor LLM.
5. Folosește --enforce-eager pentru optimizarea cold start-urilor
Implicit, vLLM compilează grafice CUDA la pornire, ceea ce durează 1-3 minute în plus. Flag-ul --enforce-eager sare această compilare. Sacrifici aproximativ 10-15% din throughput-ul maxim pentru porniri la rece dramatic mai rapide. Pentru sarcinile de lucru bursty unde latența contează mai mult decât throughput-ul brut, este aproape întotdeauna decizia corectă.
Dincolo de baze: Modele fine-tuned
Odată ce te simți confortabil implementând modele de bază, următorul pas natural este implementarea propriei versiuni fine-tuned. Fluxul de lucru este identic; doar indici MODEL_NAME către repo-ul tău Hugging Face sau un volum Modal care conține greutățile fine-tuned.
Modal suportă, de asemenea, rularea job-urilor de fine-tuning direct pe GPU-urile lor. Poți antrena un adaptor LoRA pe Modal, îl salvezi într-un volum și implementezi modelul îmbinat (merged), totul fără a părăsi platforma. Ghidul nostru despre fine-tuning-ul LLM acoperă partea de antrenament în detaliu.
Fișierul complet app.py
Iată scriptul complet de implementare într-un bloc gata de copiat și lipit:
import modal
# --- Image Definition ---
vllm_image = (
modal.Image.from_registry(
"nvidia/cuda:12.8.0-devel-ubuntu22.04", add_python="3.12"
)
.entrypoint([])
.pip_install("vllm==0.13.0", "huggingface-hub==0.36.0")
)
# --- Volumes for Model Caching ---
hf_cache = modal.Volume.from_name("huggingface-cache", create_if_missing=True)
vllm_cache = modal.Volume.from_name("vllm-cache", create_if_missing=True)
# --- Model Config ---
MODEL_NAME = "Qwen/Qwen3-4B-Thinking-2507-FP8"
MODEL_REVISION = "953532f942706930ec4bb870569932ef63038fdf"
app = modal.App("llm-endpoint", image=vllm_image)
N_GPU = 1
MINUTES = 60
VLLM_PORT = 8000
@app.function(
gpu=f"H100:{N_GPU}",
scaledown_window=15 * MINUTES,
timeout=10 * MINUTES,
volumes={
"/root/.cache/huggingface": hf_cache,
"/root/.cache/vllm": vllm_cache,
},
)
@modal.concurrent(max_inputs=32)
@modal.web_server(port=VLLM_PORT, startup_timeout=10 * MINUTES)
def serve():
import subprocess
cmd = [
"vllm", "serve",
MODEL_NAME,
"--revision", MODEL_REVISION,
"--served-model-name", MODEL_NAME,
"--host", "0.0.0.0",
"--port", str(VLLM_PORT),
"--tensor-parallel-size", str(N_GPU),
"--enforce-eager",
]
subprocess.Popen(" ".join(cmd), shell=True)Implementează cu modal deploy app.py, schimbă MODEL_NAME cu orice model Hugging Face și ești live.
Întrebări frecvente
Cât costă rularea unui LLM pe Modal?
Depinde de GPU și de cât timp rămâne cald endpoint-ul tău. Un Qwen3-4B pe un H100 costă ~3,95 USD/oră de utilizare activă. Cu scale-to-zero și o fereastră de reducere de 15 minute, un endpoint utilizat ușor ar putea costa 5-15 USD/lună. Creditul lunar gratuit de 30 USD acoperă multe experimente.
Modal se reduce la zero (scale-to-zero)?
Da, acesta este unul dintre principalele sale puncte forte. Când nu sosesc cereri pentru durata scaledown_window, containerul se închide și nu mai plătești. Următoarea cerere declanșează un cold start (de obicei 2-10 secunde, în funcție de dimensiunea modelului și dacă folosești --enforce-eager).
Pot implementa Llama 3.1 sau Mistral pe Modal?
Absolut. Schimbă constanta MODEL_NAME cu orice model suportat de vLLM: meta-llama/Llama-3.1-8B-Instruct, mistralai/Mistral-7B-Instruct-v0.3 sau sute de altele de pe Hugging Face. Pentru modele de 70B+, schimbă N_GPU în 2 și folosește gpu="H100:2".
Cum se compară cold start-urile cu RunPod?
Cold start-urile Modal sunt de obicei de 2-4 secunde pentru containerul în sine, plus timpul de încărcare a modelului. Cu greutățile modelului stocate în cache într-un Volum și --enforce-eager activat, vorbim de 10-30 de secunde în total pentru un model de 7-8B. Cold start-urile serverless ale RunPod variază de la sub 200ms (cached) la 6-12 secunde pentru containere mai mari, deși modelul lor always-on evită complet cold start-urile.
Endpoint-ul vLLM al Modal este cu adevărat compatibil OpenAI?
Da. vLLM implementează aceleași endpoint-uri /v1/chat/completions, /v1/completions și /v1/models pe care le folosește OpenAI. Poți indica SDK-ul oficial Python openai către URL-ul tău Modal și va funcționa din cutie. Streaming, apelarea funcțiilor și modul JSON funcționează toate.
Am nevoie de un GPU pe mașina mea locală?
Nu. Mașina ta locală rulează doar CLI-ul Modal. Toată munca GPU se desfășoară pe infrastructura cloud a Modal. Ai putea implementa chiar și de pe un Chromebook dacă ai dori.
Cum adaug autentificare la endpoint-ul meu?
Endpoint-urile web Modal sunt publice implicit. Pentru producție, adaugă o verificare simplă a cheii API în codul aplicației sau folosește funcțiile încorporate de autentificare web ale Modal. Poți configura, de asemenea, un strat proxy folosind un gateway LLM care gestionează auth, limitarea ratei și rutarea.
Care este diferența dintre modal serve și modal deploy?
modal serve creează un endpoint temporar care se reîncarcă automat când editezi codul, perfect pentru dezvoltare. modal deploy creează un endpoint persistent, gata de producție, cu un URL stabil. Folosește serve în timp iterezi, deploy când ești gata să lansezi.
Pot folosi SGLang în loc de vLLM?
Da. Documentația Modal include exemple SGLang alături de vLLM. SGLang tinde să aibă overhead mai mic pentru sarcinile de lucru intensive la decodare și modele mai mici. vLLM este generally mai bun pentru sarcini mixte cu prefill intens. Ambele produc endpoint-uri compatibile OpenAI.
Cum se compară acest lucru cu implementarea pe Railway sau Render?
Platforme precum Railway, Render și Fly.io sunt grozave pentru aplicații web, dar nu oferă instanțe GPU. Modal este construit special pentru sarcinile de lucru GPU cu facturare pe secundă și autoscaling. Dacă trebuie să servești un LLM, Modal (sau RunPod) este instrumentul potrivit; platformele PaaS tradiționale nu pot face acest lucru.