guides

Een LLM deployen met Modal: van pip install naar productie-endpoint

Geschreven door Mert Batur
Mar 27, 2026
9 leestijd
Een LLM deployen met Modal: van pip install naar productie-endpoint

Een LLM deployen met Modal: van pip install naar productie-endpoint

De meeste gidsen over het zelf hosten van LLM's slaan het moeilijkste deel over: de infrastructuur. Je vecht met CUDA-drivers, beheert Docker-images, configureert autoscaling, en betaalt toch nog voor inactieve GPU's om 3 uur 's nachts. Modal elimineert dit allemaal. Je schrijft Python, je deployt, je krijgt een URL.

Deze gids laat je zien hoe je een open-source LLM deployt op Modal met vLLM als inferentie-engine. Aan het einde heb je een live OpenAI-compatibel API-endpoint op H100-GPU's dat naar nul schaalt wanneer niemand het gebruikt.

Wat is Modal (en waarom gebruiken voor LLM's)?

Modal is een serverloos computerplatform dat speciaal gebouwd is voor AI-workloads. Zie het als AWS Lambda, maar met GPU-ondersteuning, facturering per seconde en een Python-native ontwikkelaarservaring. Geen YAML, geen Dockerfiles, geen Kubernetes — je definieert je volledige infrastructuur in een Python-script en deployt met één enkele opdracht.

Dit is waarom het de standaard is geworden voor LLM-deployment:

  • Scale-to-zero facturering — je betaalt niets wanneer je endpoint geen verzoeken verwerkt
  • GPU-prijzen per seconde — H100's voor ~$3,95/uur, A100 80 GB voor ~$2,50/uur, per seconde gefactureerd
  • Sub-seconde koude starts — containers starten snel op, zeker met geheugen-snapshots
  • $30/maand gratis credits — genoeg om te experimenteren zonder creditcardkosten
  • Geen DevOps — geen Docker-builds, geen Terraform, geen clusterbeheer

Als je LLM's lokaal uitvoert en ze een goede API wil geven zonder servers te beheren, is Modal de kortste weg daarheen.

FunctieModalRunPodLambda
FactureringsmodelPer seconde, scale-to-zeroPer seconde, min. kostenPer uur, altijd aan
Koude start2-4 seconden6-12 seconden (groot)Nvt (persistent)
GPU-beschikbaarheidH100, A100, L40S, T4A100, H100, A6000H100, A100
InfrastructuurPuur Python, geen config-bestandenDocker-gebaseerd, meer controleVolledige VM-toegang
Gratis niveau$30/maand creditsGeenGeen
Beste voorBurstachtige/dev-workloadsStabiel inferentieverkeerIntensieve training

Conclusie: Modal wint voor burstachtige workloads en ontwikkeling. Als je GPU-gebruik consistent boven de 40% ligt, is een toegewezen instantie op RunPod of Lambda goedkoper. Voor al het andere — prototyping, sporadische API's, demo's — bespaart Modals scale-to-zero-model echt geld.

Vereisten

Voordat je begint, heb je drie dingen nodig:

  1. Python 3.10+ lokaal geïnstalleerd
  2. Een Modal-account — gratis aanmelden op modal.com
  3. Een Hugging Face-account — voor modeltoegang (de meeste modellen zijn afgesloten)

Dat is alles. Geen GPU op je lokale machine, geen CUDA-toolkit, geen Docker.

Stap 1: Modal installeren en authenticeren

Open een terminal en installeer het Modal Python-pakket:

bash
pip install modal

Voer vervolgens de setupopdracht uit om je lokale omgeving te koppelen aan je Modal-account:

bash
modal setup

Dit opent een browservenster voor authenticatie. Zodra je bevestigt, slaat Modal een token lokaal op. Je hoeft dit nooit meer te doen.

Stap 2: Het container-image definiëren

Modal-containers worden gedefinieerd in Python. Je specificeert het basisimage, installeert afhankelijkheden en stelt omgevingsvariabelen in — alles als code. Maak een bestand aan met de naam app.py:

python
import modal

# Definieer het container-image met CUDA, Python en 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)

Een paar dingen om op te letten. Er is geen Dockerfile — die modal.Image-keten vervangt het volledig. Het basisimage bevat NVIDIA CUDA 12.8 met Ubuntu 22.04, en we installeren vLLM en de Hugging Face Hub-client erbovenop.

Stap 3: Modelopslag configureren met Volumes

LLM-gewichten zijn groot (een model met 7 miljard parameters is ~14 GB in fp16). Je wilt ze niet elke keer dat een container start opnieuw downloaden. Modal Volumes geven je persistente opslag die direct in je containers wordt gemount:

python
# Persistente volumes voor het cachen van modelgewichten
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"

We gebruiken hier Qwen3-4B-Thinking (FP8) — een gekwantiseerd model met 4 miljard parameters dat snel, capabel is en op één GPU past. Je kunt het verwisselen voor elk Hugging Face-model: Llama 3.1 8B, Mistral 7B, of alles wat vLLM ondersteunt.

Waarom FP8? Het vermindert het geheugengebruik ruwweg met de helft vergeleken met fp16, wat betekent dat je grotere modellen op dezelfde GPU kunt draaien — of kleinere modellen op goedkopere GPU's. Als je nieuwsgierig bent naar de afwegingen bij kwantisering, behandelt onze gids voor het lokaal draaien van LLM's de precisieformaten in detail.

Stap 4: De vLLM-serverfunctie aanmaken

Dit is waar Modals magie plaatsvindt. Je decoreert een Python-functie met GPU-vereisten, schalingsconfiguratie en een webserver-annotatie. Modal regelt de rest:

python
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",  # Snellere koude starts
    ]

    subprocess.Popen(" ".join(cmd), shell=True)

