, 9 Min. Lesezeit, von

Ollama: ein LLM lokal self-hosten (Quickstart per Docker und REST-API)

In 15 Minuten von der leeren Maschine zur eigenen LLM-API: Ollama per Docker Compose starten, ein Modell ziehen, /api/generate und /api/chat per curl aufrufen, plus drei Stolperfallen (offene API, Streaming-Default, VRAM-abhängiger Standard-Kontext).

Ein Sprachmodell auf eigener Hardware zu betreiben klingt nach GPU-Cluster und Wochenendprojekt. Für den Einstieg sind es ein Container und ein curl-Aufruf. Ollama bündelt Modell-Download, Speicherverwaltung und eine HTTP-Schnittstelle in einer einzigen Binary: Sie ziehen ein Modell wie ein Container-Image und sprechen es danach über REST an. Dieser Beitrag macht genau das (Container starten, Modell ziehen, zwei Endpunkte bedienen) und ordnet ein, wann dieser Weg trägt und wann nicht. Kein Deep Dive, sondern das Minimum, mit dem Sie in einer Viertelstunde eine funktionierende lokale LLM-API haben.

Aktualisiert am 19. Oktober 2026: Dieser Beitrag enthält jetzt auch die Inhalte des früheren Beitrags „Hermes von Nous Research selbst hosten: vLLM, Tool-Calling und Self-Hosting in der Praxis“.

Aktualisiert am 7. Oktober 2026: Die Angabe zur Standard-Kontextlänge präzisiert: Seit Ollama 0.15.5 hängt sie vom VRAM ab (4K unter 24 GiB, 32K bei 24 bis 48 GiB, ab 48 GiB 256K).

Was Ollama macht und wann Sie es nehmen

Ollama ist ein lokaler Inferenz-Server. Die Kernidee ist die Paketierung: Modellgewichte, Prompt-Template und Standardparameter liegen zusammen unter einem Namen im Format model:tag, etwa llama3.2:3b. Fehlt der Tag, gilt latest. Ein Pull lädt das Paket in ein lokales Verzeichnis, ein Request lädt es in den Speicher, und nach einer Leerlaufzeit (keep_alive, standardmäßig 5 Minuten) gibt Ollama den Speicher wieder frei. Sie verwalten keine Python-Umgebung, keine Tokenizer-Konfiguration und keine Quantisierung von Hand.

Genau daraus folgt die Abgrenzung. Ollama passt für lokale Entwicklung, interne Werkzeuge, Prototypen und kleine Teams, also überall dort, wo Bequemlichkeit und ein geringer Grundverbrauch wichtiger sind als maximaler Durchsatz. Sobald viele Anfragen parallel laufen und Sie Batching, Tensor-Parallelismus und ausgereiztes GPU-Sharing brauchen, ist ein Serving-Stack wie vLLM der bessere Weg. Wie das aussieht, zeigt der Abschnitt zu Hermes und Tool-Calling weiter unten. Kurzfassung: Ollama zum Anfangen und für den Einzelplatz, vLLM für die Produktionslast.

Ollama per Docker starten

Eine compose.yaml genügt. Wichtig sind zwei Dinge: ein Volume für die Modelle, sonst laden Sie mehrere Gigabyte nach jedem Neustart erneut, und eine Bindung an 127.0.0.1 (dazu gleich mehr bei den Stolperfallen).

services:
  ollama:
    image: ollama/ollama:0.32.6
    ports:
      - "127.0.0.1:11434:11434"
    volumes:
      - ollama_models:/root/.ollama
    environment:
      OLLAMA_CONTEXT_LENGTH: 8192
    restart: unless-stopped
    # Fuer NVIDIA-GPUs zusaetzlich (NVIDIA Container Toolkit vorausgesetzt):
    # deploy:
    #   resources:
    #     reservations:
    #       devices:
    #         - driver: nvidia
    #           count: all
    #           capabilities: [gpu]

volumes:
  ollama_models:

Starten und prüfen:

docker compose up -d
curl -s http://localhost:11434/api/version

