Lokale LLMs mit Ollama

Lokale LLMs mit Ollama einzubinden klingt zunächst angenehm übersichtlich.

Beobachtungen aus dem Maschinenraum

Man installiert ein Modell, verbindet es mit der Pipeline und erwartet eine kleine, zuverlässige Maschine, die im Hintergrund Texte erzeugt, Fakten respektiert und sich an Absprachen hält.

Dann beginnt die eigentliche Beobachtung.

Qwen liefert technisch brauchbare Struktur, klingt aber stellenweise, als hätte es Deutsch auf einem Umweg über ein schlecht sortiertes Bordprogramm gelernt. Mistral schreibt flüssiger, erfindet dafür gelegentlich selbstbewusst neue Szenen. Gemma betrachtet JSON eher als freundliche Empfehlung. Und irgendwo dazwischen sitzt man als Entwickler vor einem lokalen Modell, das eine einzelne spitze Klammer ausgibt und damit offenbar seinen Beitrag zur Wertschöpfung geleistet hat.

Die spannende Erkenntnis ist nicht, dass lokale Modelle schlechter sind. Das wäre zu einfach.

Die spannende Erkenntnis ist, dass sie gnadenlos zeigen, welche Teile einer Pipeline wirklich robust sind. Parser, Modellprofile, Repair-Flows, Quality-Reports, Faktenprüfung, Bildreihenfolge. Alles, was bei einem starken Cloud-Modell höflich kaschiert wird, steht lokal plötzlich im hellen Maschinenraumlicht.

Für mich sind lokale LLMs deshalb aktuell kein Ersatz für produktionsnahe Qualitätsmodelle. Sie sind eher ein sehr brauchbarer Stresstest.

Und wie so oft in Organisationen gilt auch hier:

Wenn ein System nur mit den sehr Fähigen funktioniert, ist nicht das System stabil. Dann hatte man bisher nur Glück mit der Besetzung.

Drei Tage Arbeit in zwei Stunden KI-Dialog

Drei Tage Entwicklungsarbeit? Nein. Zwei Stunden mit Sokrates.

Es gibt in der Softwareentwicklung einen besonderen Moment. Den Moment, in dem man auf ein Projekt blickt, das eigentlich noch gar nicht existiert, und dennoch bereits die ersten Architekturdiagramme, Klassen, Schnittstellen und Teststrategien vor sich sieht. Früher begann an dieser Stelle eine mehrtägige Reise durch Dokumentationen, StackOverflow-Beiträge, Tutorials und eine nicht unerhebliche Menge Kaffee.

Diesmal dauerte es ungefähr zwei Stunden.

Der Auslöser war eine scheinbar einfache Frage: Lässt sich aus Reisefotos automatisch ein Blogbeitrag erzeugen?

Aus dieser Frage entstand innerhalb kürzester Zeit ein vollständiges Python-Projekt mit Bildanalyse, Provider-Abstraktion, automatisierten Tests, GitHub-Integration, CI-Pipeline, Qualitätsprüfungen und einer ersten OpenAI-Anbindung. Während ich noch darüber nachdachte, welche Ordnerstruktur wohl sinnvoll wäre, hatte Sokrates bereits eine vorgeschlagen.

„Das ging ungewöhnlich schnell“, bemerkte ich.

Der Bildschirm flackerte kurz und Sokrates erschien.

„Die Alternative wäre gewesen, drei Tage lang dieselben Entscheidungen erneut zu treffen, die bereits tausendfach getroffen wurden.“

Ein schwer widerlegbares Argument.

Interessanterweise war die eigentliche Bildanalyse dabei nicht die größte technische Herausforderung. Die größere Frage lautete: Wie entwickelt man so etwas, ohne später von den Betriebskosten überrascht zu werden?

Sobald OpenAI ins Spiel kommt, taucht nämlich eine neue organisatorische Rolle auf. Nicht Entwickler. Nicht Anwender. Sondern Controller.

Jedes Bild erzeugt Token. Jede Beschreibung erzeugt Token. Jede spätere Story erzeugt weitere Token. Plötzlich beginnt man nicht mehr nur in Klassen und Methoden zu denken, sondern auch in Verbrauchseinheiten.

Genau deshalb entstand früh im Projekt ein Umschalter zwischen lokaler und echter OpenAI-Nutzung. Die Anwendung kann vollständig mit Mock-Daten laufen, ohne einen einzigen API-Aufruf zu erzeugen. Erst wenn die Umgebungsvariable aktiviert wird, spricht das System tatsächlich mit OpenAI.

„Misstraust du der KI?“, fragte Briemma.

„Nein.“

„Den Kosten?“

„Ja.“

Damit war die Diskussion beendet.