Laten we de belangrijkste decorators uitleggen:

  • gpu="H100:1" — vraagt één H100-GPU aan. Verander naar "A100-80GB:1" voor goedkopere inferentie, of "H100:2" voor 70B+-modellen
  • scaledown_window=15 * MINUTES — houdt de container 15 minuten warm na het laatste verzoek, dan schaalt hij naar nul
  • @modal.concurrent(max_inputs=32) — staat tot 32 gelijktijdige verzoeken per container toe (vLLM verwerkt batching intern)
  • @modal.web_server(port=8000) — stelt de vLLM HTTP-server direct bloot als Modal-web-endpoint
  • --enforce-eager — slaat CUDA-grafiekcompilatie over voor snellere koude starts (afweging: iets lager piekdoorvoer)

Het scaledown_window is je voornaamste kostenknop. Stel het in op 5 minuten voor dev, 15-30 minuten voor productie-API's met regelmatig verkeer.

Stap 5: Deployen naar productie

Één opdracht. Dat is alles:

bash
modal deploy app.py

Modal bouwt het container-image, pusht het naar hun register en geeft een live URL terug:

text
✓ 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.run

De eerste deployment duurt een paar minuten omdat modelgewichten naar het volume worden gedownload. Volgende deployments (en koude starts) zijn veel sneller omdat de gewichten gecacht zijn.

Gebruik voor ontwikkeling modal serve app.py — het herlaadt bij bestandswijzigingen en geeft je een tijdelijke URL.

Stap 6: Je endpoint aanroepen (OpenAI-compatibel)

Je gedeployede vLLM-server stelt een OpenAI-compatibele API beschikbaar op /v1/chat/completions. Je kunt de standaard OpenAI Python SDK gebruiken om hem aan te roepen — wijs de basis-URL gewoon naar je Modal-endpoint:

python
from openai import OpenAI

client = OpenAI(
    api_key="not-needed",  # vLLM vereist standaard geen authenticatie
    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)

Dit werkt ook met curl:

bash
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
  }'

Elk tool dat een OpenAI-compatibele API ondersteunt zal werken — LangChain, LlamaIndex, je eigen app. Als je verzoeken routeert over meerdere LLM-endpoints, kan een LLM-gateway-tool je helpen bij failover en taakverdeling.

