„HEureka“ – warum ich immer wieder neu angefangen habe
Am Anfang war Eureka noch eine verhältnismäßig einfache Idee. Ich wollte eine KI, die bei mir zu Hause läuft. Nicht abhängig von irgendeiner Cloud, nicht davon abhängig, ob ein Anbieter morgen seine Preise, Regeln oder Modelle ändert. Ich wollte etwas Eigenes.
Ich hatte dafür eigentlich einen ziemlich einfachen Grundsatz: Alles, was Menschen gebaut haben, kann man auch verstehen. Und wenn man es verstehen kann, kann man zumindest versuchen, es selbst zu bauen.
Die erste Eureka war deshalb auch noch viel überschaubarer. Ubuntu, Python, Flask, eine Datenbank und Ollama. Dazu ein lokales Modell wie Llama 3. Die KI sollte Fragen erkennen, Antworten finden und vor allem lernen. Es gab Intents wie Begrüßung, Wissensfrage, Planung oder Problem. Wörter, Synonyme und gelernte Antworten landeten in der Datenbank. Später kamen Wikipedia und DuckDuckGo als Quellen hinzu.
Damals dachte ich noch stärker in Kategorien wie: Frage rein, Thema erkennen, Information suchen, Antwort speichern.
Und es funktionierte sogar.
Aber je länger ich daran arbeitete, desto mehr fiel mir auf, dass „funktionieren“ nicht dasselbe bedeutet wie „verstehen“.
Wenn Eureka beispielsweise einen Text fand und daraus etwas abspeicherte, stellte sich die nächste Frage: Warum glaubt Eureka eigentlich, dass diese Information stimmt?
Dann kamen sofort weitere Fragen.
Woher stammt die Information? Ist die Quelle gut? Hat eine zweite Quelle nur von der ersten abgeschrieben? Was genau behauptet der Satz überhaupt? Worauf bezieht sich ein Pronomen? Ist etwas eine Ursache, eine Behauptung oder nur eine Beschreibung? Und wenn Eureka etwas später wiederfindet: Weiß sie dann noch, weshalb sie es damals für glaubwürdig gehalten hat?
An diesem Punkt wurde aus meinem ursprünglichen Projekt langsam etwas anderes.
Ich hätte natürlich einfach immer mehr Regeln an die alte Version hängen können. Genau das hatte ich teilweise auch getan. Es entstanden Tabellen, Lernbereiche, Pending-Queues, Synonyme, Zustände, Aktionen, Vektoren und immer mehr Sonderlogik. Zeitweise lagen zehntausende Einträge in Warteschlangen. Manche Ideen funktionierten, andere wurden verworfen, manche existierten noch im Code, obwohl ich sie längst nicht mehr verwenden wollte.
Irgendwann merkte ich: Wenn ich so weitermache, weiß ich irgendwann selbst nicht mehr, was Eureka eigentlich warum tut.
Also tat ich etwas, was sich später noch oft wiederholen sollte:
Ich baute zurück.
Nicht weil alles schlecht gewesen wäre. Im Gegenteil. Viele Teile hatten funktioniert. Aber ich wollte nicht ein System retten, nur weil ich schon viel Arbeit hineingesteckt hatte.
Im Juli 2026 begann deshalb Eureka v2.
Diesmal wollte ich das Fundament sauberer aufbauen. PostgreSQL statt der alten Datenbankstruktur, klarere Module für Bedeutung, Lernen, Wissen, Schlussfolgern und Antworterzeugung. Die alte Datenbank wurde nicht einfach weggeworfen; ich sicherte sie. Der große Dump vom 16. Juli hatte fast ein halbes Gigabyte. Das war für mich auch ein Zeichen dafür, wie weit das Projekt inzwischen gekommen war.
Eureka v2 sollte nicht einfach mehr wissen.
Sie sollte nachvollziehbarer denken.
Damit änderte sich mein Blick auf das Projekt grundlegend.
Früher hatte ich mich häufig gefragt: „Warum gibt Eureka keine Antwort?“
Jetzt begann ich zu fragen:
„An welcher Stelle verliert sie das Verständnis?“
Das klingt nach einer kleinen Änderung, war aber wahrscheinlich eine der wichtigsten überhaupt.
Ich begann einzelne Verarbeitungsschritte getrennt zu betrachten. Wahrnehmung, Sprachverständnis, Bedeutung, Kontext, Thema, vorhandenes Wissen, Wissenslücke, Recherche, Informationsverständnis, Prüfung und schließlich Antwort.
Und genau da begann auch eine Phase, in der ich mehrfach wieder zurückging.
Ein Beispiel war die Recherche.
Zunächst wollte ich Eureka sehr streng machen. Eine KI sollte schließlich nicht jeden Unsinn aus dem Internet glauben. Also entstanden Filter. Quellen wurden geprüft, Kandidaten verworfen, Beziehungen kontrolliert und Aussagen mussten bestimmte Bedingungen erfüllen.
Das war vernünftig.
Nur irgendwann war Eureka so vorsichtig geworden, dass sie zwar recherchierte, aber kaum noch etwas verwenden durfte.
Beim berühmten Test mit dem Apfel sah man das besonders gut.
Die Frage war:
„Warum fällt der Apfel auf den Boden?“
Eureka fand Quellen. Sie lud Texte herunter. Es gab verwertbare Inhalte. Und trotzdem kam keine Antwort zustande.
Wir gingen immer tiefer in die Diagnose und stellten fest, dass der entscheidende Satz praktisch direkt vor ihrer Nase lag, aber die Beziehung nicht korrekt extrahiert wurde. Ein Satz wie „Dieses Gesetz erklärt, warum ein Apfel zur Erde fällt“ wurde erkannt, aber nicht als passende Ursache verstanden. Ein anderer Satz scheiterte an einem Pronomen.
Das war einer dieser Momente, an denen ich gelernt habe, nicht einfach den Filter lockerer zu machen.
Denn der Filter war nicht unbedingt das Problem.
Das eigentliche Problem lag früher: Eureka hatte die Information noch nicht richtig verstanden.
Diese Erkenntnis tauchte später immer wieder auf.
Wenn eine Information nicht durchkommt, darf die erste Reaktion nicht sein: „Dann machen wir den Filter schwächer.“
Erst muss geklärt werden, ob das Verständnis davor stimmt.
Aus diesem Grund wurde auch die Recherchearchitektur noch einmal neu gedacht. Frühe Filter sollten nur groben Müll entfernen. Die strenge Wahrheitsprüfung sollte später stattfinden, nachdem Eureka überhaupt verstanden hatte, was eine Quelle behauptet.
Das war wieder eine Form des Zurückbauens.
Nicht alles löschen.
Aber Verantwortung an die richtige Stelle verschieben.
Im selben Zeitraum veränderte sich auch meine Hardware. Ich richtete einen zweiten Ubuntu-Rechner als Rechenmaschine ein. Ollama lief dort mit der GPU, während ich von einem anderen Rechner arbeitete. Ich testete Qwen, DeepSeek und unterschiedliche Modellgrößen. Dabei stellte ich fest, dass auch ein größeres Modell nicht automatisch das Architekturproblem löst.
Ein Modell kann helfen.
Aber wenn Eureka ihm die falschen Daten gibt, den falschen Kontext übergibt oder vorher eine Beziehung verloren hat, denkt auch das beste Modell über das Falsche nach.
Das wurde später besonders beim Dashboard deutlich.
Ich wollte endlich sehen können, was Eureka tatsächlich tut.
Nicht nur die Endantwort.
Quellen, Kandidaten, Entscheidungen, Prüfungen, Ablehnungsgründe und die einzelnen Stufen sollten sichtbar werden. Daraus entstand der Runtime-Trace und später der DeepSeek-Pfadwächter.
Auch dort ging nicht alles geradeaus.
Wir bauten Funktionen ein, änderten Cache-Versionen, bekamen Kontextfehler, Validatorfehler und zeitweise zeigte das Dashboard etwas anderes als der eigentliche Runtime-Trace.
Und wieder kam derselbe Punkt:
Zurück.
Nicht noch mehr Logik darüberbauen.
Erst feststellen, welche Darstellung die Wahrheit enthält.
Daraus entstand eine Regel, die heute wahrscheinlich wichtiger ist als viele einzelne Funktionen in Eureka:
Letzter richtiger Wert → erster falscher Wert → genaue Stelle, die ihn verändert hat.
Nicht mehr zehn Dateien gleichzeitig durchsuchen.
Nicht auf den neuesten Fehler springen.
Nicht eine Architektur neu entwerfen, nur weil irgendwo ein Feld leer ist.
Erst beweisen, wo der Wert verloren geht.
Diese Arbeitsweise hat das Projekt in den letzten Wochen enorm verändert.
Ein sehr schönes Beispiel dafür sind unsere aktuellen Satztests.
Der einfache Satz
„Der Hund jagt die Katze.“
funktionierte irgendwann.
Aber das reicht natürlich nicht für eine wirkliche Sprachverarbeitung.
Also kamen Varianten:
„Die Katze wird vom Hund gejagt.“
„Vom Hund wird die Katze gejagt.“
„Der Hund, der die Katze jagt, bellt.“
Und plötzlich zeigte sich wieder, wie viel Unterschied zwischen Worten erkennen und Sprache verstehen liegt.
Beim Passiv musste Eureka verstehen, dass die Katze grammatisch vorne steht, semantisch aber das Objekt des Jagens ist. Der Hund steckt in einer „von“-Phrase und ist trotzdem der Handelnde.
Wir änderten nicht den ganzen Parser.
Wir ergänzten genau diese grammatische Struktur.
Dann funktionierte der Passivsatz.
Beim Relativsatz wurde es noch interessanter.
„Der Hund, der die Katze jagt, bellt.“
enthält eigentlich zwei Aussagen:
Der Hund bellt.
Und:
Der Hund jagt die Katze.
Eureka musste lernen, diese zweite Aussage aus dem Relativsatz herauszulösen.
Nach mehreren Diagnosen tat sie genau das.
Aus dem Satz entstand intern tatsächlich:
Hund → jagen → Katze.
Dann lief diese Aussage durch Themenverständnis, Wissensprüfung und Recherche.
Und vor wenigen Tagen passierte etwas, das auf den ersten Blick fast unspektakulär wirkte, für das Projekt aber ziemlich wichtig war:
Eureka fand im Internet tatsächlich einen Satz, der genau diese Relation bestätigt.
Hund → jagen → Katze.
Der Claim wurde extrahiert.
Er wurde mit unserer Prüfaussage verglichen.
Und Eureka entschied:
bestätigt.
Damit war der Relativsatz nicht mehr nur grammatisch erkannt. Die darin enthaltene Aussage hatte den ganzen Weg bis in die Recherche geschafft.
Und dann blieb Eureka wieder stehen.
Aber diesmal war das kein Rückschritt.
Denn der neue Fehler lag hinter all den Dingen, die wir gerade repariert hatten.
Die Quelle war vorhanden. Der Claim war richtig. Die Relation war bestätigt.
Die Quelle durfte nur nicht als bestätigungsfähig gelten.
Warum?
Weil Eureka zwar teilweise automatisch erkennen kann, ob eine Seite beispielsweise journalistisch, wissenschaftlich oder eine Fachseite ist, aber ihre independence_group bei unbekannten Webseiten auf unknown stehen bleibt.
Also gingen wir wieder rückwärts durch die Verarbeitung.
confirmation_capable = false.
Warum?
independence_group = unknown.
Warum?
Kein Eintrag in SOURCE_PROFILES.
Aber anstatt jetzt einfach happyhunde.de dort hineinzuschreiben, gingen wir weiter.
Denn das hätte nur diesen einen Test repariert.
Und genau solche Lösungen möchte ich inzwischen vermeiden.
Wir stellten fest, dass Eureka bereits versucht, den Herausgeber einer Webseite selbst zu erkennen. Über JSON-LD, Schema.org-Daten und sogar Copyright-Hinweise.
Dann prüften wir die betreffende Webseite direkt.
Und tatsächlich liefert sie sauber strukturierte Daten:
Organisation: Happyhunde.
Autorin: Dr. Inga Menn.
Publisher: die Organisation von Happyhunde.
Nur benutzt die Webseite eine völlig normale JSON-LD-Technik: Der Artikel enthält beim Publisher lediglich eine @id, die auf den Organisationsknoten im selben JSON-LD-Graphen verweist.
Und genau diese Referenz löst Eureka noch nicht auf.
Das ist der Punkt, an dem wir heute stehen.
Nicht mehr:
„Warum kann Eureka den Relativsatz nicht verstehen?“
Nicht mehr:
„Warum findet sie keine Quelle?“
Nicht einmal mehr:
„Warum erkennt sie den richtigen Claim nicht?“
Sondern:
„Warum kann Eureka einen strukturierten Publisher-Verweis in JSON-LD noch nicht auflösen?“
Wenn ich zurückblicke, ist das wahrscheinlich die eigentliche Geschichte von Eureka.
Ich habe mehrmals neu angefangen.
Ich habe Dinge gebaut und später wieder entfernt.
Ich habe Funktionen geschrieben, von denen ich überzeugt war, und Wochen später festgestellt, dass sie an der falschen Stelle saßen.
Manchmal habe ich einen alten Stand zurückgeholt, weil eine neue Lösung mehr kaputt machte als sie reparierte.
Manchmal musste ich akzeptieren, dass wir einen Fehler an der falschen Stelle gesucht hatten.
Und manchmal hatte ich das Gefühl, dass wir uns überhaupt nicht bewegen.
Aber wenn man die erste Eureka mit dem heutigen Stand vergleicht, stimmt das nicht.
Am Anfang war die Frage:
„Kann ich eine lokale KI bauen, die Informationen findet und speichert?“
Heute lautet die Frage eher:
„Kann ich eine KI bauen, die nachvollziehbar unterscheiden kann, was ein Satz bedeutet, welche Behauptung darin steckt, welche Quelle diese Behauptung stützt, wie unabhängig diese Quelle ist und weshalb die Information später noch vertrauenswürdig sein soll?“
Das ist ein völlig anderes Projekt geworden.
Und vielleicht erklärt das auch, warum ich so oft zurückgebaut habe.
Nicht weil Eureka gescheitert ist.
Sondern weil ich während des Bauens selbst immer genauer verstanden habe, was Eureka eigentlich werden soll.
Heute würde ich sagen:
Eureka ist nicht deshalb weitergekommen, weil ich immer mehr Code hinzugefügt habe.
Sie ist weitergekommen, weil ich irgendwann angefangen habe, auch wieder Code, Ideen und Abkürzungen wegzunehmen, wenn sie nicht mehr zu dem System passten, das ich eigentlich bauen wollte.
Und das ist vermutlich der größte Unterschied zwischen der ersten Eureka und der heutigen.
Die erste sollte Antworten geben.
Die heutige soll irgendwann wissen, warum sie eine Antwort geben darf.