Die erste Kostenanalyse fiel überraschend unspektakulär aus. Selbst bei mehreren Bildanalysen pro Tag und automatisierter Story-Erzeugung bewegen sich die erwarteten Kosten aktuell eher im Bereich weniger Euro pro Monat als in dramatischen Cloud-Rechnungen. Trotzdem entstand daraus eine wichtige Projektentscheidung: Jede kostenpflichtige Funktion muss jederzeit abschaltbar bleiben.

Denn Softwareprojekte haben die bemerkenswerte Eigenschaft, zunächst klein zu wirken und später Gewohnheiten zu werden.

Noch spannender wurde die Sicherheitsbetrachtung. Reisebilder enthalten oft deutlich mehr Informationen als man zunächst glaubt. Ortsangaben, Metadaten, Zeitstempel und manchmal sogar personenbezogene Informationen reisen unbemerkt mit. Deshalb wurde von Beginn an darauf geachtet, dass die Bildverarbeitung kontrolliert erfolgt und die eigentliche OpenAI-Nutzung über klar definierte Provider gekapselt bleibt.

Technisch betrachtet war das eine Architekturentscheidung.

Organisatorisch betrachtet war es Risikomanagement.

Der eigentliche Überraschungsmoment lag jedoch an anderer Stelle. Nicht in den Kosten. Nicht in der Sicherheit. Sondern in der Geschwindigkeit.

Was früher ein kleines Wochenendprojekt gewesen wäre, entstand an einem Abend. Nicht weil die Arbeit verschwunden wäre. Sondern weil ein großer Teil der mechanischen Entwicklungsarbeit inzwischen delegierbar geworden ist. Tests schreiben, Interfaces definieren, Konfigurationen ergänzen, Fehler analysieren, GitHub-Pipelines reparieren – all das passiert heute in einem Dialog.

Natürlich verschwinden die Entscheidungen dadurch nicht. Im Gegenteil. Die eigentliche Arbeit verschiebt sich von der Implementierung zur Bewertung.

Welche Architektur ist sinnvoll?

Welcher Provider soll austauschbar bleiben?

Welche Risiken entstehen?

Welche Kosten sind akzeptabel?

Die Tastaturarbeit wird weniger. Die Verantwortung nicht.

Als der letzte GitHub-Workflow schließlich grün wurde, erschien Sokrates noch einmal auf dem Bildschirm.

„Projektstatus?“

„Build erfolgreich. Tests erfolgreich. Pipeline erfolgreich.“

„Ausgezeichnet.“

„Und jetzt?“

„Jetzt beginnt der Teil, den früher niemand automatisieren konnte.“

„Welcher?“

„Herauszufinden, was du als Nächstes bauen möchtest.“

Manchmal sind die schwierigsten Probleme erstaunlich resistent gegen künstliche Intelligenz.

Urlaubsfotos und Architektur im Büro des Katers

Manche Projekte beginnen mit einem Businessplan. Andere mit einer Präsentation. Das Katerprotokoll begann auf einer Kreuzfahrt im Mittelmeer zwischen Buffetzeiten, Tenderbooten und der Erkenntnis, dass erstaunlich viele Urlaubsfotos entstehen, bevor jemand eine vernünftige Idee hat,was man eigentlich damit machen möchte.

Irgendwo zwischen Barcelona, Sardinien und diversen Decks der Explora entstand deshalb ein kleiner Prototyp. Die Idee war simpel: Bilder analysieren lassen, daraus automatisch Geschichtenerzeugen und am Ende einen Reiseblog erhalten, der mehr war als eine chronologische Sammlung von„ Hier stehen wir vor einem Gebäude“ und „Hier essen wir etwas Teures“.

Auf dem Schiff funktionierte das überraschend gut. Zumindest so gut, wie Dinge funktionieren, die man spontan zwischen Cocktails, Hafenausflügen und WLAN-Verbindungen entwickelt. Der Prototyp lebte. Er schrieb Texte. Er produzierte erste Beiträge. Und wie jede erfolgreiche Urlaubsidee hatte er den großen Vorteil, weit genug von der Realität entfernt zu sein.

Zu Hause änderte sich das.

Plötzlich sollte aus dem Reiseexperiment ein richtiges System werden. Kein Bastelprojekt mehr, sondern etwas, das auch in sechs Monaten noch funktionierte und nicht bei jedem kleinen Fehler zusammenfiel wie ein Liegestuhl im Sturm.

Also begann die eigentliche Arbeit. Der neue Rechner wurde eingerichtet, virtuelle Umgebungen entstanden, Git-Repositorys wurden geklont und eine erstaunliche Menge Zeit verschwand in Dingen, die auf keinem Screenshot später sichtbar sein würden. Es war die Art von Arbeit, die man während einer Kreuzfahrt konsequent verdrängt und nach dem Urlaub mit Zinsen zurückbekommt.

