Einführung
In meinen vorherigen Artikeln Local LLM – KI-Sprachmodelle ohne Cloud und Lokale KI in der Praxis – Redmine-Ticketanalyse mit Ollama habe ich gezeigt, wie unkompliziert lokale KI heute ist. Einfach Modell ziehen, starten, nutzen – fertig.
Aber während ich diese Leichtigkeit durchaus genieße, bleibt ein Gedanke: Wie viel davon verstehe ich wirklich?
Denn die Komfortschicht von Ollama überdeckt eine komplexe Infrastruktur. Und genau da beginnt der spannende Teil: Wir steigen unter die Oberfläche.
Der Stack unter Ollama – was passiert da eigentlich?
Oft wird Ollama als „Runtime“ wahrgenommen. In Wahrheit ist es ein komfortabler Orchestrator, der auf mehreren anderen Projekten aufbaut – insbesondere auf llama.cpp.
Was Ollama wirklich übernimmt
- Scheduler & Ressourcenverwaltung
- Modell-Bundles und Registry
- Prompt-/Template-Handling
- Daemon + HTTP-API
- Backend-Auswahl (CUDA/Metal/ggml)
- Cache-Management
Was llama.cpp macht
llama.cpp ist bewusst minimalistisch:
- reine C/C++-Engine
- offene GGUF-Modelle
- keine Bundles, keine Registry
- vollständige Kontrolle über Quantisierung, Tokenizer, Build-Flags
Ollama erweitert, abstrahiert und verpackt – llama.cpp führt aus.
Warum der manuelle Weg wichtig ist
Wer KI in sensiblen oder produktiven Bereichen betreibt, braucht Transparenz:
- Welche Komponenten werden ausgeführt?
- Welche Compiler wurden genutzt?
- Welche quantisierte Variante habe ich wirklich geladen?
- Welche Abhängigkeiten existieren?
- Wie vertrauenswürdig ist die Supply Chain?
Schritt 1: llama.cpp selbst bauen
Um vollständige Transparenz über die Inferenz-Engine zu erhalten, bauen wir llama.cpp direkt aus dem Quellcode. Der Prozess besteht aus drei klar abgegrenzten Teilschritten:
1.1 Repository klonen
Wir holen den vollständigen, unveränderten Quellcode von GitHub:
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
Damit steht exakt die Version bereit, die auch auf GitHub veröffentlicht wurde – inklusive Commit-Hashes und Build-Skripten.
1.2 Abhängigkeiten installieren
Am Beispiel von Ubuntu lässt sich die für llama.cpp notwendige Build-Umgebung mit wenigen Paketen einrichten. Der Vorteil: Die gesamte Toolchain bleibt extrem schlank und transparent.
sudo apt update
sudo apt install -y \
build-essential \
cmake \
libcurl4-openssl-dev
Was steckt dahinter?
-
build-essential Installiert die grundlegende Compiler-Toolchain (gcc/g++, make).
-
cmake Wird von llama.cpp als Build-System verwendet.
-
libcurl4-openssl-dev Kleine, unkritische Systembibliothek – nötig für HTTP-Funktionalität einzelner llama.cpp-Tools.
Damit ist die Ubuntu-Umgebung bereits vollständig vorbereitet, um llama.cpp aus dem Quellcode zu kompilieren.
1.3 Build erzeugen
Wir erzeugen eine reproduzierbare Release-Build-Variante:
cmake -B build
cmake --build build --config Release
Optional: Binary global verfügbar machen:
export PATH=$PATH:$(pwd)/build/bin
Bei jedem Build sollte man dokumentieren:
- Commit-Hash
- CMake-Version
- Compiler-Version (gcc/clang)
- verwendete Flags
So entsteht eine vollständig überprüfbare und reproduzierbare Inferenzumgebung, die langfristig auditier- und dokumentierbar bleibt.
Schritt 2: Modelle ohne Ollama laden
Ollama nutzt eigene, komplexe Bundle-Formate. Für einen vollständig transparenten Stack laden wir stattdessen reine GGUF-Modelle – ohne Zusatzschichten, ohne versteckte Metadaten und ohne proprietäre Struktur.
Der Prozess besteht aus drei klaren Einzelschritten:
2.1 Download-Tool bauen
Wir verwenden ein kleines, schlankes CLI („hfdownloader“), das ausschließlich die tatsächlichen Artefakte von HuggingFace lädt – rekursiv, reproduzierbar und ohne Abhängigkeit auf Python-Ökosysteme.
git clone https://github.com/bodaay/HuggingFaceModelDownloader.git
cd HuggingFaceModelDownloader
# Binary bauen
make
# Binary systemweit verfügbar machen
cp output/hfdownloader_linux_amd64_2.0.0 ~/bin/hfdownloader
2.2 Zugriffs-Token setzen
Private oder große Modelle benötigen ein gültiges HuggingFace-Access-Token:
export HF_TOKEN=hf_xxxxxxxxx
2.3 GGUF-Modell herunterladen
Jetzt holen wir das Modell genau so, wie es auf HuggingFace liegt – ohne Umwandlung oder Zusatzdaten:
hfdownloader download Qwen/Qwen2.5-3B-Instruct-GGUF -o ./models
Die Ordnerstruktur entspricht exakt dem Repository. Wichtig: Hier wird nichts entpackt, zusammengeführt oder verändert.
Schritt 3: Eine eigene API – mit llama-server
Nachdem Modell und Engine bereitstehen, brauchen wir nur noch eine leichtgewichtige, lokale API, über die Anwendungen mit dem Modell kommunizieren können. Genau diese Lücke schließt llama-server.
llama-server ist die offizielle HTTP-Server-Komponente von llama.cpp und bietet:
- eine OpenAI-kompatible REST-API
- ohne proprietäre Layers oder Bundles
- direkt ausführbar als einzelne Binary
Damit lässt sich jedes GGUF-Modell sofort per Curl, Skript oder Client-Bibliothek ansprechen.
llama-server -m ./models/Qwen/Qwen2.5-3B-Instruct-GGUF/qwen2.5-3b-instruct-q5_k_m.gguf --host 0.0.0.0 --port 8080
Schritt 4: API testen
Sobald llama-server läuft, stellt er eine OpenAI-kompatible REST-API bereit.
Das bedeutet: vorhandene Tools, Skripte und Clients funktionieren ohne Anpassungen – nur der Host ändert sich.
Die wichtigsten Endpunkte für erste Tests sind:
4.1 Chat Completion (mehrere Nachrichten, Rollen)
Der Chat-Endpunkt bildet das klassische ChatGPT-Verhalten ab:
curl http://localhost:8080/v1/chat/completions \
-d '{
"model": "qwen2.5-3b",
"messages": [
{ "role": "user", "content": "Erkläre lokale LLMs." }
]
}'
4.2 Text Completion (einfacher Prompt → Antwort)
Für klassische Prompt-in/Text-out-Fälle:
curl http://localhost:8080/v1/completions \
-d '{
"model": "qwen2.5-3b",
"prompt": "Schreibe ein Gedicht."
}'
Dieser Endpunkt verhält sich wie das ursprüngliche GPT-3 API-Modell: Ein reiner Prompt ohne Rollen – ideal für kurze Texte, Code, Extraktionen und strukturierte Ausgaben.
llama-server direkt – oft ohne Änderungen.
Schritt 5: Bonus – die neue Web-GUI von llama-server
llama-server bringt eine leichtgewichtige UI gleich mit:
Features:
- browserbasierte Chat-Oberfläche
- mehrere Sessions, History, Parametersteuerung
- vollständig lokal
- Dokumentverarbeitung (PDF, TXT, MD, JSON)
Fazit
Wir haben den Ollama-Stack Schicht für Schicht geöffnet und einen vollständig transparenten lokalen LLM-Workflow aufgebaut:
- die Inferenz-Engine selbst kompiliert
- Modelle direkt und nachvollziehbar geladen
- Quantisierung bewusst kontrolliert
- eine eigene, minimalistische OpenAI-kompatible API bereitgestellt
- und mit der Web-UI einen lokalen Bedienkomfort ergänzt
Ergebnis: Statt einer abstrahierten Blackbox steht nun ein klarer, auditierbarer und reproduzierbarer KI-Stack, der sich in jeder Ebene verstehen und anpassen lässt.
Im nächsten Schritt möchte ich mich einmal in Ruhe mit den inneren Mechanismen eines Modells beschäftigen. Geplant ist ein Blick auf:
- die Erstellung eines eigenen Tokenizers
- die Definition einer kleinen, nachvollziehbaren Modellarchitektur
- erste Experimente zu Training & Feintuning
- die Konvertierung nach GGUF
- einfache Evaluations- und Testverfahren
Ziel ist kein vollwertiger Leitfaden, sondern ein verständlicher Mini-LLM-Stack als Lernprojekt, an dem sich die zentralen Bausteine eines Modells erkunden lassen.