Auf einem Entwicklungsrechner geht es auch ohne Docker: Unter Linux installiert curl -fsSL https://ollama.com/install.sh | sh den Dienst nativ, unter macOS und Windows gibt es Installer. Die API ist in allen Fällen dieselbe.

Ein Modell ziehen

Modelle kommen aus der Ollama-Bibliothek. Für den ersten Test ist llama3.2:3b ein guter Kompromiss: 2,0 GB Download, 128K Kontextfenster laut Modellkarte, läuft notfalls auch auf CPU (dann langsam).

docker compose exec ollama ollama pull llama3.2:3b
docker compose exec ollama ollama list

Dasselbe geht über die API, was für Automatisierung praktischer ist:

curl -s http://localhost:11434/api/pull -d '{ "model": "llama3.2:3b", "stream": false }'
curl -s http://localhost:11434/api/tags

Das Minimalbeispiel: generate und chat

Ollama bietet zwei Endpunkte, die Sie kennen müssen. /api/generate nimmt einen einzelnen prompt und ist ideal für Klassifikation, Extraktion oder Zusammenfassungen ohne Gesprächsverlauf:

curl -s http://localhost:11434/api/generate -d '{
  "model": "llama3.2:3b",
  "prompt": "Fasse in einem Satz zusammen: Self-Hosting von LLMs.",
  "stream": false,
  "options": { "temperature": 0.2 }
}'

Die Antwort ist ein JSON-Objekt; der Text steht in response. Zusätzlich liefert Ollama Kennzahlen, alle Dauern in Nanosekunden: total_duration, load_duration, prompt_eval_count (Tokens im Prompt) und eval_count (erzeugte Tokens). Die Tokens pro Sekunde berechnen Sie als eval_count / eval_duration * 10^9. Das ist die einfachste Art, verschiedene Modelle auf Ihrer Hardware zu vergleichen.

/api/chat nimmt stattdessen ein messages-Array mit den Rollen system, user, assistant und tool. Den Gesprächsverlauf hält Ihre Anwendung; Ollama ist zustandslos und erwartet ihn bei jedem Aufruf komplett:

curl -s http://localhost:11434/api/chat -d '{
  "model": "llama3.2:3b",
  "messages": [
    { "role": "system", "content": "Du antwortest knapp und auf Deutsch." },
    { "role": "user", "content": "Nenne drei Vorteile von Self-Hosting." }
  ],
  "stream": false
}'

Hier steckt der Text in message.content. Das ist bereits das komplette Fundament: Ein weiteres {"role": "assistant", ...} plus die nächste Nutzerfrage an das Array angehängt, und Sie haben einen Chat.

Der Ablauf in der Übersicht:

   +--------------+   ollama pull llama3.2:3b   +-------------------+
   |  Bibliothek  | --------------------------> |  Volume           |
   |  ollama.com  |      Gewichte + Template    |  /root/.ollama    |
   +--------------+                             +---------+---------+
                                                          | laedt bei Bedarf
   +--------------+   POST /api/chat                      v
   |   Ihre App   | --------------------------> +-------------------+
   |  (curl, SDK, |                             |  ollama serve     |
   |   Backend)   | <-------------------------- |  Port 11434       |
   +--------------+   JSON: message.content     +-------------------+
                                                  entlaedt nach keep_alive (5m)

Drei typische Stolperfallen

1. Die API kennt keine Authentifizierung. Lokal ist für den Zugriff auf http://localhost:11434 kein Token nötig. Das ist bewusst so und der Grund, warum der Dienst nativ installiert nur an 127.0.0.1 lauscht. Das offizielle Container-Image setzt dagegen OLLAMA_HOST=0.0.0.0:11434, damit das Port-Mapping überhaupt funktioniert. Ihre einzige Grenze ist damit die linke Seite des Mappings. Schreiben Sie "11434:11434" statt "127.0.0.1:11434:11434", hängt Ihr Modell offen im Netz, und Docker publiziert an gängigen Host-Firewalls vorbei. Wer den Dienst wirklich exponieren muss, stellt einen Reverse Proxy mit Authentifizierung und TLS davor.