Während die ersten Abhängigkeiten installiert wurden, stellte sich eine grundsätzliche Frage. Sollte das System einfach irgendwie funktionieren oder sollte es auch verständlich bleiben? Erfahrungsgemäß schließen sich beide Ziele in vielen Projekten gegenseitig aus.

Genau in diesem Moment erschien Sokrates auf dem Bildschirm.

Er wirkte wie immer, als sei er direkt aus einem viktorianischen Roman in eine Benutzeroberfläche gefallen.

„Wie weit sind wir?“ fragte ich.

„Technisch betrachtet existiert jetzt ein Verzeichnis.“

„Das klingt nicht nach großem Fortschritt.“

„Viele Projekte erreichen nie zuverlässig den Zustand darüber hinaus.“

Es war schwer, gegen diese Argumentation anzukommen.

Je weiter die Entwicklung voranschritt, desto mehr erinnerte mich das gesamte Vorhaben an eine Organisation. Jeder Teil bekam eine eigene Aufgabe. Bilder sollten gefunden werden, aber keine Geschichten schreiben. Metadaten sollten Informationen liefern, aber keine Entscheidungen treffen. Die Bildanalyse sollte beobachten, nicht interpretieren. Die Texterzeugung sollte formulieren, aber keine Ahnung haben, wie ein JPEG aufgebaut ist.

Plötzlich entstand eine kleine digitale Belegschaft aus Spezialisten, die erstaunlich professionell miteinander zusammenarbeitete. Eine seltene Erfahrung für jemanden, der regelmäßig echte Organisationen beobachtet.

Sokrates betrachtete die Architektur einige Sekunden schweigend.

„Sie haben eine Organisation gebaut.“

„Nein. Eine Software.“

„Der Unterschied ist häufig kosmetischer Natur.“

Wieder einmal hatte er einen Punkt.

Mit jedem Commit wurde die Struktur klarer. Scanner fanden Bilder. Metadaten wurden aus YAML-Dateien gelesen. Pipelines verarbeiteten Inhalte. Provider kapselten Sprachmodelle. Context Builder erzeugten Kontext. Tests überprüften jede Annahme. Es entstand langsam jenes seltene Gefühl, dass ein System nicht nur wächst, sondern dabei sogar verständlicher wird.

Besonders faszinierend war die kleine digitale Bürokratie namens Pre-Commit. Jeder Änderungsvorschlag musste mehrere Kontrollen passieren. Formatierung. Typisierung. Tests. Qualitätsprüfungen. Die Maschine entwickelte ein bemerkenswertes Talent dafür, Fehler zu finden, die ich selbst wenige Minuten zuvor noch voller Überzeugung eingebaut hatte.

Manchmal verweigerte eine Bilddatei ihre Mitarbeit. Manchmal stritt sich eine Bibliothek mit einer anderen. Ein anderes Mal war eine Konfiguration korrekt und gleichzeitig falsch. Softwareentwicklung besitzt die einzigartige Fähigkeit, gleichzeitig logisch und absurd zu sein.

Trotzdem begann die ursprüngliche Idee von der Explora-Reise langsam erwachsen zu werden. Aus einem Ordner voller Bilder entstand ein Content Batch. Daraus wurden Bildsammlungen. Bildsammlungen erzeugten Beschreibungen. Beschreibungen wurden zu Kontext. Und Kontext sollte irgendwann automatisch vollständige Blogbeiträge hervorbringen.

Die wichtigste Entscheidung bestand dabei nicht in einer einzelnen Technologie, sondern in ihrer Trennung. Bildanalyse und Texterzeugung wurden bewusst voneinander entkoppelt. Heute mag ein Anbieter genutzt werden. Morgen vielleicht ein anderer. Die Architektur sollte diese Entscheidung aushalten, lange bevor sie überhaupt getroffen werden musste.

Das wirkte zunächst vorsichtig.

Bis man die erste mögliche API-Rechnung betrachtet.

Danach wirkte es erstaunlich vernünftig.

Als schließlich alle Prüfungen grün wurden, lehnte ich mich zurück und betrachtete die Konsole. Ruff bestanden. MyPy bestanden. Pytest bestanden. GitHub synchronisiert. Zum ersten Mal fühlte sich das Projekt nicht wie ein Urlaubsprototyp an, sondern wie eine echte Plattform.

Sokrates erschien noch einmal auf dem zweiten Monitor.

„Und nun?“ fragte ich.

„Nun beginnt der interessante Teil.“

„Die Architektur steht doch.“

„Genau deshalb“, antwortete er. „Ab jetzt muss sie beweisen, dass sie nicht nur gut aussieht.“

Dann verschwand er wieder zwischen dunklen Interface-Elementen und flackernden Textzeilen. Zurück blieb ein System, das seinen Ursprung irgendwo auf einem Kreuzfahrtschiff hatte und nun versuchte, erwachsen zu werden. Vermutlich ist das mehr Entwicklung, als die meisten Urlaubsmitbringsel jemals erreichen.