Repository navigation
Chat und Bots
Diese Seite ordnet ein, wie aus einer Frage im Chat eine belegte Antwort wird
und woher die Bots stammen, die dabei antworten. Sie ersetzt keine der
massgeblichen Beschreibungen: der Ablauf steht feldgenau in
contracts/internal-chat.md,
die Bot-Konfiguration in
services/runtime/README.md,
die Betriebsseite in
docs/betrieb.md.
Vier Dienste sind an einem Chat-Turn beteiligt, in dieser Reihenfolge.
-
Weave Chat (
services/chat) ist die Weboberfläche. Sie hat keine Datenbank und genau einen Upstream: das Gateway. Sie ruft weder Runtime noch Retrieval direkt auf. -
Weave-API (
services/api) ist das Gateway: Anmeldung, Rate-Limit, Konversations-Verlauf in PostgreSQL. Chat-Intelligenz gehört ausdrücklich nicht dazu. -
Weave-Runtime (
services/runtime) ist der Bot-Orchestrator: Intent-Routing, Bot-Auswahl, Rechte-Schnittmenge, LLM-Aufruf, Response Guard. Sie ist zustandslos und speichert nichts. -
Weave-Retrieval (
services/retrieval) ist die Suche. Sie wird nur aufgerufen, wenn der Turn sie tatsächlich braucht.
Die Trennung ist der Grund dafür, dass ein Fehlerbild oft weit vom Symptom
entfernt liegt: eine Antwort ohne Quellen kann eine Router-Entscheidung sein,
eine leere Rechte-Schnittmenge, ein leerer Index oder eine nicht erreichbare
Suche. Der trace, den jede Antwort mitliefert, unterscheidet diese Fälle;
wie man ihn liest, steht in
docs/betrieb.md, Abschnitt 10.
Bevor irgendetwas durchsucht wird, klassifiziert der Intent-Router die Nachricht
in einen von fünf Intents: conversational, knowledge, document, action,
complex. Nur knowledge führt überhaupt zu einer Suche. conversational geht
direkt ans Modell und liefert bewusst keine Quellen. document, action und
complex beantwortet ein LLM-Bot in dieser Version mit einem festen Hinweistext,
ohne Modellaufruf — bei einem n8n-Bot dagegen werden genau diese Intents an den
Flow weitergereicht.
Zwei Punkte, die regelmässig missverstanden werden:
- Der Router läuft in zwei Modi (
ROUTER_MODE):rulesist der Standard, ein deterministischer Schlüsselwort-Klassifikator ohne Netzaufruf;llmdelegiert die Klassifikation an ein Modell und fällt bei jedem Fehler aufruleszurück, statt den Turn scheitern zu lassen. - Eine Router-Entscheidung für
knowledgegenügt nicht, damit gesucht wird. Zusätzlich muss der Bot selbst Retrieval aktiviert haben. Ein Bot ohne Wissensanbindung löst nie einen Such-Aufruf der Runtime aus, egal wie die Frage lautet. Für einen n8n-Bot gilt das anders herum: Runtime sucht dort grundsätzlich nicht selbst, der Flow sucht mit seinem Delegations-Token.
Wer also glaubt, der Bot habe den Index nicht gefunden, sollte zuerst
trace.intent ansehen: conversational bei einer Wissensfrage heisst, dass gar
nicht gesucht wurde.
Weave-Retrieval ist eine Hybrid-Suche. In Stichworten:
- Vektorsuche (pgvector) und Volltextsuche laufen parallel über denselben
Korpus, jeweils bis
top_kTreffer. - Reciprocal Rank Fusion kombiniert beide Ranglisten allein über die Rang-Position, nicht über die Rohscores — Cosine-Similarity und Volltext-Rang sind nicht vergleichbar. Ein Chunk, den beide Signale finden, gewinnt fast immer.
-
Reranking ist optional (
noneals Vorgabe, daneben ein Test-Provider und ein Cohere/Jina-kompatibler API-Provider). Ein Reranker-Ausfall lässt die Suche nie scheitern: sie fällt auf die Fusions-Reihenfolge zurück und markiert das im Trace. - Erst nach dem Reranking wird auf
final_kgekürzt. Ein Reranker kann eine Kandidatenmenge nur verkleinern, nie vergrössern.
Die vollständige Pipeline samt Parametern, Trace-Feldern und Fehlerbildern steht
in services/retrieval/README.md.
Bei aktiviertem Retrieval erzwingt der Guard eine belegte Antwort. Findet die Suche nichts Verwertbares, antwortet der Bot mit einem festen Text statt mit einer vom Modell erfundenen Antwort. Das ist die Vorgabe, nicht eine Option, die erst eingeschaltet werden muss.
Der Trace nennt drei unterschiedliche Gründe, und die Unterscheidung ist der eigentliche Nutzen:
-
no_context— gesucht wurde, gefunden wurde nichts. -
no_collections— es gab von vornherein keinen Wissensbereich, den dieser Bot und dieser Mensch beide nutzen dürfen. Es wurde gar nicht erst gesucht. -
filter_excluded_all— die Rechte hätten gereicht, aber die eigene Auswahl in der Seitenleiste hat den Suchraum geleert. Das ist der einzige der drei Fälle, den der Fragende allein beheben kann.
Zwei Dinge, die der Guard ausdrücklich nicht tut: er weicht beim Streaming nicht auf. Ein Guard-Text wird als gewöhnlicher Textstrom ausgeliefert, die Quellenpflicht bestimmt nur, welcher Text gestreamt wird. Und er springt nicht für einen Ausfall ein: ist Weave-Retrieval nicht erreichbar, antwortet Runtime mit einem Fehler, nie mit einer stillen, unbelegten Antwort.
Bei einem n8n-Bot gilt die Quellenpflicht in der Gegenrichtung. Was ein Flow als
Quelle zurückmeldet, ist eine Behauptung. Weave prüft jede gemeldete Quelle gegen
den signierten Umfang des Delegations-Tokens und verwirft, was nicht passt; die
verworfenen Einträge stehen im Trace. Details in
contracts/n8n-flow.md.
In der Seitenleiste lassen sich Wissensbereiche auswählen. Das ist ein Filter für die nächste Nachricht, keine Rechtevergabe. Die Auswahl schneidet nur von dem ab, was ohnehin lesbar wäre; sie kann nichts hinzufügen. Keine Auswahl bedeutet kein Filter, also alles, was erlaubt ist — nicht "nichts".
Die Autorität liegt serverseitig: Runtime bildet die Schnittmenge aus den Bereichen, die der Bot nutzen darf, und denen, die der anfragende Mensch laut seinem Team lesen darf. Ein Bereichsname aus einem Anfrage-Feld, einem Tool-Argument oder einer Modell-Ausgabe ist immer nur eine Einschränkung innerhalb dieser Schnittmenge. Wie Leserechte an Wissensbereichen entstehen, steht unter Wissensbereiche-und-Freigaben und Rechte-und-Sichtbarkeit.
Runtime stellt die Bot-Liste vor jeder Anfrage neu zusammen, aus zwei Quellen.
Bots als YAML-Dateien in Runtimes Bot-Verzeichnis (BOTS_DIR). Im
Compose-Betrieb ist das das Volume runtime_bots, das Docker beim ersten Mount
aus den Beispiel-Bots des Images befüllt; Dateien dort werden pro
Anfrage neu gelesen, ein Neustart ist nicht nötig. Feld-für-Feld-Beschreibung
eines Bots — Modell, Prompt, Retrieval, erlaubte Teams, Guard — in
services/runtime/README.md,
Volume-Details in
deploy/README.md.
Seit v0.1.0 werden n8n-Bots nicht mehr als Datei auf der Platte gepflegt, sondern zentral in Weave-Ingest unter Administration → Bots: Anzeigename, Webhook-Adresse, optionales Flow-Token, Timeout, erlaubte Teams und Wissensbereiche. Runtime holt die aktivierten Einträge pro Anfrage über ein eigenes Service-Token ab. Das Flow-Token liegt verschlüsselt in Ingest und verlässt es nur über diese interne Route.
Der Grund für den Umzug: eine Änderung gilt ab der nächsten Anfrage, ohne dass jemand eine Datei in einem Container bearbeitet oder einen Pod neu startet. Und Team- sowie Bereichsauswahl in der Maske sind, wie überall, reine Einschränkungen — Runtime schneidet weiter mit den Rechten des Fragenden.
Beide Quellen werden gegen dasselbe Bot-Schema und dieselbe Webhook-Allowlist geprüft. Die Allowlist greift dabei beim Zusammenstellen der Liste, nicht erst beim ersten Aufruf, und für beide Quellen gleich: weder eine Konfigurationsdatei noch ein Administrator soll den Dienst in ein beliebiges Netz rufen lassen können. Ist die Allowlist leer, sind n8n-Bots abgeschaltet.
Kollidieren die Quellen, gewinnt die Zentrale: trägt ein zentraler Eintrag dieselbe Bot-ID wie eine lokale YAML-Datei, überschreibt der zentrale Eintrag die lokale Definition. Eine lokale Datei ist damit ein Ausgangspunkt oder ein Rückfall, nie ein stiller Konkurrent zur gepflegten Version.
Die zentrale Anbindung ist bewusst nicht ausfalltolerant. Sind die beiden Werte
für Adresse und Service-Token gesetzt und Ingest antwortet nicht oder liefert
Unbrauchbares, scheitert die gesamte Bot-Liste — auch die lokalen YAML-Bots.
Runtime meldet sich degraded, /v1/bots antwortet über das Gateway mit 502,
und jeder Chat-Turn hängt damit an der Erreichbarkeit von Ingest.
Das ist gewollt: eine halb alte, halb neue Bot-Definition wäre schlimmer als gar keine. Es heisst aber, dass Ingest für den Chat kritisch wird, sobald die zentrale Konfiguration eingeschaltet ist. Sind beide Werte leer, läuft Runtime eigenständig weiter, nur mit den YAML-Bots. Die vollständige Begründung samt Symptomtabelle steht in docs/betrieb.md, Abschnitt 9.
Unter Administration → Chat & LLM gibt es neben dem zentralen Endpunkt weitere, benannte LLM-Endpunkte, zum Beispiel ein Modell mit nativen Tool-Aufrufen. Pro Bot gilt:
- LLM-Endpunkt legt fest, womit der Bot antwortet. Leer heisst: der zentrale Endpunkt.
- Im Chat zur Auswahl anbieten lässt Nutzer pro Chat zwischen diesem und weiteren Endpunkten wählen; im Chat erscheint dann neben dem Eingabefeld eine Auswahl Sprachmodell. Alle aktiven Endpunkte bietet jeden aktivierten an. Ohne Eintrag gibt es keine Auswahl.
- Ein Subagent im Agentenmodus kann einen eigenen Endpunkt nutzen. Zur Wahl stehen nur Endpunkte, die Tool-Aufrufe unterstützen.
YAML-Bots tragen dieselben Angaben als model.endpoint und model.endpoints
(['*'] = alle aktiven). Runtime prüft jede Auswahl gegen die Liste des Bots;
einen Endpunkt, den ein Bot noch verwendet, lässt Ingest nicht löschen.
n8n-Bots bleiben bei dem Modell, das ihr Flow vorgibt.
-
"Der Bot findet unser Dokument nicht." Meistens ist das keine Suchqualität,
sondern eine Stufe davor: kein
knowledge-Intent, kein Retrieval am Bot, keine gemeinsame Bereichs-Schnittmenge, oder das Dokument ist nie freigegeben worden. Siehe Wissensbereiche-und-Freigaben. - "Die Auswahl in der Seitenleiste gibt mir Zugriff." Sie schränkt nur ein. Rechte entstehen ausschliesslich über Team und Wissensbereich.
- "Bots konfiguriert man im Chat." Die Oberfläche listet nur, was das Gateway zurückgibt. Gepflegt werden Bots in Runtimes Bot-Verzeichnis oder zentral in Ingest.
-
"Antworten beginnen mit
[fake-llm], das ist ein Bug." Das ist der Vorgabe-Provider für Entwicklung und Tests. Echte Provider einrichten: Betrieb.
- Wissensbereiche-und-Freigaben — wie Inhalte überhaupt durchsuchbar werden
- Rechte-und-Sichtbarkeit — woher die Schnittmenge kommt, die jeden Turn begrenzt
- Betrieb — Provider, Anmeldung, Selbsttest
-
contracts/internal-chat.md— der Chat-Turn feldgenau, inklusive Trace und Guard-Gründen -
contracts/n8n-flow.md— Delegations-Token, Signaturprüfung, Quellenprüfung in der Gegenrichtung
Einstieg
Konzepte
Betrieb
Im Repository