2. Streaming ist der Standard. Ohne "stream": false antworten /api/generate und /api/chat mit einer Folge von JSON-Objekten, eines pro Zeile, mit jeweils einem Textfragment. Wer diese Ausgabe naiv durch einen JSON-Parser schickt, bekommt einen Syntaxfehler oder nur das erste Token. Für Skripte und Batch-Jobs setzen Sie stream konsequent auf false; für eine Oberfläche mit Tipp-Effekt lassen Sie den Standard und lesen zeilenweise. Dasselbe gilt für /api/pull, das den Download-Fortschritt streamt.

3. Das Kontextfenster ist kleiner, als Sie denken. Ohne eigene Einstellung legt Ollama die Kontextlänge abhängig vom VRAM fest: unter 24 GiB 4K (4096 Token), bei 24 bis 48 GiB 32K, ab 48 GiB 256K. Auf Rechnern mit weniger als 24 GiB VRAM oder ganz ohne GPU arbeitet Ollama also mit 4096 Token, unabhängig davon, dass die Modellkarte 128K ausweist. Längere Prompts werden stillschweigend abgeschnitten, was sich als „das Modell ignoriert die Hälfte meines Dokuments" äußert. Setzen Sie OLLAMA_CONTEXT_LENGTH serverseitig (siehe compose.yaml oben) oder num_ctx in options pro Request. Rechnen Sie mit dem Preis: Der Speicherbedarf skaliert mit OLLAMA_NUM_PARALLEL mal Kontextlänge, ein großzügiges Fenster plus Parallelität sprengt schnell den verfügbaren VRAM.

Hermes und andere Modelle mit Tool-Calling

Sobald das Modell nicht nur Text liefern, sondern Funktionen Ihrer Anwendung aufrufen soll, kommt es auf Modelle an, die für Tool-Calling trainiert sind. Ein Beispiel ist die Hermes-Reihe von Nous Research: Open-Weight-Modelle, die Nous Research auf Basis bestehender Foundation-Modelle feinjustiert (Fine-Tuning, kein eigenes Pre-Training). Ihr Fokus liegt auf zuverlässigem Function- und Tool-Calling, stabiler JSON-Ausgabe und konsequenter Steuerung über den System-Prompt. Die neueste Generation ist Hermes 4 (14B auf Basis von Qwen 3, 70B und 405B auf Basis von Llama 3.1), ergänzt um Hermes 4.3 (36B auf Basis von ByteDance Seed-OSS-36B). Die Beispiele hier nutzen Hermes 3, das auf Meta Llama 3.1 aufsetzt und unter anderem als 8B, 70B und 405B verfügbar ist. Die Gewichte liegen im HuggingFace-Namespace NousResearch. Für Hermes 3 gilt die Llama 3.1 Community License: kommerzielle Nutzung erlaubt, aber mit Bedingungen (unter anderem eine Schwelle bei sehr großen Nutzerzahlen sowie Namens- und Attributionsvorgaben). Prüfen Sie die Llama-3.1-Lizenz vor dem produktiven Einsatz.

Zum Ausprobieren genügt Ollama. Verfügbare Tags variieren; prüfen Sie die Bibliothek vor dem Pull:

# Beispielhaft eine Hermes-Variante ziehen und starten
ollama run hermes3

# oder explizit eine Groesse
ollama run hermes3:8b

Für Produktionslast ist vLLM der Weg: hoher Durchsatz durch Continuous Batching und PagedAttention sowie eine OpenAI-kompatible API. Nach der Installation (pip install vllm) starten Sie den Server mit dem dedizierten Tool-Parser hermes und --enable-auto-tool-choice, damit vLLM die vom Modell erzeugten Tool-Aufrufe korrekt in das OpenAI-Format überführt:

vllm serve NousResearch/Hermes-3-Llama-3.1-8B \
  --enable-auto-tool-choice \
  --tool-call-parser hermes \
  --host 0.0.0.0 \
  --port 8000 \
  --max-model-len 8192

