Warum RAG-Antworten vollständig erscheinen, obwohl die Suche in Azure DevOps zeigt, dass sie es nicht sind
Schließung von Vollständigkeitslücken in einem graphbasierten Azure DevOps RAG-System: deterministische Tag-Prüfungen, Graph-Walks, Kontextobergrenzen sowie nur-Lese-Abfragemittel.
Ein System, das die Historie von Azure DevOps in eine Graph-Datenbank lädt, kann Fragen zu Projekten, Verantwortlichkeiten und abgelieferten Arbeiten mit verständlichen Texten sowie klickbaren Quellenangaben beantworten. Eine Zeit lang schien das ausreichend zu sein – bis die Antworten anhand einer simplen Grundlage überprüft wurden: einer rohen Azure DevOps-Abfrage. Die Lücke zwischen einer ausgearbeiteten Antwort und einer umfassenden Liste ist der Punkt, an dem eine „vollständige“ Auswertung heimlich versagt. Um diese Lücke zu schließen, waren deterministische Schritte, gemessene Tests sowie mehrere Korrekturen erforderlich, die wiederum eigene neue Probleme mit sich brachten.
Die Frage, die die Lücke aufzeigte
Frühe Anfragen ergaben saubere, belegte Antworten mit wenig Eigeninitiative. Eine umfassendere Anfrage – „Welche KI-Arbeiten werden in dieser Organisation durchgeführt?“ – sah ebenfalls gut aus: ein paar Absätze, einige Quellenangaben, nichts Offensichtlich Falsches. Dasselbe Frageformat eingesetzt in az boards query, einer Brute-Force-Suche ohne Ranking-Intelligenz, lieferte Dutzende von Ergebnissen, die in der ausgearbeiteten Antwort nicht erwähnt wurden. Cluster zu Themen wie der Bewertung von Programmierassistenten, dem Vergleich von Modellkosten oder dem Debuggen eines bestimmten Tools fehlten, weil sie nur wenig mit der Frage gemeinsam hatten und in der semantischen Suche nie an die Spitze kamen.
Dieses Versagen ist leicht zu übersehen: Eine gut gerankte Antwort ist nicht gleichbedeutend mit einer vollständigen Antwort, und das System gibt keinen Hinweis darauf, welche Art von Antwort man erhalten hat.
Eine Anfrage, die nur manchmal half
Der erste Impuls war, dem Modell Anweisungen zu geben, vorsichtiger zu sein – bei allgemeinen Fragen sollten die Kategorietags vor der Beantwortung überprüft werden, anstatt sich allein auf die Suche zu verlassen. Das half gelegentlich. Derselbe Formulierung führte bei verschiedenen Ausführungen zu unterschiedlichem Verhalten: Manchmal überprüfte das Modell die Tags, manchmal übersprang es sie. An der Frage selbst änderte sich nichts – nur, ob in diesem Schritt die Anweisung befolgt wurde.
Eine Anweisung an ein Sprachmodell ist ein Anstoß, keine Garantie. Wenn Vollständigkeit wichtig ist, darf die Sorgfalt nicht davon abhängen, ob das Modell im Moment entscheidet, sorgfältig zu sein oder nicht.
Den Ablauf deterministisch machen
Die nächste Änderung beendete das ständige Nachfragen. Der Code überprüft bei jeder umfassenden Anfrage immer die Tags, unabhängig davon, ob das Modell es für notwendig hält. Allein dadurch sank die Anzahl der Items mit einer eindeutigen Wahrheit von etwa der Hälfte auf sieben von insgesamt sechzehn – besser, aber immer noch unvollständig. Weitere Schritte resultierten aus konkreten Lücken bei den Tests und nicht aus Spekulationen:
Ein Schritt besteht darin, bei Suchanfragen nach Tags nach wiederholten Namen und Phrasen zu suchen, die zwei oder drei Mal auftauchen, und diese Namen anschließend direkt abzusuchen – so kommt ein Produktname ans Licht, selbst wenn niemand ihn explizit abgefragt hat, sobald der kleine Cluster, der ihn enthält, bereits sichtbar ist.
Ein Schritt, der die Beziehungen im Graphen berücksichtigt, nicht nur die Wortwahl, denn gleichartige Arbeitsobjekte können denselben Elterneintrag teilen, ohne dass sie dieselben Titelwörter haben. Ein Objekt mit einem Titel wie ein als Vorlage dienendes Test-Repository mit repräsentativen Programmieraufgaben kann in seinem eigenen Text nichts über KI aussagen und verbindet sich lediglich über die Hierarchie.
Ein Schritt für Repositorien, die nicht dieselben Kategorietags wie Arbeitsobjekte tragen und sonst für tagbasierte Suchwege unsichtbar blieben würden.
Ein Schritt für Personen, nachdem Fragen wie „Wie oft haben zwei Mitarbeiter zusammen gearbeitet?“ zu zuverlässig falschen Antworten führten.
Jeder dieser Schritte schloss eine bestimmte Lücke. Schließlich wurde der schwierigste Fall mit sechzehn Objekten vollständig gelöst – nicht nur teilweise, sondern ganz.
Mehr abgerufener Kontext verschlechterte die Antworten
Ungewöhnlicherweise wurden die Antworten kürzer und unvollständiger, sobald die Informationsabrufleistung so weit verbessert wurde, dass der Pool des Modells von einigen Hundert Elementen auf über tausend anstieg. Das Modell stürzte nicht ab; es produzierte einfach weniger Inhalte, obwohl mehr relevanter Material verfügbar war. Ab einem bestimmten Umfangswert steigt die Antwortqualität nicht mit der Größe des Kontexts an – sie verschlechtert sich vielmehr. Während die Metriken zur Informationsabrufleistung verbesserten, sanken die Metriken für die Endantworten im selben Testlauf. Die Lösung bestand nicht darin, mehr hinzuzufügen, sondern den Grenzwert zu finden und sich darunter zu halten.
Eine Transparenzlösung, die zu übermäßigen Antworten führte
Wenn das Modell echtes Material zusammenfasste, anstatt es zu benennen, listete ein neuer Antwortabschnitt die gefundenen, aber nicht benannten Elemente auf, sodass nichts stillschweigend verschwand. Die erste Version fügte bei spezifischen Fragen Antworten mit mehr als tausend nur lose miteinander verbundenen Elementen hinzu, da der Listengenerator keine präzisen Übereinstimmungen von allgemeinem „Tag-Noise“ unterscheiden konnte. Eine breite Kategorie sammelte alles, was nur entfernt damit zusammenhing, und betrachtete es als gleichwertig für die Darstellung.
Die dauerhafte Lösung bestand nicht nur in einer numerischen Obergrenze. Vielmehr wurden zwei Arten von „gefunden, aber nicht benannt“ unterschieden: eine kleine Gruppe präziser Übereinstimmungen, die immer angezeigt werden sollten, sowie eine große Menge locker gekennzeichneter „Noise“-Elemente, für die eine klare Obergrenze sowie eine Hinweistexte notwendig waren, dass es noch weitere gibt. Diese Unterscheidung war wichtiger als die Obergrenze selbst.
Dem Modell Werkzeuge geben – mit Schutzmaßnahmen
Eine wichtige Frage prägte den weiteren Verlauf der Arbeit: Warum kann ein Mensch das beantworten, was das System nicht kann, obwohl beide dieselben Daten sehen? Menschen können eine neue Abfrage erstellen, wenn feste Werkzeuge nicht geeignet sind, und sie überprüfen Antworten noch einmal, die ihnen seltsam vorkommen. Das Modell verfügte über keine dieser Fähigkeiten. Es erhielt ein Werkzeug, mit dem es eigene nur-Lese-Datenbankabfragen schreiben konnte – wobei die Datenbank eine nur-Lese-Regel durchsetzte, Zeitbeschränkungen galten und die Größe der Ergebnisse begrenzt war.
Zwei weitere Runden waren erforderlich. Als gefragt wurde, wie oft zwei benannte Personen zusammenarbeiteten, nahm das Modell zunächst an, dass sie denselben Nachnamen hatten, weil er gemeinsam erwähnt wurde, erhielt jedoch kein Ergebnis und tippte stattdessen auf unzusammenhängende Kommentare, anstatt die leere Ausgabe in Frage zu stellen. Die Regel wurde daraufhin: Jeden Namen zunächst auf sein genaues Datensatz-Eintrag prüfen und eine leere Selbstabfrage als Beweis dafür betrachten, dass die Abfrage falsch ist – und nicht darauf, dass die Anzahl null ist.
Beim nächsten Versuch wurden beide Personen berücksichtigt, die richtige Abfrage ausgeführt, es wurden fünfundzwanzig gemeinsam genutzte Elemente ermittelt – doch die Zahl wurde dennoch nicht angegeben, weil jede faktische Aussage eine Quellen-ID erforderte, während eine berechnete Anzahl keine solche hatte. Gemäß den Buchstaben der Zitierregeln wurde somit eine richtige Antwort verworfen. Es war eine ausdrückliche Ausnahme erforderlich: Eine berechnete Zahl kann ohne Quellen-ID einfach angegeben werden.
Auch dieses Versagen war keine Unfähigkeit; beides war eine korrekte Befolgung von Anweisungen, die die Situation nicht abdeckten. Dieser Unterschied ist wichtiger, als es auf den ersten Blick scheint.
Wie die Tests ehrlich blieben
Die Grundwahrheit war keine Stimmungsprüfung. Für den schwierigsten Cluster wurden zu Beginn sechzehn bekannte Elemente aus der umfassenden Abfrage aufgelistet, anschließend nach jeder Änderung bei der Suche bewertet: Wie viele tauchten in der endgültigen Antwort auf, wie viele wurden zitiert und wie viele wurden stillschweigend weggelassen. Genau diese Bewertungsmatrix machte „sieben von sechzehn“ sowie später „sechzehn von sechzehn“ bedeutungsvoll. Ohne eine externe, umfassende Liste ist „scheinbar vollständig“ lediglich eine ästhetische Beurteilung.
Die Pipeline sortieren, ohne das Modell zu überlasten
Deterministische Schritte benötigen dennoch eine bestimmte Reihenfolge. Zunächst erweitert die Tag-Expansion den Kandidatenpool; anschließend vertieft das Name-Mining diesen Pool; Graph-Walks fügen strukturelle Nachbarn hinzu; die Schritte bezüglich Repositorien und Personen schließen Modalitätslücken. Erst nachdem dieser Pool erstellt wurde, begrenzt eine Obergrenze für die Größe das, was in den Prompt aufgenommen wird. Wenn man diese Reihenfolge umkehrt – also vom Modell verlangt, gründlich vor Erstellung des Pools zu arbeiten – kehrt man zum Problem der ungenauen Ergebnisse zurück. Die Gewährleistung der Vollständigkeit liegt im Pipeline-Design, nicht in besseren Adjektiven im Systemprompt.
Zitate versus berechnete Fakten
Die Regel „Jeder Behauptung muss eine Quelle zugeordnet werden“ schützt vor Fälschungen, wenn das Modell Arbeitsobjekte zitiert. Sie wird schädlich, wenn das Modell arithmetische Operationen durchführt oder Ergebnisse aus verschiedenen Tools zusammenführt. Durch die Trennung von „zitierten Behauptungen“ und „berechneten Aggregaten“ in den Anweisungen wurde die Zahl der 25 Zusammenarbeiten wiederhergestellt, ohne die Disziplin bei der Zitierung von narrativen Behauptungen zu schwächen. RAG-Systeme, die Tools nutzen, benötigen beide Regeln ausdrücklich.
Der aktuelle Stand der Entwicklung
Eine rohe Datenbankabfrage ist per Konstruktion ausführlich: Es können keine passenden Zeilen übersehen werden. Sie kann außerdem keinen Sinn erklären, gruppieren oder darstellen – sie liefert lediglich eine Liste, keine Antwort. Das System prüft nun die Vollständigkeit dieser Abfragen anhand der gefundenen und getesteten schwierigen Fälle und erklärt die Ergebnisse dennoch in Prosa unter Verwendung überprüfbarer Quellen. Dieses Ergebnis wird gemessen, nicht angenommen.
Es handelt sich nicht um ein gelöstes Problem. Jede der oben genannten Lösungen existiert, weil bei der Überprüfung der Antworten anhand einer umfassenden Liste ein spezifischer Fehler auftrat. Diese Methode erkennt Lücken, beweist aber nicht, dass keine mehr vorhanden sind. Nach den oben genannten Änderungen tauchte erneut eine neue Frageart auf: Es wurde eine Quelle zitiert, um eine Behauptung über eine Person zu untermauern, obwohl die zitierte Quelle nichts über diese Person aussagte – dieses Problem wurde entdeckt, zum Zeitpunkt der Niederschrift aber noch nicht behoben. Das Muster setzt sich fort: Etwas, das als vollständig erscheint, wird überprüft, und es taucht etwas Neues auf.
Die ehrliche Zusammenfassung lautet nicht „Die Vollständigkeit von RAG ist gelöst.“ Vielmehr wurden alle konkret gefundenen und getesteten Lücken mit vorherigen und nachfolgenden Zahlen geschlossen. Es ist nicht möglich, zu versprechen, dass es keine weiteren Lücken gibt, und kein solches System sollte etwas anderes suggerieren. „Das Modell hat in der Regel recht“ ist keine Grundlage für Zuverlässigkeit – gerade das Wort „in der Regel“ versagt bei den wirklich wichtigen Fragen.