guides

LLM mit Modal deployen: Von pip install zum Production-Endpoint

Geschrieben von Mert Batur
Mar 27, 2026
9 Lesezeit
LLM mit Modal deployen: Von pip install zum Production-Endpoint

LLM mit Modal deployen: Von pip install zum Production-Endpoint

Die meisten Anleitungen zum Selbst-Hosten von LLMs übergehen den schwierigsten Teil: die Infrastruktur. Man kämpft mit CUDA-Treibern, verwaltet Docker-Images, konfiguriert Autoscaling und zahlt trotzdem für idle GPUs um 3 Uhr nachts. Modal eliminiert das alles. Du schreibst Python, deployest und bekommst eine URL.

Diese Anleitung zeigt dir, wie du ein Open-Source-LLM auf Modal mit vLLM als Inferenz-Engine deployest. Am Ende hast du einen live OpenAI-kompatiblen API-Endpunkt auf H100-GPUs, der auf null skaliert, wenn niemand ihn nutzt.

Was ist Modal (und warum für LLMs nutzen)?

Modal ist eine serverlose Computing-Plattform, die speziell für KI-Workloads gebaut wurde. Stell es dir vor wie AWS Lambda, aber mit GPU-Unterstützung, sekundengenauer Abrechnung und einer Python-nativen Entwicklererfahrung. Kein YAML, keine Dockerfiles, kein Kubernetes – du definierst deine gesamte Infrastruktur in einem Python-Skript und deployest mit einem einzigen Befehl.

Deshalb ist es die erste Wahl für LLM-Deployment:

  • Scale-to-Zero-Abrechnung – du zahlst nichts, wenn dein Endpunkt keine Anfragen bearbeitet
  • Sekundengenaue GPU-Preise – H100s für ~3,70 €/Std., A100 80GB für ~2,35 €/Std., sekundengenau abgerechnet
  • Subsekundenkaltstarts – Container starten schnell, besonders mit Memory-Snapshots
  • 30 $/Monat Gratis-Credits – genug zum Experimentieren ohne Kreditkartenbelastung
  • Kein DevOps – keine Docker-Builds, kein Terraform, kein Cluster-Management

Wenn du LLMs lokal ausführst und ihnen ohne Server-Management eine richtige API geben möchtest, ist Modal der kürzeste Weg dorthin.

MerkmalModalRunPodLambda
AbrechnungsmodellSekundengenau, Scale-to-ZeroSekundengenau, MindestgebührStündlich, immer aktiv
Kaltstart2-4 Sekunden6-12 Sekunden (groß)Entfällt (persistent)
GPU-VerfügbarkeitH100, A100, L40S, T4A100, H100, A6000H100, A100
InfrastrukturReines Python, keine Config-DateienDocker-basiert, mehr KontrolleVollständiger VM-Zugriff
Gratis-Tier30 $/Monat CreditsKeinsKeins
Am besten fürBursthafte/Dev-WorkloadsGleichmäßiger Inferenz-TrafficHochauslastungs-Training

Fazit: Modal gewinnt bei burstartigen Workloads und der Entwicklung. Wenn deine GPU-Auslastung dauerhaft über 40 % liegt, ist eine dedizierte Instanz auf RunPod oder Lambda günstiger. Für alles andere – Prototyping, sporadische APIs, Demos – spart Modals Scale-to-Zero-Modell echtes Geld.

Voraussetzungen

Bevor du anfängst, brauchst du drei Dinge:

  1. Python 3.10+ lokal installiert
  2. Ein Modal-Konto – kostenlos anmelden unter modal.com
  3. Ein Hugging Face-Konto – für Modellzugriff (die meisten Modelle sind gesperrt)

Das war's. Keine GPU auf deinem lokalen Rechner, kein CUDA-Toolkit, kein Docker.

Schritt 1: Modal installieren und authentifizieren

Öffne ein Terminal und installiere das Modal Python-Paket:

bash
pip install modal

Führe dann den Setup-Befehl aus, um deine lokale Umgebung mit deinem Modal-Konto zu verknüpfen:

bash
modal setup

Dies öffnet ein Browserfenster zur Authentifizierung. Nach der Bestätigung speichert Modal lokal ein Token. Das musst du nie wieder tun.

Schritt 2: Das Container-Image definieren

