Wer heute eine LLM-Anwendung baut, verliert schnell den Überblick: zehn Prompt-Varianten, drei Modelle, zwei Vektordatenbanken und am Ende weiß niemand mehr, welche Kombination den besten Output lieferte. Genau an dieser Stelle kommt MLflow ins Spiel. Die Open-Source-Plattform, bekannt aus klassischen ML-Projekten, hat mit Version 3 ein vollständiges Tracing- und Evaluations-System für LLM- und Agenten-Workflows bekommen. Dieser Artikel zeigt Schritt für Schritt, wie du MLflow 3.17.0 lokal und mit Docker einrichtest, GenAI-Traces aufzeichnest, Prompts versionierst und LLM-Ausgaben automatisiert bewertest.
Das Repository mlflow/mlflow zählte am 8. Oktober 2026 rund 28.300 Sterne auf GitHub, Tendenz steigend. Anders als viele reine LLM-Tools ist MLflow seit 2018 im produktiven Einsatz und bringt entsprechend ausgereifte Infrastruktur für Backend-Speicher, Modellregistrierung und Multi-User-Betrieb mit. Für Teams in Deutschland und der DACH-Region, die GenAI-Experimente nachvollziehbar und auditierbar dokumentieren müssen, ist das ein handfester Vorteil gegenüber vielen jüngeren Observability-Tools.
Dieser Artikel richtet sich an Entwicklerinnen und Entwickler, die bereits mit Python arbeiten und eine LLM-Anwendung, einen Agenten oder eine RAG-Pipeline betreiben, aber bislang keinen systematischen Überblick über Kosten, Latenz und Antwortqualität haben. Am Ende des Tutorials läuft ein vollständiges Beispielprojekt: ein Support-Bot, dessen Prompts versioniert, dessen Antworten automatisch getrackt und dessen Qualität per LLM-as-a-Judge bewertet werden. Alle Befehle sind gegen MLflow 3.17.0 getestet und funktionieren sowohl auf macOS, Linux als auch unter Windows mit WSL.
Was ist MLflow und warum lohnt sich das Setup 2026?
MLflow ist eine Open-Source-Plattform für den gesamten Lebenszyklus von Machine-Learning- und GenAI-Projekten. Ursprünglich von Databricks entwickelt, deckt MLflow heute vier Kernbereiche ab: Experiment-Tracking, Modellregistrierung, Projektverpackung und, seit MLflow 3, GenAI-Observability mit Tracing und Evaluation. Die aktuelle Version 3.17.0 wurde am 7. Oktober 2026 veröffentlicht und bringt laut den offiziellen Release-Notes schnellere Trace-Analysen, feingranulare Ressourcen-Berechtigungen und ein Feature namens “Jev Decisions” mit, das Entscheidungspfade innerhalb von Agenten nachvollziehbarer macht.
Der Unterschied zu reinen LLM-Observability-Tools liegt im Umfang. MLflow trennt nicht zwischen klassischem ML und GenAI, sondern führt beides in einem Tracking-Server zusammen. Ein Team, das heute ein RAG-System mit LangChain baut und morgen ein klassisches Klassifikationsmodell trainiert, braucht keine zwei getrennten Werkzeuge. Für Entwicklerinnen und Entwickler, die bereits mit LlamaIndex oder anderen RAG-Frameworks arbeiten, fügt sich MLflow als zentrale Tracking-Schicht darüber ein, ohne bestehenden Code grundlegend umzubauen. Die komplette Versionsgeschichte, inklusive aller Zwischenschritte von MLflow 2 zu MLflow 3, lässt sich direkt im GitHub-Release-Verzeichnis nachvollziehen.
Die Lizenz ist Apache License 2.0, also vollständig kostenlos und auch für kommerzielle Projekte ohne Einschränkungen nutzbar. Das unterscheidet MLflow von Tools mit “Open Core”-Modell, bei denen zentrale Funktionen hinter einer Bezahlschranke verschwinden. Wer MLflow selbst hostet, zahlt nur für die eigene Infrastruktur, nicht für Lizenzgebühren. Das macht die Plattform besonders für kleinere Teams und Startups attraktiv, die ein Budget für API-Aufrufe einplanen müssen, aber keine zusätzlichen Software-Lizenzkosten tragen wollen.
Ein weiterer Punkt, der MLflow von jüngeren Konkurrenten unterscheidet: Die Plattform wird nicht von einem einzelnen Start-up getrieben, sondern von einer breiten Community aus Databricks-Ingenieuren und externen Beitragenden weiterentwickelt. Das zeigt sich an der Release-Frequenz. Allein in den Wochen vor dem 7. Oktober 2026 erschienen mehrere Patch-Releases der 3.x-Reihe, jeweils mit kleineren Bugfixes und Verbesserungen an der GenAI-Auswertung. Für produktive Umgebungen bedeutet das: Wer heute startet, sollte eine konkrete Version fixieren und nicht automatisch auf jedes neue Release aktualisieren, ohne die Release-Notes gelesen zu haben.
Voraussetzungen: Diese Versionen brauchst du
Bevor es losgeht, sollte die Umgebung stimmen. Ein häufiger Fehler beim ersten Versuch ist, direkt mit dem vollständigen Docker-Compose-Setup zu starten, ohne zuvor die einfache lokale Installation getestet zu haben. Das erschwert die Fehlersuche unnötig, weil bei Problemen nicht klar ist, ob die Ursache in MLflow selbst, in der Datenbankverbindung oder in der Docker-Netzwerkkonfiguration liegt. Die folgende Tabelle fasst zusammen, was für ein reibungsloses Setup nötig ist, bevor im nächsten Abschnitt die eigentliche Installation beginnt.
| Komponente | Empfohlene Version / Angabe | Hinweis |
|---|---|---|
| Python | 3.10 oder neuer | Für MLflow 3.17.0 unterstützte, aktuelle Python-Version |
| MLflow | 3.17.0 | Veröffentlicht am 7. Oktober 2026 |
| Docker | Docker Desktop oder Docker Engine | Für Server, PostgreSQL und MinIO im Compose-Setup |
| RAM (lokal, nur Tracking) | mindestens 4 GB | 8 GB praxisnäher bei GenAI-Tracing mit UI und Datenbank |
| Freier Festplattenplatz | mindestens 2 GB | Für Artefakte, Traces und SQLite/Postgres-Datenbank |
| Betriebssystem | Linux, macOS oder Windows mit WSL | Docker-Unterstützung ist Voraussetzung für Compose-Setup |
| API-Zugang | Ein LLM-Provider-Key (z. B. OpenAI, Anthropic) | Nur nötig für die GenAI-Evaluations-Schritte |
Wichtig: MLflow selbst benötigt keine GPU. Die Rechenlast für GPU oder große RAM-Mengen entsteht erst, wenn du zusätzlich ein lokales LLM über Ollama oder vLLM betreibst. Für reine API-Aufrufe gegen Claude, GPT oder Gemini reicht ein normaler Laptop völlig aus.
Schritt 1: Python-Umgebung und MLflow installieren
Der einfachste Einstieg führt über pip, idealerweise in einer isolierten virtuellen Umgebung, damit sich Abhängigkeiten nicht mit anderen Projekten überschneiden.
python3 -m venv mlflow-env
source mlflow-env/bin/activate
python -m pip install --upgrade pip
python -m pip install mlflow
mlflow --version
Der letzte Befehl sollte 3.17.0 oder eine neuere Version ausgeben. Falls eine ältere Version installiert wird, liegt meist ein gecachtes Wheel im pip-Cache vor. Ein pip install --upgrade --no-cache-dir mlflow löst das Problem zuverlässig.
Schritt 2: Den lokalen Tracking-Server starten
Für den ersten Test reicht ein einzelner Befehl. MLflow startet dabei einen eigenen Webserver mit integrierter SQLite-Datenbank und lokalem Dateispeicher für Artefakte.
mlflow server \
--backend-store-uri sqlite:///$(pwd)/mlflow.db \
--default-artifact-root ./mlartifacts \
--host 127.0.0.1 \
--port 5000
Im Browser ist die Oberfläche anschließend unter http://127.0.0.1:5000 erreichbar. Wichtig: Diese Konfiguration eignet sich für lokale Experimente und Tests, nicht für dauerhaften Mehrbenutzerbetrieb. Für ein Team-Setup folgt im nächsten Abschnitt die produktionsnähere Docker-Variante.
Schritt 3: Produktionsnäheres Setup mit Docker Compose
Für ein Team, das MLflow dauerhaft betreiben will, braucht es einen persistenten Backend-Store (PostgreSQL) und einen S3-kompatiblen Artefaktspeicher (MinIO). MLflow liefert dafür ein fertiges Docker-Compose-Setup direkt im Repository mit.
git clone https://github.com/mlflow/mlflow.git
cd mlflow/docker-compose
cp .env.dev.example .env
docker compose up -d
Das Compose-Setup startet drei Container: PostgreSQL als Metadaten-Backend, MinIO als S3-kompatiblen Objektspeicher für Artefakte und den eigentlichen MLflow-Tracking-Server. Eine Einführung in die Grundkonzepte von Compose-Dateien, Services und Volumes liefert die offizielle Docker-Dokumentation, falls einzelne Begriffe aus der .env.dev.example-Datei unklar sind. Wer stattdessen nur einen einzelnen Container ohne Datenbankanbindung testen möchte, kann auf das offizielle Image zurückgreifen:
docker run --rm -p 5000:5000 ghcr.io/mlflow/mlflow:v3.17.0 \
mlflow server --host 0.0.0.0 --port 5000
Ein konkreter Image-Tag statt latest ist hier bewusst gewählt: Nur so bleibt die Umgebung über Monate reproduzierbar, wenn ein neues MLflow-Release andere Standardwerte mitbringt.
Schritt 4: Tracking-URI setzen und erste Verbindung testen
Damit ein Python-Skript weiß, wohin es Tracking-Daten senden soll, muss die Umgebungsvariable MLFLOW_TRACKING_URI gesetzt sein.
export MLFLOW_TRACKING_URI=http://127.0.0.1:5000
python -c "import mlflow; print(mlflow.get_tracking_uri())"
Gibt dieser Befehl die korrekte URL zurück, ist die Grundkonfiguration fertig. Läuft MLflow dagegen in einem Docker-Container und das Skript auf einem anderen Container, funktioniert 127.0.0.1 nicht, weil es sich dann auf den eigenen Container statt auf den MLflow-Host bezieht. In diesem Fall muss der Docker-Service-Name aus der Compose-Datei verwendet werden.
Schritt 5: Ein Experiment anlegen und klassisches Tracking testen
Bevor es an GenAI-spezifische Funktionen geht, lohnt sich ein kurzer Blick auf klassisches Tracking, weil es dieselbe Infrastruktur nutzt.
import mlflow
mlflow.set_experiment("llm-tutorial-shattered")
with mlflow.start_run(run_name="erster-test"):
mlflow.log_param("modell", "claude-sonnet-4-6")
mlflow.log_param("temperatur", 0.2)
mlflow.log_metric("antwortzeit_sekunden", 1.8)
mlflow.log_metric("tokens_gesamt", 342)
Nach dem Ausführen erscheint im MLflow-Dashboard ein neuer Run mit Parametern und Metriken. Das ist die Basis, auf der die GenAI-Funktionen aufbauen: Jeder Trace, jede Evaluation und jede Prompt-Version hängt letztlich an so einem Run.
Schritt 6: Automatisches Tracing für LLM-Aufrufe aktivieren
Der eigentliche Mehrwert für GenAI-Projekte liegt im Tracing. Ein Trace zeichnet die komplette Ausführung einer LLM- oder Agentenanfrage als Baum aus Spans auf: Prompt, Modellaufruf, Zwischenschritte, Tool-Calls und finale Antwort. MLflow unterstützt dafür Autologging für verbreitete Frameworks wie LangChain, OpenAI, Anthropic und LlamaIndex.
import mlflow
import anthropic
mlflow.anthropic.autolog()
client = anthropic.Anthropic()
with mlflow.start_run():
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=200,
messages=[{"role": "user", "content": "Erkläre MLflow Tracing in zwei Sätzen."}]
)
print(response.content[0].text)
Mit nur einer Zeile, mlflow.anthropic.autolog(), erfasst MLflow ab sofort jeden API-Aufruf automatisch: den vollständigen Prompt, die Antwort, Latenz und, sofern der Provider sie liefert, Token-Zahlen für Input und Output. Für OpenAI, LangChain oder LlamaIndex funktioniert das Prinzip identisch, nur der Modulname ändert sich, etwa mlflow.openai.autolog() oder mlflow.langchain.autolog().
Ein wichtiger Hinweis für den produktiven Einsatz: Tracing speichert vollständige Prompts und Antworten. Bei sensiblen Daten, etwa Kundendaten oder internen Dokumenten, sollte vor dem produktiven Rollout klar definiert sein, welche Felder maskiert oder gar nicht erst protokolliert werden.
Die folgende Tabelle zeigt, welche Autologging-Module MLflow mitbringt und was jeweils automatisch erfasst wird. Die vollständige, stets aktuelle Liste pflegt das Projekt in der GenAI-Dokumentation.
| Framework | Autolog-Befehl | Was erfasst wird |
|---|---|---|
| Anthropic | mlflow.anthropic.autolog() | Prompt, Antwort, Latenz, Token-Zahlen |
| OpenAI | mlflow.openai.autolog() | Chat- und Completion-Aufrufe inklusive Function-Calls |
| LangChain | mlflow.langchain.autolog() | Chain-Schritte, Retrieval-Aufrufe, Zwischenergebnisse |
| LlamaIndex | mlflow.llama_index.autolog() | Query-Engine-Aufrufe, Retrieval-Kontext, Antwortsynthese |
Für Frameworks ohne fertiges Autolog-Modul bietet MLflow zusätzlich eine manuelle Tracing-API über Decorators, mit der sich einzelne Funktionen gezielt als Span markieren lassen. Das lohnt sich etwa bei selbstgeschriebenen Agenten-Schleifen, die kein unterstütztes Framework nutzen.
Schritt 7: Traces im MLflow-Dashboard analysieren
Im Tab “Traces” der MLflow-Oberfläche erscheint nach jedem Aufruf ein neuer Eintrag mit Gesamtlaufzeit, Anzahl der Spans und Status. Ein Klick öffnet die hierarchische Ansicht: Jeder Span zeigt Eingabe, Ausgabe, Dauer und bei Agenten auch verschachtelte Tool-Aufrufe. Das ist besonders hilfreich, wenn ein Agent mehrere Schritte durchläuft, zum Beispiel eine Datenbankabfrage, einen Retrieval-Schritt und erst danach die finale Textgenerierung.
Bei langsamen Antworten lässt sich so schnell erkennen, welcher Teilschritt die Latenz verursacht, etwa ein langsamer Vektordatenbank-Lookup statt des eigentlichen Modellaufrufs. Wer bereits mit Observability-Tools für LLMs wie Langfuse gearbeitet hat, wird das Grundprinzip wiedererkennen, MLflow bettet es aber direkt in die bestehende Experiment-Infrastruktur ein.
Ein weiterer nützlicher Blick im Dashboard betrifft Fehler-Traces. Schlägt ein API-Aufruf fehl, etwa wegen eines abgelaufenen Keys oder einer Rate-Limit-Meldung des Providers, markiert MLflow den betroffenen Span als fehlerhaft und zeigt die zugehörige Fehlermeldung direkt in der Trace-Ansicht an. Für die Fehlersuche im Team ist das deutlich schneller als das Durchsuchen verteilter Anwendungslogs, weil Fehler und der auslösende Prompt an derselben Stelle sichtbar sind.
Schritt 8: Prompts versionieren mit der Prompt Registry
MLflow bringt eine eigene Prompt Registry mit, über die Prompts als eigenständige, versionierte Objekte verwaltet werden, statt als hartcodierte Strings im Python-Code zu verschwinden.
import mlflow
prompt = mlflow.genai.register_prompt(
name="kundensupport-antwort",
template="Beantworte die folgende Kundenanfrage freundlich und präzise: {{frage}}",
commit_message="Erste Version des Support-Prompts"
)
print(prompt.uri)
Jede Änderung am Prompt-Text erzeugt eine neue Version mit eigener Commit-Nachricht, vergleichbar mit Git für Code. Über die Weboberfläche lassen sich verschiedene Versionen nebeneinander anzeigen, was besonders bei iterativer Prompt-Optimierung Zeit spart: Statt in Slack-Nachrichten nachzuschauen, welche Formulierung letzte Woche besser funktionierte, liegt die komplette Historie an einem Ort.
Schritt 9: Automatisierte Evaluation mit LLM-as-a-Judge
Der vielleicht wichtigste GenAI-Baustein ist mlflow.genai.evaluate(). Damit lässt sich eine Modell- oder Prompt-Variante gegen einen Testdatensatz laufen lassen, wobei die Bewertung automatisiert über sogenannte Scorer erfolgt.
import mlflow
from mlflow.genai.scorers import Correctness, Guidelines, Safety
eval_data = [
{"inputs": {"frage": "Wie starte ich den MLflow-Server?"},
"outputs": "Nutze den Befehl mlflow server mit Backend-Store-URI."},
{"inputs": {"frage": "Was kostet MLflow?"},
"outputs": "MLflow ist unter Apache 2.0 kostenlos nutzbar."},
]
results = mlflow.genai.evaluate(
data=eval_data,
scorers=[Correctness(), Guidelines(guidelines="Antworte auf Deutsch"), Safety()]
)
print(results.metrics)
MLflow unterscheidet zwischen klassischen, deterministischen Scorern (zum Beispiel exakte Übereinstimmung oder Regex-Prüfung) und LLM-as-a-Judge-Scorern, bei denen ein zweites Modell die Antwort anhand von Kriterien wie Correctness, Relevance, Safety oder Groundedness bewertet. Wichtig für die Praxis: Ein LLM-as-a-Judge-Scorer ist selbst nur ein Modellaufruf und damit kein objektiver Maßstab. Er hängt von Modellwahl, Bewertungsprompt und Sprache ab. Für belastbare Aussagen empfiehlt sich eine Kombination aus automatisierten Scorern und stichprobenhafter menschlicher Prüfung.
Neben den eingebauten Scorern lassen sich auch eigene Python-Funktionen als Scorer registrieren. Das eignet sich für Prüfungen, die kein generisches LLM-Kriterium abdeckt, etwa ob eine Antwort eine bestimmte Produktnummer enthält oder eine maximale Zeichenlänge einhält. Ein eigener Scorer ist dabei nichts anderes als eine Funktion, die Eingabe und Ausgabe entgegennimmt und eine Zahl oder einen Wahrheitswert zurückgibt. Dieser deterministische Anteil der Evaluation läuft deutlich schneller und verursacht keine zusätzlichen API-Kosten, weil kein zweites Modell aufgerufen wird.
Schritt 10: Mehrere Prompt-Varianten im Vergleich evaluieren
Ein typischer Anwendungsfall: Zwei Prompt-Formulierungen sollen gegeneinander getestet werden, um zu entscheiden, welche produktiv geschaltet wird.
varianten = {
"foermlich": "Sie werden gebeten, folgende Frage zu beantworten: {{frage}}",
"locker": "Hey, kannst du kurz folgende Frage beantworten? {{frage}}",
}
for name, template in varianten.items():
with mlflow.start_run(run_name=f"prompt-{name}"):
mlflow.log_param("prompt_variante", name)
ergebnis = mlflow.genai.evaluate(
data=eval_data,
scorers=[Correctness(), Guidelines(guidelines="Höflicher Ton")]
)
mlflow.log_metrics(ergebnis.metrics)
Im Dashboard lassen sich die Runs anschließend per Checkbox markieren und über die Vergleichsansicht gegenüberstellen. So wird aus einer gefühlten Einschätzung (“der lockere Ton wirkt besser”) eine Zahl, die sich dokumentieren und später reproduzieren lässt.
Schritt 11: Modelle und Anwendungen mit LoggedModel verknüpfen
MLflow 3 führt das Konzept der LoggedModel-Entität ein, das Anwendungsversionen, Code, Konfiguration, Traces und Evaluation-Runs an einem zentralen Punkt zusammenführt. Das löst ein Problem, das in älteren MLflow-Versionen und in vielen Konkurrenz-Tools bestand: Traces, Metriken und Modellversionen lagen oft getrennt vor.
import mlflow
logged_model = mlflow.pyfunc.log_model(
name="support-agent-v2",
python_model="agent_wrapper.py",
registered_model_name="kundensupport-agent"
)
mlflow.set_active_model(logged_model.model_id)
Sobald ein Modell als aktiv markiert ist, verknüpft MLflow automatisch alle nachfolgenden Traces und Evaluation-Ergebnisse mit genau dieser Modellversion. Beim Rollback auf eine ältere Version lässt sich so sofort nachvollziehen, welche Traces und Metriken zu welcher Codeversion gehörten. Gerade bei Agenten-Projekten mit mehreren beteiligten Entwicklern verhindert das eine häufige Fehlerquelle: Ohne diese Verknüpfung lässt sich im Nachhinein kaum rekonstruieren, ob ein schlechter Trace von der aktuellen oder einer bereits abgelösten Codeversion stammt. Mit set_active_model() ist diese Zuordnung dagegen von Anfang an eindeutig dokumentiert, ganz ohne manuelles Nachtragen in einer separaten Tabelle oder einem Wiki.
Schritt 12: Zugriffsrechte und Teambetrieb konfigurieren
Mit MLflow 3.17.0 kamen feingranulare Resource Permissions hinzu, mit denen sich der Zugriff auf einzelne Experimente, Modelle oder Prompt-Registrierungen einschränken lässt. Für Teams, die mehrere Projekte auf einem gemeinsamen Server betreiben, ist das ein wichtiger Baustein, um versehentliches Überschreiben fremder Experimente zu verhindern.
In der Praxis bedeutet das: Ein Admin-Account verwaltet den Server, einzelne Teams erhalten Lese- oder Schreibrechte nur für ihre eigenen Experiment-Namespaces. Für Unternehmen mit Compliance-Anforderungen, etwa im Rahmen von NIS2 oder internen Audit-Vorgaben, lässt sich damit nachvollziehbar dokumentieren, wer wann auf welche LLM-Experimentdaten zugegriffen hat.
Schritt 13: MLflow-Evaluation in die CI/CD-Pipeline einbinden
Der letzte Setup-Schritt macht aus manueller Qualitätskontrolle einen automatisierten Gate-Check. Statt die Evaluation nur lokal auszuführen, lässt sich dasselbe Python-Skript aus Schritt 10 in eine CI-Pipeline einbetten, zum Beispiel als GitHub-Actions-Job, der vor jedem Merge in den Hauptzweig läuft.
# ci_quality_gate.py
import sys
import mlflow
from mlflow.genai.scorers import Correctness
mlflow.set_tracking_uri("http://mlflow-server:5000")
ergebnis = mlflow.genai.evaluate(data=eval_data, scorers=[Correctness()])
score = ergebnis.metrics.get("correctness/mean", 0)
if score < 0.85:
print(f"Qualitätsgate fehlgeschlagen: Correctness-Score {score}")
sys.exit(1)
print(f"Qualitätsgate bestanden: Correctness-Score {score}")
Schlägt der Score-Schwellenwert fehl, bricht die Pipeline mit Exit-Code 1 ab und verhindert das Deployment einer schlechteren Prompt- oder Modellversion. Dieser Ansatz verhindert eine häufige Falle bei LLM-Projekten: dass eine neue Prompt-Formulierung zwar in zwei, drei Testfällen gut aussieht, in der Breite aber schlechter performt als die bisherige Version.
Die MLflow-Oberfläche im Überblick: Diese Tabs solltest du kennen
Nach dem ersten Start wirkt die MLflow-Oberfläche auf den ersten Blick dicht, weil sie sowohl klassische ML- als auch GenAI-Funktionen in derselben Navigation vereint. Für den Einstieg reicht es, vier Bereiche zu kennen.
- Experiments: Die Übersicht aller angelegten Experimente und ihrer Runs, mit Filterfunktion nach Parametern und Metriken. Hier starten die meisten Analysen.
- Traces: Die chronologische Liste aller aufgezeichneten LLM- und Agenten-Aufrufe, durchsuchbar nach Status, Dauer und Modell. Ein Klick öffnet die Span-Hierarchie aus Schritt 7.
- Models: Die Modellregistrierung mit allen über
log_model()gespeicherten Versionen, inklusive Verlinkung zu den zugehörigen Traces und Evaluation-Runs. - Prompts: Die Prompt Registry aus Schritt 8, in der sich alle Versionen eines Prompt-Templates nebeneinander vergleichen lassen.
Ein praktischer Startpunkt für den Alltag: Wer eine Qualitätsregression vermutet, beginnt meist im Tab Experiments mit einem Vergleich der letzten Runs nach dem Correctness-Score, springt bei Auffälligkeiten in die zugehörigen Traces und prüft dort, ob sich die Eingabedaten, der verwendete Prompt oder das Modell selbst verändert haben. Dieser Dreischritt deckt in der Praxis die meisten Qualitätsprobleme ab, ohne dass manuell durch Logdateien gesucht werden muss.
Die Suchfunktion innerhalb jedes Tabs unterstützt eine einfache Abfragesprache, mit der sich zum Beispiel gezielt nach Runs mit einem bestimmten Parameterwert oder nach Traces oberhalb einer Latenzschwelle filtern lässt. Das ersetzt in vielen Fällen den Umweg über ein separates Analyse-Notebook, zumindest für die alltägliche Fehlersuche. Für tiefere statistische Auswertungen über viele hundert Runs hinweg lässt sich die MLflow-Tracking-API aber weiterhin direkt aus Python oder einem BI-Tool heraus abfragen.
Häufige Stolperfallen beim MLflow-Setup
Beim Einrichten von MLflow tauchen immer wieder dieselben Probleme auf, unabhängig davon, ob der Server lokal, per Docker oder auf einer gemieteten VM läuft. Die meisten dieser Fehler lassen sich in drei Gruppen einteilen: falsch konfigurierte Pfade und URIs, fehlende Zugangsdaten für externe Dienste wie LLM-APIs oder S3-Speicher, und Versionskonflikte zwischen Client und Server. Die folgende Übersicht zeigt die häufigsten Fehlerquellen und wie sie sich vermeiden lassen.
- Relative SQLite-Pfade: Wird
sqlite:///mlflow.dbstatt eines absoluten Pfads verwendet, entstehen je nach Arbeitsverzeichnis mehrere getrennte Datenbanken. Immer$(pwd)oder einen absoluten Pfad nutzen. - Fehlende Schreibrechte: Läuft der Server in einem Docker-Container als eingeschränkter Benutzer, scheitert das Anlegen der SQLite-Datei oder des Artefaktordners oft an Dateirechten.
- Veraltete API-Aufrufe: Ältere Tutorials nutzen noch
mlflow.evaluate()für GenAI-Fälle. Seit MLflow 3 istmlflow.genai.evaluate()der richtige Einstiegspunkt für LLM-Bewertungen. - Vergessene Tracking-URI: Ohne gesetztes
MLFLOW_TRACKING_URIschreibt MLflow standardmäßig in einen lokalenmlruns-Ordner, nicht auf den gestarteten Server. - localhost in Containern: Innerhalb eines Docker-Netzwerks verweist
localhostauf den eigenen Container, nicht auf den MLflow- oder MinIO-Container. Stattdessen die Service-Namen aus der Compose-Datei verwenden. - Fehlende API-Keys für Autologging:
mlflow.anthropic.autolog()protokolliert nur Aufrufe, die tatsächlich erfolgreich durchgeführt wurden. Ohne gültigen API-Key entstehen keine Traces, aber auch keine aussagekräftige Fehlermeldung von MLflow selbst. - Zu viele parallele Scorer: Jeder LLM-as-a-Judge-Scorer verursacht einen zusätzlichen API-Aufruf pro Testfall. Bei großen Testdatensätzen und mehreren Scorern können Kosten und Laufzeit schnell steigen.
Beispiel-Output: So sieht ein ausgewerteter Run aus
Nach dem Ausführen von mlflow.genai.evaluate() liefert MLflow ein Metrik-Objekt zurück, das sich direkt ausgeben lässt.
{
"correctness/mean": 0.91,
"guidelines/mean": 1.0,
"safety/mean": 1.0,
"latency_ms/mean": 842,
"total_token_count/mean": 187
}
Im Dashboard erscheinen dieselben Werte zusätzlich pro Einzelfall, inklusive der jeweiligen Begründung des Judge-Modells. Das erlaubt es, gezielt die schlechtesten Einzelfälle herauszufiltern, statt nur auf den Durchschnittswert zu schauen, der einzelne Ausreißer leicht verdeckt.
Troubleshooting: Die wichtigsten Fehlermeldungen und Lösungen
| Fehler / Symptom | Ursache | Lösung |
|---|---|---|
| Address already in use | Port 5000 ist bereits belegt, oft von einem früheren MLflow-Prozess | Anderen Port mit --port 5001 starten oder blockierenden Prozess beenden |
| sqlite3.OperationalError: unable to open database file | Relativer Pfad oder fehlende Schreibrechte im Zielverzeichnis | Absoluten Pfad verwenden und Verzeichnisrechte prüfen |
| Connection refused beim Client | MLFLOW_TRACKING_URI zeigt auf falschen Host oder Server läuft nicht | URI prüfen, Server-Logs auf Startfehler kontrollieren |
| Traces erscheinen nicht im Dashboard | Autolog-Funktion wurde nicht vor dem API-Aufruf aktiviert | mlflow.<provider>.autolog() vor dem ersten Aufruf platzieren |
| S3-Zugriff verweigert (MinIO) | Falscher Endpoint, fehlende Access-Keys oder falsche Bucket-Rechte | Umgebungsvariablen MLFLOW_S3_ENDPOINT_URL, AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY prüfen |
| AttributeError: module mlflow.genai has no attribute evaluate | Veraltete MLflow-Version ohne GenAI-Modul installiert | Mit pip install --upgrade mlflow auf Version 3.x aktualisieren |
| Docker-Container startet, UI bleibt leer | Falsches Backend-Store- oder Artefakt-Volume gemountet | Volumes in der docker-compose.yml auf persistente Pfade prüfen |
| Evaluation extrem langsam | Zu viele LLM-as-a-Judge-Scorer bei großem Testdatensatz | Scorer-Anzahl reduzieren oder Testdatensatz für erste Durchläufe verkleinern |
| Prompt Registry zeigt alte Version an | Client-Cache oder falsche Prompt-URI mit fixierter Versionsnummer | Aktuelle Versions-URI aus der Registry-Oberfläche kopieren |
Fortgeschrittene Tipps für den produktiven Einsatz
Sobald das Grundsetup läuft, lohnen sich einige Anpassungen, die den Unterschied zwischen einem Testaufbau und einem belastbaren Produktionssystem ausmachen.
- PostgreSQL statt SQLite ab dem zweiten Nutzer: SQLite verträgt keine parallelen Schreibzugriffe mehrerer Prozesse zuverlässig. Sobald mehr als eine Person oder ein CI-Job gleichzeitig schreibt, ist PostgreSQL die sicherere Wahl.
- Trace-Sampling bei hohem Volumen: Wer tausende Anfragen pro Tag protokolliert, sollte nicht jeden einzelnen Trace dauerhaft speichern. Eine Stichprobe, etwa jeder zehnte Request, reicht oft für aussagekräftige Analysen.
- Sensible Felder maskieren: Vor dem produktiven Rollout festlegen, welche Eingabefelder (E-Mail-Adressen, Kundennummern) vor dem Logging anonymisiert werden.
- Evaluation in die CI-Pipeline einbauen: Ein einfacher Schwellenwert, etwa "Correctness-Score darf nicht unter 0,85 fallen", lässt sich als automatisierter Check vor jedem Deployment einbauen.
- Kosten der Judge-Modelle im Blick behalten: Für große Testläufe lohnt sich ein günstigeres, aber ausreichend genaues Modell als Judge, statt für jede einzelne Bewertung das teuerste verfügbare Modell zu nutzen.
- Backups des Backend-Stores einplanen: Die PostgreSQL-Datenbank enthält die komplette Experiment-Historie. Ein tägliches Backup verhindert Datenverlust bei einem Server-Ausfall.
- Experiment-Namespaces konsequent trennen: Statt alle Projekte in ein einziges Experiment zu schreiben, lohnt sich eine klare Namenskonvention wie "team-produkt-umgebung", damit die Übersicht auch nach hundert Runs erhalten bleibt.
- Trace-Export für externe Analysen nutzen: MLflow erlaubt den Export von Traces in gängige Formate, was sich eignet, wenn zusätzlich ein spezialisiertes BI-Tool oder Data-Warehouse für Langzeitauswertungen zum Einsatz kommt.
Keiner dieser Punkte ist für den ersten Testlauf zwingend. Sie werden aber relevant, sobald ein Prototyp den Sprung in die Produktion schafft und mehr als eine Person regelmäßig mit dem Tracking-Server arbeitet. Wer früh eine klare Namenskonvention und ein Backup-Konzept etabliert, erspart sich später eine aufwendige Migration bestehender Experimentdaten.
Kosten realistisch einschätzen: Was MLflow im Betrieb kostet
MLflow selbst verursacht keine Lizenzkosten, aber drei andere Kostenblöcke sollten vor dem produktiven Einsatz eingeplant werden: die Serverinfrastruktur, der Artefaktspeicher und die API-Aufrufe an den jeweiligen LLM-Provider. Die folgende Tabelle gibt eine grobe Orientierung für unterschiedliche Betriebsgrößen.
| Betriebsgröße | Infrastruktur | Zusätzliche Kosten |
|---|---|---|
| Einzelperson, lokaler Test | Laptop, SQLite, lokaler Dateispeicher | Nur API-Kosten des LLM-Providers |
| Kleines Team, gemeinsamer Server | Ein VM-Server mit Docker Compose, PostgreSQL, MinIO | Hosting-Kosten des VM-Anbieters plus API-Kosten |
| Produktion mit hohem Trace-Volumen | Managed PostgreSQL, S3-Objektspeicher, mehrere MLflow-Instanzen | Datenbank- und Objektspeicher-Kosten, API-Kosten, ggf. Lastverteilung |
| Lokales LLM statt API | GPU-Server mit mindestens 24 GB VRAM oder Apple-Silicon-Mac mit 64 GB RAM | Hardware- oder GPU-Mietkosten statt Token-Gebühren |
Der größte variable Kostenfaktor ist in der Praxis selten MLflow selbst, sondern die Anzahl der LLM-as-a-Judge-Aufrufe während der Evaluation. Jeder zusätzliche Scorer multipliziert die Anzahl der API-Calls mit der Größe des Testdatensatzes. Ein Testlauf mit 500 Testfällen und drei Judge-Scorern erzeugt entsprechend 1.500 zusätzliche Modellaufrufe, zusätzlich zu den eigentlichen Anwendungsaufrufen. Für regelmäßige CI-Checks empfiehlt sich deshalb ein kleinerer, aber repräsentativer Testdatensatz statt eines riesigen Datensatzes bei jedem einzelnen Commit.
Ein praktischer Mittelweg, der sich in vielen Teams etabliert hat: Der vollständige Testdatensatz läuft einmal täglich oder wöchentlich als Übersichtsprüfung, während bei jedem einzelnen Pull-Request nur eine kleinere, aber trotzdem repräsentative Stichprobe von 20 bis 30 Testfällen geprüft wird. So bleiben die CI-Laufzeiten kurz, ohne dass größere Qualitätsregressionen über längere Zeit unentdeckt bleiben.
Komplettes Projekt: MLflow-Setup für ein Support-Bot-Evaluationssystem
Zum Abschluss ein vollständiges, lauffähiges Beispiel, das alle vorherigen Schritte zusammenführt: ein kleiner Support-Bot, der automatisch getrackt und bewertet wird.
# datei: support_bot_eval.py
import mlflow
import anthropic
from mlflow.genai.scorers import Correctness, Guidelines
mlflow.set_tracking_uri("http://127.0.0.1:5000")
mlflow.set_experiment("support-bot-produktion")
mlflow.anthropic.autolog()
client = anthropic.Anthropic()
prompt = mlflow.genai.register_prompt(
name="support-bot-prompt",
template="Du bist ein freundlicher Support-Mitarbeiter. Beantworte: {{frage}}",
commit_message="Produktionsversion 1.0"
)
testfragen = [
{"inputs": {"frage": "Wie setze ich mein Passwort zurück?"},
"outputs": "Klicke auf 'Passwort vergessen' und folge den Anweisungen in der E-Mail."},
{"inputs": {"frage": "Wo finde ich meine Rechnung?"},
"outputs": "Rechnungen findest du unter 'Konto' > 'Abrechnung' im Kundenportal."},
]
with mlflow.start_run(run_name="support-bot-v1-live"):
mlflow.log_param("prompt_version", prompt.version)
ergebnis = mlflow.genai.evaluate(
data=testfragen,
scorers=[Correctness(), Guidelines(guidelines="Freundlicher, klarer Ton auf Deutsch")]
)
mlflow.log_metrics(ergebnis.metrics)
print("Evaluation abgeschlossen:", ergebnis.metrics)
Dieses Skript erledigt in einem Durchlauf: Verbindung zum Tracking-Server, automatisches Tracing aller Anthropic-Aufrufe, Registrierung einer versionierten Prompt-Vorlage und eine automatisierte Bewertung über zwei Scorer. Das Ergebnis lässt sich direkt im MLflow-Dashboard unter dem Experiment "support-bot-produktion" einsehen, inklusive aller Traces, Metriken und der verwendeten Prompt-Version.
Für ein echtes Produktionsprojekt lässt sich dieses Grundgerüst in drei Richtungen erweitern. Erstens: Statt zwei Testfragen sollte ein realistischer Datensatz mit mindestens 50 bis 100 echten, anonymisierten Kundenanfragen verwendet werden, damit die Evaluation repräsentativ ist. Zweitens: Der Correctness- und Guidelines-Scorer lassen sich um einen eigenen, projektspezifischen Scorer ergänzen, der zum Beispiel prüft, ob die Antwort einen Link zur richtigen Hilfe-Seite enthält. Drittens: Das Skript aus Schritt 13 lässt sich direkt in dasselbe Repository einbauen, sodass jede Änderung am Support-Bot-Prompt automatisch gegen den Testdatensatz geprüft wird, bevor sie live geht.
MLflow im Vergleich zu anderen LLM-Observability-Ansätzen
MLflow ist nicht das einzige Werkzeug für GenAI-Tracking. Der zentrale Unterschied liegt in der Herkunft: Während viele jüngere Tools von Grund auf für LLM-Workflows entstanden sind, bringt MLflow seine Stärken aus über sieben Jahren klassischem ML-Lifecycle-Management mit. Das zeigt sich vor allem bei Modellregistrierung, Governance und der Fähigkeit, klassische ML-Modelle und GenAI-Anwendungen in derselben Infrastruktur zu verwalten.
Teams, die bereits Fine-Tuning-Workflows mit klassischen ML-Metriken betreiben, profitieren besonders davon, weil sich Trainingsmetriken und spätere GenAI-Evaluationsergebnisse im selben Tool vergleichen lassen. Reine LLM-Tracing-Tools glänzen dagegen oft mit schnellerer Einrichtung für den Einzelfall, bieten aber selten die gleiche Tiefe bei Modellregistrierung und Multi-User-Rechteverwaltung.
Für die Auswahl des richtigen Judge-Modells bei der Evaluation lohnt sich zudem ein Blick auf aktuelle LLM-Benchmark-Methoden, da die Qualität der automatisierten Bewertung direkt von der Zuverlässigkeit des eingesetzten Judge-Modells abhängt. Wer zusätzlich gezielt nach Schwachstellen in Prompts und Sicherheitsrisiken suchen will, findet in einem Setup mit Promptfoo ein ergänzendes Werkzeug, das sich parallel zu MLflow betreiben lässt, ohne sich gegenseitig zu stören.
Ein praktischer Unterschied zeigt sich auch bei der Lernkurve. Teams mit MLOps-Hintergrund, die bereits klassische ML-Pipelines mit MLflow betreiben, benötigen für den GenAI-Einstieg kaum zusätzliche Einarbeitungszeit, weil Konzepte wie Experimente, Runs und Metriken bereits vertraut sind. Teams, die komplett neu einsteigen, sollten dagegen etwas mehr Zeit für die ersten Schritte einplanen, da MLflow mehr Konfigurationsmöglichkeiten bietet als schlankere Spezial-Tools. Diese zusätzliche Komplexität zahlt sich allerdings aus, sobald ein Projekt über den Prototyp-Status hinauswächst und mehrere Modelle, Prompt-Versionen und Teams parallel verwaltet werden müssen.
Datenschutz und Compliance beim Einsatz in Deutschland
Wer MLflow in Deutschland oder der EU produktiv einsetzt, sollte den Speicherort von Tracking-Daten bewusst wählen. Da MLflow Prompts und Antworten vollständig protokolliert, können je nach Anwendungsfall personenbezogene Daten im Sinne der DSGVO entstehen, etwa wenn Kundenanfragen im Klartext erfasst werden.
Praktisch bedeutet das: Der Tracking-Server und der Artefaktspeicher sollten auf Servern innerhalb der EU liegen, wenn personenbezogene Daten verarbeitet werden. Zusätzlich empfiehlt sich eine klare interne Richtlinie, wie lange Traces aufbewahrt werden und wer Zugriff auf die Rohdaten hat. Die in Schritt 12 beschriebenen Resource Permissions von MLflow 3.17.0 helfen dabei, den Zugriffskreis technisch einzuschränken, ersetzen aber keine schriftliche Datenschutz-Dokumentation.
Ein weiterer Punkt betrifft die LLM-Provider selbst. Wird ein API-basiertes Modell wie Claude oder GPT verwendet, verlassen Prompts und Kontextdaten ohnehin das eigene Rechenzentrum, unabhängig vom MLflow-Setup. Wer besonders sensible Daten verarbeitet, etwa Gesundheits- oder Finanzdaten, sollte parallel prüfen, ob der jeweilige Modell-Provider eine EU-Region anbietet und eine passende Auftragsverarbeitungsvereinbarung abschließt. MLflow kann an dieser Stelle nur die eigene Tracking-Infrastruktur absichern, nicht die Datenverarbeitung beim externen Modell-Anbieter.
Der Grundsatz der Datenminimierung aus Artikel 5 der DSGVO lässt sich direkt auf das Tracing-Setup übertragen: Es sollten nur die Felder protokolliert werden, die für Debugging und Qualitätskontrolle tatsächlich notwendig sind. Ein vollständiger Mitschnitt jeder Kundeninteraktion "auf Verdacht", ohne klaren Zweck und ohne Löschkonzept, widerspricht diesem Grundsatz und sollte vermieden werden, selbst wenn MLflow technisch keine Obergrenze für die Trace-Menge vorgibt.
Mehr zum generellen Umgang mit sensiblen Daten in KI-Chatbot-Workflows, inklusive konkreter Maskierungsstrategien, findet sich im Überblick zu KI- und Machine-Learning-Themen auf shattered.io.
Häufig gestellte Fragen zu MLflow für LLM-Tracking
Ist MLflow für LLM-Projekte komplett kostenlos?
Ja, der MLflow-Kern steht unter Apache License 2.0 und ist kostenlos, auch für kommerzielle Projekte. Kosten entstehen nur für die eigene Serverinfrastruktur und für API-Aufrufe an LLM-Provider wie Anthropic oder OpenAI. Eine separate Enterprise- oder Cloud-Variante mit zusätzlichen Funktionen existiert zwar, ist für die in diesem Artikel beschriebenen Schritte aber nicht erforderlich.
Brauche ich eine GPU, um MLflow zu betreiben?
Nein. MLflow selbst läuft auf CPU-Basis. Eine GPU wird nur benötigt, wenn zusätzlich ein lokales LLM über Ollama oder vLLM betrieben wird, nicht für MLflow selbst.
Welche LLM-Provider unterstützt das Autologging?
MLflow bietet Autologging-Integrationen unter anderem für LangChain, OpenAI, Anthropic und LlamaIndex, zusätzlich eine allgemeine Tracing-API für weitere Frameworks.
Was ist der Unterschied zwischen mlflow.evaluate() und mlflow.genai.evaluate()?
mlflow.evaluate() stammt aus dem klassischen ML-Bereich und eignet sich für Regressions- oder Klassifikationsmodelle. mlflow.genai.evaluate() ist die seit MLflow 3 eingeführte Funktion speziell für LLM- und Agenten-Evaluation mit LLM-as-a-Judge-Scorern.
Kann ich MLflow mit mehreren Teams gleichzeitig nutzen?
Ja. Seit Version 3.17.0 unterstützt MLflow feingranulare Resource Permissions, mit denen sich Lese- und Schreibrechte für einzelne Experimente, Modelle und Prompts einschränken lassen.
Wie zuverlässig sind LLM-as-a-Judge-Bewertungen?
Sie sind ein nützliches, aber kein objektives Werkzeug. Da der Judge selbst ein Modellaufruf ist, hängt die Bewertung von Modellwahl, Bewertungsprompt und Sprache ab. Eine Kombination mit deterministischen Scorern und stichprobenhafter menschlicher Prüfung liefert belastbarere Ergebnisse. In der Praxis hat es sich bewährt, bei neuen Scorer-Definitionen die ersten Durchläufe manuell gegen eine kleine, von Menschen bewertete Stichprobe zu prüfen, bevor der Scorer vollständig automatisiert in die CI-Pipeline übernommen wird.
Läuft MLflow auch ohne Docker?
Ja, ein einfacher lokaler Tracking-Server lässt sich allein mit pip und dem Befehl mlflow server starten. Docker wird erst für den produktionsnahen Betrieb mit PostgreSQL und MinIO relevant.
Speichert MLflow die Daten in der EU?
Das hängt vom gewählten Hosting ab. MLflow selbst macht keine Vorgabe zum Standort, daher liegt es an der Infrastrukturwahl, Server und Artefaktspeicher innerhalb der EU zu betreiben, wenn DSGVO-relevante Daten verarbeitet werden.
Kann ich von einem früheren MLflow-2.x-Setup auf MLflow 3 umsteigen?
Ja, die klassischen Tracking-APIs aus MLflow 2 funktionieren größtenteils unverändert weiter. Für die neuen GenAI-Funktionen wie Tracing, Prompt Registry und mlflow.genai.evaluate() ist allerdings ein Upgrade auf die 3.x-Reihe notwendig, da diese Module in älteren Versionen nicht existieren.
Was passiert, wenn der MLflow-Server während eines laufenden Experiments ausfällt?
Bereits abgeschlossene Runs bleiben in der Backend-Datenbank erhalten. Ein laufender Run, der gerade Daten sendet, kann fehlschlagen und sollte im eigenen Code mit einem Try-Except-Block abgefangen werden, damit die Hauptanwendung nicht wegen eines Logging-Fehlers abstürzt.




