{
    "kind": 30023,
    "id": "97c751410dc626f360787fb5b18b9cbcafdc0579e41a11fa4770c2d7c3bf6e8e",
    "pubkey": "c1baf4f74cd829963828b1da8d73e52cc94caa6d8dc944f7ca450a75c4b3311f",
    "created_at": 1792092245,
    "tags": [
        [
            "title",
            "RAG-System gegen KI-Halluzination: Wie meine Suche \u201awei\u00df ich nicht\u2018 sagen lernte"
        ],
        [
            "d",
            "rag-system-ki-halluzination-weiss-ich-nicht"
        ],
        [
            "summary",
            "Mein RAG-System gab einer Unsinnsfrage denselben Wert wie einer echten. Wie Reranker und Jev KI-Halluzination abfangen, gemessen an 35 Fragen."
        ],
        [
            "published_at",
            "1792092244"
        ]
    ],
    "content": "Ich habe meiner Suche eine Frage gestellt, auf die sie keine Antwort haben kann: \u201eWie koche ich Spaghetti Carbonara?\u201c Durchsucht hat sie die Dokumentation von Scrapling, einem Werkzeug zum Abholen von Webseiten. \u00dcber Nudeln steht da nichts drin. Die Suche hat trotzdem f\u00fcnf Abschnitte geliefert. Und der beste bekam denselben Spitzenwert wie bei einer echten Frage: 0,5.\n\nGenau da f\u00e4ngt ein RAG-System an, Antworten zu erfinden. Die Suche findet immer etwas. Das Sprachmodell dahinter bekommt dann Text \u00fcber Webseiten und soll Carbonara erkl\u00e4ren. Ob es ehrlich sagt \u201esteht hier nicht drin\u201c, h\u00e4ngt am Modell. Wenn du KI misstraust, dann wahrscheinlich wegen so einer Antwort: klingt sicher, stimmt nicht. Das nennt man KI-Halluzination. Einen \u00dcberblick \u00fcber die Forschung dazu gibt [die \u00dcbersichtsarbeit von Huang u. a. (2023)](https://arxiv.org/abs/2311.05232).\n\nWarum die Suche das nicht merkt, ist schnell erkl\u00e4rt. Der Wert 0,5 sagt nicht, wie gut ein Abschnitt passt. Er entsteht, indem mehrere Ranglisten miteinander verrechnet werden. Das Verfahren hei\u00dft Reciprocal Rank Fusion, auf Deutsch Rangfusion, [beschrieben von Cormack, Clarke und B\u00fcttcher (2009)](https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf). Platz 1 bleibt Platz 1, auch wenn nichts passt. So eine Suche kann also gar nicht sagen: Dazu habe ich nichts.\n\nAlso habe ich ihr das beigebracht. Gemessen habe ich alles am 15.10.2026.\n\n## Was ist RAG?\n\nRAG steht f\u00fcr Retrieval Augmented Generation. Der Begriff stammt aus [der Arbeit von Lewis u. a. (2020)](https://arxiv.org/abs/2005.11401). Auf Deutsch ungef\u00e4hr: erst nachschlagen, dann antworten. Ein Sprachmodell wei\u00df nur, was in seinem Training war. Deine Handb\u00fccher und deine Webseite kennt es nicht. Also h\u00e4ngt man eine Suche davor. Damit wird die eigene Webseite zur Datenquelle f\u00fcr KI. Was dabei z\u00e4hlt, steht in [Webseite f\u00fcr KI optimieren: Was ChatGPT lesen kann](https://in48stunden.de/wissen/webseite-datenquelle-fuer-ki/). Wie gut KI eine bestimmte Seite lesen kann, l\u00e4sst sich mit dem [LLM-Checker](https://codeback.de/llm-checker/) kostenlos testen.\n\nDie RAG-Pipeline l\u00e4uft so: Die Texte werden in Abschnitte zerlegt. Jeder Abschnitt wird in eine lange Zahlenreihe \u00fcbersetzt, die seine Bedeutung abbildet. Diese Zahlen liegen in einer Vektordatenbank, dieselbe Sorte, die ich auch beim [Ged\u00e4chtnis f\u00fcr meine KI-Agenten](https://stevennoack.de/artikel/ki-agenten-gedaechtnis-lokal/) verwendet habe. Kommt eine Frage, wird sie genauso \u00fcbersetzt. Die Datenbank sucht die Abschnitte, die am n\u00e4chsten dran liegen. Die besten f\u00fcnf gehen mit der Frage an das Sprachmodell, und das schreibt die Antwort.\n\nDas klappt gut, solange die Antwort in den Daten steht. Steht sie nicht drin, merkt die Suche das nicht.\n\n## Erst die Sitemap, dann die Seiten\n\nF\u00fcr den Test habe ich die [Doku von Scrapling](https://scrapling.readthedocs.io/en/latest/) genommen. Scrapling ist ein Python-Werkzeug zum Abholen von Webseiten. Wer schon mit [Scrapy](https://docs.scrapy.org/en/latest/) gearbeitet hat, kennt die Aufgabe.\n\nBevor ich irgendwas abhole, hole ich die Sitemap. Das ist die Liste aller Adressen einer Webseite. Die kommt ordentlich in eine kleine Datenbank, SQLite, und dann wei\u00df ich, was es gibt, ohne schon alles geladen zu haben. Ich hab mir kurz vorgestellt, wie ich bei einer gro\u00dfen Seite einfach mal eine Million Seiten runterlade. Nein. Erst die \u00dcbersicht, dann entscheiden.\n\nAus dieser Liste l\u00e4sst sich vorher aussortieren, was ich nicht brauche: \u00dcbersetzungen, \u00c4nderungslisten, Rechtliches, Anmeldeseiten. Vieles erkennt eine einfache Regel am Pfad. F\u00fcr den Rest frage ich Jev, dazu gleich mehr. Hochgerechnet auf eine Million Adressen w\u00fcrde dieses Vorsortieren etwa 20 Dollar kosten.\n\nDanach holt Scrapling die Seiten, macht Markdown daraus und legt sie in der Datenbank ab. Die Abschnitte wandern in die Vektordatenbank. Am Ende waren es 39 Seiten mit 711 Abschnitten.\n\nDann der Test: 30 Fragen, bei denen feststeht, auf welcher Seite die Antwort steht. 15 auf Deutsch, 15 auf Englisch. Dazu f\u00fcnf Spa\u00dffragen, auf die die Doku keine Antwort hat. Carbonara war eine davon.\n\n## Mein RAG-System: Suche, Ja/Nein-Modell, Entscheidungsmodell\n\nMir ging es von Anfang an um eine Kombination. Es gibt Modelle, die selbst nichts entscheiden, aber ein Entscheidungsmodell mit Ja und Nein unterst\u00fctzen k\u00f6nnen. Die wollte ich zusammenbringen.\n\nDie Suche sammelt. Sie holt zu jeder Frage 20 Kandidaten, schnell und grob.\n\nDann kommt das Ja/Nein-Modell, das Fachwort daf\u00fcr ist Reranker. Es bekommt die Frage und einen Abschnitt und gibt einen Wert, wie gut der Abschnitt auf die Frage passt. Das macht es f\u00fcr alle 20 und sortiert danach neu. Ich habe daf\u00fcr bge-reranker-v2-m3 genommen ([Modellkarte](https://huggingface.co/BAAI/bge-reranker-v2-m3)). Das l\u00e4uft bei mir auf dem iMac, nur auf dem Prozessor, rund 3,8 Sekunden pro Frage, und kostet nichts.\n\nAm Ende entscheidet Jev. Jev ist ein Entscheidungsmodell. Es schreibt keinen Text, es w\u00e4hlt aus einer festen Liste von Antworten und sagt dazu, wie sicher es ist. Was das genau ist, habe ich in einem eigenen Artikel aufgeschrieben: [Typisierte Entscheidungen statt Flie\u00dftext, was Jev ist](https://stevennoack.de/artikel/typisierte-entscheidungen-jev/).\n\nJev bekommt die Frage und die besten f\u00fcnf Abschnitte und hat sechs M\u00f6glichkeiten: Abschnitt 1 bis 5 oder \u201enichts davon\u201c. Dieses \u201enichts davon\u201c ist der ganze Trick. Damit kann das System zum ersten Mal sagen: wei\u00df ich nicht.\n\n## Ergebnis: von 15 auf 25 Treffer auf Platz 1\n\n| Kette | richtige Seite auf Platz 1 (von 30) | Spa\u00dffragen abgelehnt (von 5) | echte Fragen abgelehnt (von 30) |\n|---|---|---|---|\n| nur Suche | 15 bzw. 16 | geht nicht | entf\u00e4llt |\n| Suche + Ja/Nein-Modell | 25 | 3 | 1 |\n| Suche + Jev | 25 | 4 | 0 |\n| Suche + Ja/Nein-Modell + Jev | 24 | 5 | 2 |\n\nDie Suche allein kam in zwei Messl\u00e4ufen auf 15 und 16 Treffer auf Platz 1. Die richtige Seite war aber meistens unter den ersten f\u00fcnf. Das Ja/Nein-Modell holt sie nach vorn, auf 25 von 30. Jev schafft dasselbe, auch 25. Das h\u00e4tte ich nicht erwartet: Das kleine Modell auf meinem Rechner sortiert so gut wie Jev.\n\nBei den deutschen Fragen war der Sprung am gr\u00f6\u00dften. Die Doku ist englisch, die Suche arbeitet mit einem deutschen Modell, und das passt schlecht zusammen. Nur 5 von 15 deutschen Fragen landeten auf Platz 1. Mit dem Ja/Nein-Modell waren es 11 von 15.\n\nBeim \u201ewei\u00df ich nicht\u201c trennen sich die Wege. Die Werte vom Ja/Nein-Modell streuen. Eine Spa\u00dffrage bekam 0,71, eine echte Frage 0,01. Da trennt eine feste Grenze schlecht. Mit einem Wert unter 0,01 als Grenze hat es 3 der 5 Spa\u00dffragen erwischt.\n\nJev mit seinem \u201enichts davon\u201c trennt klarer. Allein hat er 4 der 5 Spa\u00dffragen abgelehnt, ohne eine echte Frage wegzuwerfen. Durchgerutscht ist eine Frage zum Export nach PostgreSQL, da lag Jev genau bei 0,5. Ich h\u00e4tte die Schwelle hochdrehen k\u00f6nnen. Bei 0,6 lehnt Jev alle f\u00fcnf ab, wirft daf\u00fcr aber sechs echte Fragen weg. Das ist ein schlechter Tausch.\n\nMit beiden zusammen lehnt das System alle f\u00fcnf Spa\u00dffragen ab. Platz 1 stimmt in 24 von 30 F\u00e4llen, und zweimal hat es bei einer echten Frage abgewunken. Das ist die Arbeitsteilung, die ich wollte: Das Ja/Nein-Modell sortiert lokal und kostenlos, Jev sagt am Ende \u201ediese Antwort oder keine\u201c.\n\nWas das kostet: 0,003 Dollar f\u00fcr alle 35 Fragen. Jev braucht rund eine halbe Sekunde pro Frage.\n\n## Der Umweg, den ich nicht bestellt hatte\n\nBevor diese Kette stand, gab es einen Umweg. Der erste Aufbau lie\u00df Jev \u00fcber jeden der 711 Abschnitte einzeln urteilen: Fachinhalt, Quelltext, Werbung, Navigation. Was sicher M\u00fcll war, sollte aus der Suche verschwinden. Das war nicht meine Entscheidung, jeden einzelnen Abschnitt so abzufragen.\n\nDie Urteile selbst waren sauber. 113 Abschnitte wurden ausgeblendet, 16 Prozent. Von 25 davon, die nachgepr\u00fcft wurden, waren alle 25 zu Recht drau\u00dfen.\n\nBesser gefunden wurde danach aber nichts. Platz 1 blieb bei 16 von 30, unter den ersten f\u00fcnf bei 27 von 30. Der M\u00fcll hatte vorher nur 8 von 175 Pl\u00e4tzen unter den ersten f\u00fcnf belegt. Danach waren es null. Weniger M\u00fcll im Material, das sp\u00e4ter ans Sprachmodell geht, das schon. Bessere Treffer gab es keine.\n\nGebracht hat der Umweg trotzdem was. Jev hat das Muster gefunden. Fast der ganze M\u00fcll kam aus einem einzigen Baustein der Doku-Software, den K\u00e4sten \u201eSource code in \u2026\u201c in der API-Referenz. Die kann man schon beim Abholen der Seiten weglassen, mit einer einfachen Regel, einem sogenannten Selektor. Danach waren es 480 statt 711 Abschnitte, die Treffer blieben gleich, und die Regel kostet nichts. Jev noch mal \u00fcber alle Abschnitte laufen zu lassen h\u00e4tte bei jedem Abholen 0,015 Dollar gekostet.\n\nDaraus nehme ich mit: Das Modell findet das Muster einmal. Danach geh\u00f6rt es als Regel ins Skript. Jev setze ich dort ein, wo eine Regel nicht weiterkommt. Ob ein Abschnitt eine Frage beantwortet, kann keine Regel entscheiden.\n\n## Grenzen: ein Lauf, 35 Fragen, eine Doku\n\nDas ist eine kleine Messung. Jede Messung lief nur einmal. 35 Fragen, eine Doku mit 39 Seiten. Die Fragen hat ein KI-Agent aus den \u00dcberschriften der Doku abgeleitet. Gez\u00e4hlt wurde, ob die richtige Seite vorne liegt, nicht der richtige Abschnitt.\n\nUnd manchmal war die Vorgabe zu eng. Zweimal w\u00e4hlte Jev die deutsche README. Die beantwortet die Frage inhaltlich, nur war eine andere Seite als richtig eingetragen. Das z\u00e4hlt in der Tabelle als Fehler, obwohl die Antwort gestimmt h\u00e4tte.\n\nOb das auf andere Texte \u00fcbertragbar ist, wei\u00df ich erst, wenn ich es dort messe.\n\n## Was das f\u00fcr \u201eFrag Steven\u201c hei\u00dft\n\nAls N\u00e4chstes kommt das auf meine eigene Webseite. \u201eFrag Steven\u201c soll eine Suche \u00fcber meine eigenen Texte werden. Da gilt dieselbe Regel: Eine Antwort gibt es nur, wenn sie in meinen Texten belegt ist. Wenn nicht, sagt das System, dass ich dazu nichts geschrieben habe.\n\nZwei Fehlalarme bei 30 echten Fragen nehme ich daf\u00fcr in Kauf. Lieber einmal zu oft \u201ewei\u00df ich nicht\u201c als eine erfundene Antwort mit meinem Namen drunter.\n\nUnd wenn du von KI nicht viel h\u00e4ltst: So ein System l\u00e4sst sich so bauen, dass es zugibt, wenn es nichts wei\u00df. Ob es das tut, sieht man allerdings erst, wenn man es mit Fragen pr\u00fcft, auf die es keine Antwort gibt.\n\nDen Aufbau nehme ich so mit: Suche, Ja/Nein-Modell und Jev mit dem Ausweg \u201enichts davon\u201c. Die Regel gegen die Quelltext-K\u00e4sten brauche ich dort wahrscheinlich nicht. Meine Seiten haben keine API-Referenz.\n\n## Quellen\n\n- Lewis u. a. (2020): [Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks](https://arxiv.org/abs/2005.11401)\n- Huang u. a. (2023): [A Survey on Hallucination in Large Language Models](https://arxiv.org/abs/2311.05232)\n- Cormack, Clarke, B\u00fcttcher (2009): [Reciprocal Rank Fusion](https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf)\n- [Modellkarte bge-reranker-v2-m3](https://huggingface.co/BAAI/bge-reranker-v2-m3)\n- [Scrapling-Dokumentation](https://scrapling.readthedocs.io/en/latest/)\n- [Scrapy-Dokumentation](https://docs.scrapy.org/en/latest/)\n- [Webseite f\u00fcr KI optimieren: Was ChatGPT lesen kann](https://in48stunden.de/wissen/webseite-datenquelle-fuer-ki/) (in48stunden.de)\n- [LLM-Checker: LLM-Readability kostenlos testen](https://codeback.de/llm-checker/) (CodeBack)\n- [Typisierte Entscheidungen statt Flie\u00dftext: was Jev ist](https://stevennoack.de/artikel/typisierte-entscheidungen-jev/)\n- [Wie ich meinen KI-Agenten ein Ged\u00e4chtnis gebaut habe](https://stevennoack.de/artikel/ki-agenten-gedaechtnis-lokal/)\n\nAlle Messwerte: eigene Messung vom 15.10.2026, je ein Lauf.",
    "sig": "d00faee6735b3028c9ccbbe9886f52fea2fc46c7f064864be08fd8b1a78f2f9ae5d0a5bfd7482f1d98e7bd3d4db72d21fc3480e02001327774798b302bef72c0"
}