Tips voor kostenoptimalisatie

Modals facturering per seconde is al efficiënter dan uurtarieven, maar je kunt er nog meer uit halen:

1. Gebruik FP8-kwantisering

FP8-modellen gebruiken ruwweg de helft van de VRAM van hun fp16-equivalenten. Een Qwen3-8B in FP8 past op één H100, terwijl de fp16-versie het grootste deel van de 80 GB van die GPU nodig heeft. Minder VRAM betekent dat je goedkopere GPU's (A100 40 GB, L40S) kunt gebruiken voor kleinere modellen.

2. Stel het scale-down-venster af

De scaledown_window-parameter bepaalt hoe lang een container warm blijft na het laatste verzoek:

ScenarioAanbevolen vensterWaarom
Ontwikkeling/testen5 minutenGeld besparen, koude starts zijn prima
Interne API (af en toe)10-15 minutenBalans tussen kosten en latentie
Productie (regelmatig verkeer)20-30 minutenKoude starts minimaliseren
Intensieve productieGebruik min_containers=1Houd er altijd één warm

3. Kies de juiste GPU

Neem niet altijd een H100. Kleinere modellen hebben dat niet nodig:

ModelgrootteAanbevolen GPUGeschatte kosten/uur
1-4B parametersL4 of T4$0,59 – $0,80
7-8B parametersA10 of L40S$1,10 – $1,95
13-14B parametersA100 40 GB$2,10
30-70B parametersA100 80 GB of H100$2,50 – $3,95
70B+ parametersH100 x2$7,90

4. Schakel prompt-caching in

Als je workloads herhaalde systeemprompts of gedeelde prefixen bevatten, kan vLLM's automatische prefix-caching latentie en rekenkracht aanzienlijk verminderen. Schakel het in door --enable-prefix-caching toe te voegen aan de vLLM serve-opdracht. Voor een diepere duik in hoe caching werkt bij verschillende providers, bekijk onze LLM prompt-caching-gids.

5. Gebruik --enforce-eager voor koude-start-optimalisatie

Standaard compileert vLLM CUDA-grafieken bij het opstarten, wat 1-3 extra minuten kost. De --enforce-eager-vlag slaat deze compilatie over. Je ruilt ~10-15% piekdoorvoer in voor dramatisch snellere koude starts. Voor burstachtige workloads waarbij latentie belangrijker is dan ruwe doorvoer, is dit bijna altijd de juiste keuze.

Verder gaan: fijngezuiverde modellen

Zodra je vertrouwd bent met het deployen van basismodellen, is de volgende stap het deployen van je eigen fijngezuiverde versie. De workflow is identiek — je wijst MODEL_NAME gewoon naar je Hugging Face-repository of een Modal-volume met je fijngezuiverde gewichten.

Modal ondersteunt ook het uitvoeren van fijnafstemtaken direct op hun GPU's. Je kunt een LoRA-adapter trainen op Modal, opslaan in een volume en het samengevoegde model deployen — alles zonder het platform te verlaten. Onze LLM fine-tuning-gids behandelt de trainingskant uitgebreid.

De volledige app.py

Hier is het volledige deployment-script in één kopieerklaar blok:

python
import modal

# --- Image-definitie ---
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 voor modelcaching ---
hf_cache = modal.Volume.from_name("huggingface-cache", create_if_missing=True)
vllm_cache = modal.Volume.from_name("vllm-cache", create_if_missing=True)

# --- Modelconfiguratie ---
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)

Deploy met modal deploy app.py, verwissel MODEL_NAME voor elk Hugging Face-model, en je bent live.

Veelgestelde vragen

Hoeveel kost het om een LLM op Modal te draaien?

Dat hangt af van de GPU en hoe lang je endpoint warm blijft. Een Qwen3-4B op een H100 kost ~$3,95/uur actief gebruik. Met scale-to-zero en een scale-down-venster van 15 minuten kan een weinig gebruikt endpoint $5-15/maand kosten. De $30 gratis maandelijkse credits dekt veel experimenten.