Der Server stellt danach unter http://localhost:8000/v1 die Endpunkte /chat/completions, /completions und /models bereit (vLLM-Dokumentation zu Tool Calling). Als grobe Größenordnung für den Speicher gilt in halber Präzision (FP16/BF16) rund zwei GB VRAM pro einer Milliarde Parameter plus Reserve für den KV-Cache; die 8B-Variante läuft auf einer einzelnen GPU.

Beim Tool-Calling übergeben Sie ein tools-Array. Fordert das Modell einen Aufruf an, liefert die Antwort tool_calls statt content. Ihre Anwendung führt die Funktion aus und gibt das Ergebnis als Nachricht mit role: "tool" zurück:

import json
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Liefert die aktuelle Temperatur fuer einen Ort.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "Stadtname"}
            },
            "required": ["city"],
        },
    },
}]

messages = [{"role": "user", "content": "Wie warm ist es gerade in Hamburg?"}]

first = client.chat.completions.create(
    model="NousResearch/Hermes-3-Llama-3.1-8B",
    messages=messages,
    tools=tools,
    tool_choice="auto",
)

msg = first.choices[0].message

if msg.tool_calls:
    call = msg.tool_calls[0]
    args = json.loads(call.function.arguments)

    # Funktion in Ihrer App ausfuehren (hier nur simuliert)
    result = {"city": args["city"], "temp_c": 18}

    messages.append(msg)  # Assistenten-Nachricht mit tool_calls
    messages.append({
        "role": "tool",
        "tool_call_id": call.id,
        "content": json.dumps(result),
    })

    final = client.chat.completions.create(
        model="NousResearch/Hermes-3-Llama-3.1-8B",
        messages=messages,
        tools=tools,
    )
    print(final.choices[0].message.content)

Das tool_calls-Objekt enthält eine id, den Funktionsnamen und die Argumente als JSON-String. Genau diese id muss in der role: "tool"-Antwort als tool_call_id referenziert werden, damit das Modell Aufruf und Ergebnis zuordnen kann. Verifizieren Sie die Schleife zuerst mit einer simulierten Funktion wie hier, bevor Sie echte Systeme anbinden, und validieren Sie strukturierte Ausgaben serverseitig per Schema, statt dem Modell blind zu vertrauen.

Wie es weitergeht

Damit steht ein lokaler LLM-Dienst mit persistenten Modellen und zwei belastbaren Endpunkten. Der naheliegende nächste Schritt ist POST /api/embed mit einem Embedding-Modell wie nomic-embed-text: Der Endpunkt nimmt model und input und liefert unter embeddings ein Array von Vektoren, einen pro Eingabe. Prüfen Sie die Länge des ersten Vektors (embeddings[0]), denn genau diese Zahl ist die Dimension, die Ihre Vektordatenbank braucht. Wie es von dort weitergeht, steht im Beitrag Qdrant self-hosten für RAG. Bestehende Anwendungen binden Sie oft ohne Umbau an: Ollama stellt zusätzlich eine OpenAI-kompatible Schicht unter http://localhost:11434/v1/ bereit, inklusive /v1/chat/completions.

Ein Hinweis zum Versions-Pinning: Zum Redaktionsschluss ist 0.32.6 der jüngste versionierte Tag des Standard-Images auf Docker Hub, während die GitHub-Releases bereits bei v0.32.9 stehen: Die Image-Tags laufen der Release-Liste einige Tage hinterher. Pinnen Sie trotzdem eine feste Version statt :latest, sonst ändert ein docker compose pull Ihr Setup unbemerkt. Weiter geht es im Ollama-Quickstart, in der API-Referenz und in der FAQ, die die Speicher- und Nebenläufigkeitsparameter im Detail erklärt.

Hinweis: Die Beiträge dieses Blogs werden unter Einsatz von KI erstellt und vor der Veröffentlichung redaktionell geprüft. Die redaktionelle Verantwortung trägt Emre Yurtbay (siehe Impressum).

Lassen Sie uns sprechen

Im kostenlosen Erstgespräch schildern Sie mir Ihre Situation. Ich gebe Ihnen eine erste Einschätzung, wie ich Sie unterstützen kann.

Kostenloses Erstgespräch anfragen