Wir extrahieren Text und sagen klar, wenn wir es nicht können
Aus reinem Text, Markdown, Logs, CSV, JSON, DOCX und PDF. DOCX wird als Archiv entpackt und das darin enthaltene XML-Dokument gelesen; PDF durchläuft den Standard-Extractor mit Erhalt des Seitenlayouts, und falls dieser fehlt, gibt es eine Reserve, die die Textoperatoren direkt aus der Datei liest. Der wichtige Fall ist der, in dem es nicht funktioniert: Ein gescanntes PDF, das ein Bild ist, enthält keinen auswählbaren Text, und das System gibt eine explizite Meldung zurück — laden Sie DOCX oder Text hoch, oder lassen Sie die Datei vorher per optischer Erkennung verarbeiten. Optische Erkennung haben wir nicht implementiert und tun auch nicht so, als hätten wir sie.
Wir teilen in Fragmente mit Überlappung, schneiden zwischen Sätzen, nicht durch sie hindurch
Die Standardwerte, die wir verwenden: 500 lexikalische Einheiten mit 50 Überlappung für die Sprach-Pipeline, 1.200 Zeichen mit 150 Überlappung für die Text-Pipeline; auf der Sprach-Anbieterseite 500 mit 100. Die Überlappung existiert, weil ein Satz, der mitten zwischen zwei Fragmenten abgeschnitten wird, für beide unbrauchbar wird. Der Satztrenner ist für die Sprachen geschrieben, mit denen wir arbeiten: Er erkennt das Satzende, gefolgt von einem lateinischen **oder kyrillischen** Großbuchstaben, einschließlich der rumänischen Diakritika. Ein für Englisch geschriebener Trenner schneidet auf Rumänisch schlecht und auf Russisch noch schlechter.
Wir indexieren mit Vektoren dort, wo wir es gestartet haben, und sagen, wo nicht
Das Standarddarstellungsmodell ist `text-embedding-3-small` mit 1.536 Dimensionen, angefordert über unser Modell-Gateway, nicht direkt beim Anbieter — so kann der Anbieter gewechselt werden, ohne den Code der Wissensbasis anzutasten. In der Datenbank ist die Spalte vom Typ Vektor mit `ivfflat`-Index auf Kosinusdistanz. In der Migration gibt es eine Reserve-Strategie: Wenn die Vektorerweiterung nicht verfügbar ist, wird das Schema jederzeit mit Trigramm-Index auf Text erstellt, und das Retrieval schaltet auf lexikalische Ähnlichkeit um. Das ist nicht hypothetisch — es wurde genau deshalb geschrieben, weil die Rechte für die Erweiterung nicht auf jeder Installation garantiert sind.
Hybrides Retrieval, mit den Gewichten sichtbar
Der Endscore besteht zu 0,7 aus der Vektorähnlichkeit plus zu 0,3 aus der Wortübereinstimmung, mit normalisiertem lexikalischem Anteil. Es wird ein Satz von Kandidaten bewertet und die ersten Fragmente werden behalten, und der an das Modell gesendete Kontext schneidet jedes Fragment auf eine maximale Länge zu, damit ein einzelnes langes Dokument nicht den ganzen Platz belegt. Die Konfiguration ist pro Assistent, in der Basis: Abruf ein- oder ausgeschaltet, maximale Anzahl von Fragmenten pro Frage (standardmäßig 5, begrenzt zwischen 1 und 20), Ähnlichkeitsschwelle, Suchtyp — semantisch, lexikalisch oder hybrid — und die Gewichtung des lexikalischen Anteils.
Das Genehmigungstor: Wissen wächst aus Lücken, mit einem Menschen in der Schleife
Wenn der Agent antwortet, dass er die Information nicht hat, wird die Frage in eine Tabelle mit dem Status „wartend“ geschrieben, markiert mit dem Kanal, aus dem sie kam — Sprache oder Widget. Ein Mensch erhält die Benachrichtigung und antwortet direkt auf die Nachricht; ein Webhook übernimmt die Antwort, setzt den Eintrag auf den Status „genehmigt“, und von dort gelangt er in den Kontext des Agenten. Die möglichen Stati sind vier: wartend, genehmigt, ignoriert, dupliziert — und die Duplikate werden über eine Referenz mit der ursprünglichen Frage verknüpft, damit sich nicht zehn Formulierungen desselben Mangels ansammeln. Die Auslieferung an den Agenten erfolgt einmalig pro genehmigtem Eintrag.
Auffrischung: was passiert, wenn sich die Quelle ändert
Beim Hinzufügen wird der SHA-256-Fingerabdruck des Inhalts berechnet; wenn der Text mit etwas bereits Indexiertem identisch ist, wird er wiederverwendet und es wird keine neue Vektorrepräsentation bezahlt. Wenn das Dokument geändert wird, werden seine Fragmente vollständig gelöscht und neu geschrieben — vollständiger Austausch pro Quelle, keine partielle Aktualisierung, weil eine partielle Aktualisierung verwaiste Fragmente aus der alten Version zurücklässt, und genau diese erzeugen Antworten, die dem Website-Inhalt widersprechen. Die Quelle hat einen sichtbaren Zustandszyklus: wartend, in Bearbeitung, in Reprozessierung, bereit oder fehlgeschlagen, und die Neuindexierung kann punktuell pro Quelle angefordert werden.
Wir indexieren nichts neu, was sich nicht geändert hat
In einer Schleife, die alle dreißig Minuten über eine Liste läuft, die nur wächst, ist die Neuberechnung der Repräsentation für ein unverändertes Element eine wiederkehrende Zahlung für einen Vektor, der sich nicht hätte bewegen können. Unsere Schleife vergleicht den Zeitpunkt der letzten Änderung mit dem Zeitpunkt der letzten Indexierung und überspringt das Unveränderte. Die Repräsentationen werden in Batches angefordert, nicht einzeln. Das sind Kostendetails, aber die monatlichen Kosten einer Wissensdatenbank werden hier fast vollständig entschieden.
Ein angebundenes Katalogsystem ist keine geladene Liste
Der Unterschied liegt nicht im Format, sondern im Zeitpunkt. Eine geladene Liste ist zum Zeitpunkt des Ladens wahr: Preis, Bestand und neue Produkte bleiben eingefroren, bis sich jemand erinnert, erneut zu laden — und meist stellt man fest, dass sich niemand erinnert, wenn ein Kunde nach einem Preis fragt, der drei Monate alt ist. Ein angebundener Katalog wird zum Zeitpunkt der Frage aus der Quelle gelesen, die die Daten führt. Was wir in diese Richtung gebaut haben: ein Extraktor, der Produktkollektionen in JSON oder CSV anhand der üblichen Schlüssel erkennt und, wenn die Struktur unüblich ist, die Hilfe eines Modells anfordert, das strikt in einer vorgegebenen Form antworten muss; und ein Parser, der den Preis aus der Live-Seite des Shops liest. Der beste Weg bleibt die eigene strukturierte Schnittstelle des Shops, wo sie existiert — aber sie wird pro Shop geprüft, nicht vorausgesetzt.
Das Durchsuchen einer Website: erst die Karte, dann die Erkundung
Zuerst wird nach der Sitemap in den üblichen Namensvarianten gesucht, und verschachtelte Karten auf zwei Ebenen werden entfaltet. Nur wenn keine Sitemap vorhanden ist, wird zur Breitensuche übergegangen, strikt auf derselben Origin, mit einer konfigurierbaren Seitenlimitierung (standardmäßig 50, gedeckelt bei 200). Die tatsächlich verwendete Strategie wird zurückgemeldet — Sitemap oder Erkundung —, denn daraus liest man ab, ob ein armes Ergebnis von der Website oder von der Methode kommt. Die Ausschlussdatei der Website wird beachtet.