Modal-Container werden in Python definiert. Du gibst das Basis-Image an, installierst Abhängigkeiten und setzt Umgebungsvariablen – alles als Code. Erstelle eine Datei namens app.py:

python
import modal

# Container-Image mit CUDA, Python und vLLM definieren
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)

Ein paar Dinge fallen auf: Es gibt kein Dockerfile – die modal.Image-Kette ersetzt es vollständig. Das Basis-Image enthält NVIDIA CUDA 12.8 mit Ubuntu 22.04, und wir installieren vLLM und den Hugging Face Hub-Client darüber.

Schritt 3: Modell-Speicher mit Volumes konfigurieren

LLM-Gewichte sind groß (ein 7B-Parameter-Modell ist ~14 GB in fp16). Du willst sie nicht bei jedem Container-Start neu herunterladen. Modal Volumes bieten persistenten Speicher, der direkt in deine Container gemountet wird:

python
# Persistente Volumes für das Caching von Modellgewichten
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"

Wir verwenden hier Qwen3-4B-Thinking (FP8) – ein quantisiertes 4-Milliarden-Parameter-Modell, das schnell, leistungsfähig ist und auf eine einzelne GPU passt. Du kannst es gegen jedes Hugging Face-Modell austauschen: Llama 3.1 8B, Mistral 7B oder alles, was vLLM unterstützt.

Warum FP8? Es reduziert den Speicherbedarf im Vergleich zu fp16 ungefähr um die Hälfte, sodass du größere Modelle auf derselben GPU ausführen oder kleinere Modelle auf günstigeren GPUs betreiben kannst. Wenn dich Quantisierungs-Kompromisse interessieren, behandelt unser Leitfaden zum lokalen Ausführen von LLMs die Präzisionsformate ausführlich.

Schritt 4: Die vLLM-Server-Funktion erstellen

Hier geschieht Modals Magie. Du dekorierst eine Python-Funktion mit GPU-Anforderungen, Skalierungskonfiguration und einer Webserver-Annotation. Modal kümmert sich um den 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",  # Schnellere Kaltstarts
    ]

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

Lass uns die wichtigsten Dekoratoren aufschlüsseln:

  • gpu="H100:1" – fordert eine einzelne H100-GPU an. Ändere zu "A100-80GB:1" für günstigere Inferenz oder "H100:2" für 70B+-Modelle
  • scaledown_window=15 * MINUTES – hält den Container 15 Minuten nach der letzten Anfrage warm, dann skaliert er auf null
  • @modal.concurrent(max_inputs=32) – erlaubt bis zu 32 gleichzeitige Anfragen pro Container (vLLM handhabt Batching intern)
  • @modal.web_server(port=8000) – exponiert den vLLM-HTTP-Server direkt als Modal-Web-Endpunkt
  • --enforce-eager – überspringt die CUDA-Graph-Kompilierung für schnellere Kaltstarts (Kompromiss: etwas geringerer Spitzendurchsatz)

Das scaledown_window ist dein wichtigster Kostenhebel. Setze es auf 5 Minuten für Dev, 15-30 Minuten für Produktions-APIs mit regelmäßigem Traffic.

Schritt 5: In Produktion deployen

Ein Befehl. Das ist alles:

bash
modal deploy app.py

Modal erstellt das Container-Image, pusht es in sein Registry und gibt eine Live-URL zurück:

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

Das erste Deployment dauert ein paar Minuten, da Modellgewichte in das Volume heruntergeladen werden. Nachfolgende Deployments (und Kaltstarts) sind viel schneller, da die Gewichte gecacht sind.

Für die Entwicklung verwende stattdessen modal serve app.py – es lädt bei Dateiänderungen heiß neu und gibt dir eine temporäre URL.

Schritt 6: Deinen Endpunkt aufrufen (OpenAI-kompatibel)

Dein deployeter vLLM-Server exponiert eine OpenAI-kompatible API unter /v1/chat/completions. Du kannst das Standard-OpenAI Python SDK verwenden, um ihn aufzurufen – zeige einfach die Basis-URL auf deinen Modal-Endpunkt:

python
from openai import OpenAI

client = OpenAI(
    api_key="not-needed",  # vLLM erfordert standardmäßig keine Authentifizierung
    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)

Das funktioniert auch mit 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
  }'