Schaalt Modal naar nul?

Ja — dat is een van de belangrijkste voordelen. Wanneer er geen verzoeken binnenkomen gedurende jouw scaledown_window, sluit de container af en stop je met betalen. Het volgende verzoek triggert een koude start (doorgaans 2-10 seconden afhankelijk van de modelgrootte en of je --enforce-eager gebruikt).

Kan ik Llama 3.1 of Mistral deployen op Modal?

Absoluut. Verwissel de MODEL_NAME-constante voor elk model dat vLLM ondersteunt: meta-llama/Llama-3.1-8B-Instruct, mistralai/Mistral-7B-Instruct-v0.3, of honderden anderen op Hugging Face. Voor 70B+-modellen, verander N_GPU naar 2 en gebruik gpu="H100:2".

Hoe vergelijken koude starts met RunPod?

Modal koude starts zijn doorgaans 2-4 seconden voor de container zelf, plus laadtijd van het model. Met modelgewichten gecacht in een Volume en --enforce-eager ingeschakeld, kijk je naar 10-30 seconden totaal voor een 7-8B model. RunPod's serverloze koude starts variëren van minder dan 200 ms (gecacht) tot 6-12 seconden voor grotere containers — hoewel hun always-on-model koude starts volledig vermijdt.

Is Modals vLLM-endpoint echt OpenAI-compatibel?

Ja. vLLM implementeert dezelfde /v1/chat/completions-, /v1/completions- en /v1/models-endpoints die OpenAI gebruikt. Je kunt de officiële openai Python SDK naar je Modal-URL wijzen en het werkt meteen. Streaming, function calling en JSON-modus werken allemaal.

Heb ik een GPU op mijn lokale machine nodig?

Nee. Je lokale machine voert alleen de Modal CLI uit. Al het GPU-werk vindt plaats op de cloudinfrastructuur van Modal. Je zou kunnen deployen vanaf een Chromebook als je dat wilde.

Hoe voeg ik authenticatie toe aan mijn endpoint?

Modal-web-endpoints zijn standaard openbaar. Voor productie, voeg een eenvoudige API-sleutelcontrole toe in je applicatiecode, of gebruik Modals ingebouwde webauthenticatiefuncties. Je kunt ook een proxy-laag opzetten met een LLM-gateway die authenticatie, snelheidsbeperking en routing afhandelt.

Wat is het verschil tussen modal serve en modal deploy?

modal serve maakt een tijdelijk endpoint dat opnieuw laadt bij codewijzigingen — perfect voor ontwikkeling. modal deploy maakt een persistent, productieklaar endpoint met een stabiele URL. Gebruik serve tijdens het itereren, deploy wanneer je klaar bent om te verzenden.

Kan ik SGLang gebruiken in plaats van vLLM?

Ja. Modals documentatie bevat SGLang-voorbeelden naast vLLM. SGLang heeft de neiging minder overhead te hebben voor decode-zware workloads en kleinere modellen. vLLM is over het algemeen beter voor gemengde workloads met veel prefill. Beide produceren OpenAI-compatibele endpoints.

Hoe vergelijkt dit met deployen op Railway of Render?

Platforms zoals Railway, Render en Fly.io zijn geweldig voor webapplicaties, maar bieden geen GPU-instanties. Modal is speciaal gebouwd voor GPU-workloads met facturering per seconde en autoscaling. Als je een LLM wilt aanbieden, is Modal (of RunPod) het juiste gereedschap — traditionele PaaS-platforms kunnen dit niet.

Bronnen

Tags

llm deployen modalmodal serverless gpuvllm deploymentllm inference apiserverless llmmodal labs tutorialllm zelf hosten

Dit artikel delen

Start je project

Klaar om iets buitengewoons te bouwen?

Laten we je idee werkelijkheid maken. Ons team staat klaar om software te bouwen die het verschil maakt.