Jedes Tool, das eine OpenAI-kompatible API unterstützt, funktioniert – LangChain, LlamaIndex, deine eigene App. Wenn du Anfragen über mehrere LLM-Endpunkte routest, kann ein LLM-Gateway-Tool dir bei Failover und Load-Balancing helfen.

Tipps zur Kostenoptimierung

Modals sekundengenaue Abrechnung ist bereits effizienter als stündliche Preisgestaltung, aber du kannst noch mehr herausholen:

1. FP8-Quantisierung verwenden

FP8-Modelle verbrauchen ungefähr halb so viel VRAM wie ihre fp16-Entsprechungen. Ein Qwen3-8B in FP8 passt auf eine einzelne H100, während die fp16-Version den größten Teil der 80 GB dieser GPU benötigt. Weniger VRAM bedeutet, dass du günstigere GPUs (A100 40GB, L40S) für kleinere Modelle verwenden kannst.

2. Das Scaledown-Fenster anpassen

Der scaledown_window-Parameter steuert, wie lange ein Container nach der letzten Anfrage warm bleibt:

SzenarioEmpfohlenes FensterWarum
Entwicklung/Tests5 MinutenGeld sparen, Kaltstarts sind in Ordnung
Interne API (gelegentlich)10-15 MinutenBalance zwischen Kosten und Latenz
Produktion (regelmäßiger Traffic)20-30 MinutenKaltstarts minimieren
Hochfrequenz-Produktionmin_containers=1 verwendenEinen immer warm halten

3. Die richtige GPU wählen

Nicht immer H100 nehmen. Kleinere Modelle brauchen das nicht:

ModellgrößeEmpfohlene GPUUngefähre Kosten/Std.
1-4B ParameterL4 oder T40,55 – 0,75 €
7-8B ParameterA10 oder L40S1,05 – 1,85 €
13-14B ParameterA100 40GB2,00 €
30-70B ParameterA100 80GB oder H1002,35 – 3,70 €
70B+ ParameterH100 x27,40 €

4. Prompt-Caching aktivieren

Wenn deine Workloads wiederholte System-Prompts oder gemeinsame Präfixe beinhalten, kann vLLMs automatisches Präfix-Caching Latenz und Rechenaufwand erheblich reduzieren. Aktiviere es, indem du --enable-prefix-caching zum vLLM-Serve-Befehl hinzufügst. Für einen tieferen Einblick, wie Caching bei verschiedenen Anbietern funktioniert, sieh dir unseren LLM Prompt-Caching-Leitfaden an.

5. --enforce-eager für Kaltstart-Optimierung verwenden

Standardmäßig kompiliert vLLM CUDA-Graphen beim Start, was 1-3 zusätzliche Minuten dauert. Das --enforce-eager-Flag überspringt diese Kompilierung. Du tauschst ~10-15 % Spitzendurchsatz gegen dramatisch schnellere Kaltstarts ein. Für bursthafte Workloads, bei denen Latenz wichtiger als roher Durchsatz ist, ist es fast immer die richtige Wahl.

Weiterführend: Fine-Tuned Modelle

Sobald du mit dem Deployment von Basismodellen vertraut bist, ist der natürliche nächste Schritt das Deployment deiner eigenen feinabgestimmten Version. Der Workflow ist identisch – du zeigst MODEL_NAME einfach auf dein Hugging Face-Repository oder ein Modal-Volume mit deinen feinabgestimmten Gewichten.

Modal unterstützt auch das Ausführen von Fine-Tuning-Jobs direkt auf ihren GPUs. Du kannst einen LoRA-Adapter auf Modal trainieren, ihn in einem Volume speichern und das zusammengeführte Modell deployen – alles ohne die Plattform zu verlassen. Unser LLM Fine-Tuning-Leitfaden behandelt die Trainingsseite ausführlich.

Die vollständige app.py

Hier ist das vollständige Deployment-Skript als kopierfertigem Block:

python
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 für Modell-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)

# --- Modell-Konfiguration ---
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)

Mit modal deploy app.py deployen, MODEL_NAME gegen ein beliebiges Hugging Face-Modell austauschen, und du bist live.

Häufig gestellte Fragen

Wie viel kostet es, ein LLM auf Modal zu betreiben?

Das hängt von der GPU und davon ab, wie lange dein Endpunkt warm bleibt. Ein Qwen3-4B auf einem H100 kostet ~3,70 €/Std. aktiver Nutzung. Mit Scale-to-Zero und einem 15-minütigen Scaledown-Fenster könnte ein wenig genutzter Endpunkt 5-15 €/Monat kosten. Die 30 $ Gratis-Credits pro Monat decken viele Experimente ab.

Skaliert Modal auf null?

Ja – das ist einer der wichtigsten Vorteile. Wenn für die Dauer deines scaledown_window keine Anfragen eintreffen, fährt der Container herunter und du hörst auf zu zahlen. Die nächste Anfrage löst einen Kaltstart aus (typischerweise 2-10 Sekunden, je nach Modellgröße und ob du --enforce-eager verwendest).

Kann ich Llama 3.1 oder Mistral auf Modal deployen?

Absolut. Tausche die MODEL_NAME-Konstante gegen ein beliebiges von vLLM unterstütztes Modell aus: meta-llama/Llama-3.1-8B-Instruct, mistralai/Mistral-7B-Instruct-v0.3 oder Hunderte andere auf Hugging Face. Für 70B+-Modelle ändere N_GPU auf 2 und verwende gpu="H100:2".

Wie vergleichen sich Kaltstarts mit RunPod?

Modal-Kaltstarts dauern typischerweise 2-4 Sekunden für den Container selbst, plus Modell-Ladezeit. Mit in einem Volume gecachten Modellgewichten und aktiviertem --enforce-eager sind es insgesamt 10-30 Sekunden für ein 7-8B-Modell. RunPods serverlose Kaltstarts reichen von unter 200 ms (gecacht) bis 6-12 Sekunden für größere Container – obwohl ihr Always-On-Modell Kaltstarts vollständig vermeidet.

Ist Modals vLLM-Endpunkt wirklich OpenAI-kompatibel?

Ja. vLLM implementiert dieselben /v1/chat/completions-, /v1/completions- und /v1/models-Endpunkte, die OpenAI verwendet. Du kannst das offizielle openai Python SDK auf deine Modal-URL zeigen und es funktioniert sofort. Streaming, Function Calling und JSON-Modus funktionieren alle.

Brauche ich eine GPU auf meinem lokalen Rechner?

Nein. Dein lokaler Rechner führt nur die Modal CLI aus. Die gesamte GPU-Arbeit findet auf Modals Cloud-Infrastruktur statt. Du könntest von einem Chromebook aus deployen, wenn du wolltest.

Wie füge ich meinem Endpunkt Authentifizierung hinzu?

Modal-Web-Endpunkte sind standardmäßig öffentlich. Für die Produktion füge eine einfache API-Key-Prüfung in deinen Anwendungscode ein oder nutze Modals integrierte Web-Authentifizierungsfunktionen. Du kannst auch eine Proxy-Schicht mit einem LLM-Gateway einrichten, das Auth, Rate Limiting und Routing handhabt.

Was ist der Unterschied zwischen modal serve und modal deploy?

modal serve erstellt einen temporären Endpunkt, der bei Code-Änderungen heiß neu lädt – perfekt für die Entwicklung. modal deploy erstellt einen persistenten, produktionsreifen Endpunkt mit einer stabilen URL. Verwende serve beim Iterieren, deploy wenn du bereit zum Ausliefern bist.

Kann ich SGLang anstelle von vLLM verwenden?

Ja. Modals Dokumentation enthält SGLang-Beispiele neben vLLM. SGLang hat tendenziell weniger Overhead für decode-lastige Workloads und kleinere Modelle. vLLM ist generell besser für gemischte Workloads mit schwerem Prefill geeignet. Beide produzieren OpenAI-kompatible Endpunkte.

Wie verhält sich das im Vergleich zum Deployment auf Railway oder Render?

Plattformen wie Railway, Render und Fly.io sind großartig für Web-Apps, bieten aber keine GPU-Instanzen. Modal ist speziell für GPU-Workloads mit sekundengenauer Abrechnung und Autoscaling gebaut. Wenn du ein LLM bereitstellen musst, ist Modal (oder RunPod) das richtige Werkzeug – traditionelle PaaS-Plattformen können das nicht.

Quellen

Tags

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

Diesen Artikel teilen

Ihr Projekt starten

Bereit, etwas Außergewöhnliches zu bauen?

Machen wir aus Ihrer Vision ein fertiges Produkt. Unser Team baut mit Ihnen Software, die spürbar etwas bewegt.