git-subtree-dir: bahn/wissensdatenbank git-subtree-split: 07a8196e5f9e55d027f90485beb95f4006387669
161 lines
8.3 KiB
Markdown
161 lines
8.3 KiB
Markdown
# Architektur & Wissensfluss (Steering)
|
||
|
||
Diese Datei ist die verbindliche Referenz dafuer, **was mit dem Wissen passiert**.
|
||
Bei jeder Aenderung am Datenfluss (neue Connectoren, Filter, Gates, Ziele) ist
|
||
dieses Dokument inkl. der Diagramme zu aktualisieren.
|
||
|
||
## Ziel
|
||
|
||
Klar definieren, **welches Wissen in Chatbots darf und welches nicht**. Klassifikation
|
||
nach Scope: **allgemein** (intern UND extern, nicht toolspezifisch), **intern** (nur DB
|
||
InfraGO intern), **extern** (public / fuer EVUs/EIUs). Aufgenommenes Wissen wird
|
||
verarbeitet und als `output/processed/<scope>/...` fuer Chatbots/Vektor-DB bereitgestellt.
|
||
|
||
## Grundprinzipien
|
||
|
||
- **Denken in Tools**: Jede Wissenseinheit gehoert zu einem Tool und einer Domaene.
|
||
- **Scope ist Pflicht**: `intern | extern | allgemein` (allgemein = intern UND extern).
|
||
- **Nur freigegebenes Wissen verlaesst die Pipeline** (`review_status: approved`).
|
||
- **Repo = Single Source of Truth**: Ergebnis liegt versioniert in `output/processed/`.
|
||
|
||
## Context-Diagramm (C4 Level 1)
|
||
|
||
```mermaid
|
||
graph TD
|
||
subgraph Quellen
|
||
CF[Confluence BES]
|
||
WEB[dbinfrago.com Kundeninfos]
|
||
PDF[INB-PDFs Regulierung]
|
||
end
|
||
|
||
ETL[Wissens-ETL-Pipeline]
|
||
|
||
subgraph Repo [Git-Repo = Single Source of Truth]
|
||
PROC[output/processed/<scope>/<domaene>/]
|
||
RAW[staging/raw/ Roh-PDFs]
|
||
STG[staging/pending/ - versioniert fuer Transparenz]
|
||
end
|
||
|
||
VDB[(Vektor-DB / RAG)]
|
||
USER[1st-Level-Support & Kund:innen]
|
||
|
||
CF --> ETL
|
||
WEB --> ETL
|
||
PDF --> ETL
|
||
ETL --> PROC
|
||
ETL --> RAW
|
||
ETL --> STG
|
||
PROC --> VDB
|
||
VDB --> USER
|
||
```
|
||
|
||
## Datenfluss (Freigabe + ETL)
|
||
|
||
Die **Freigabe** ist der Merge Request (Mensch, 4-Augen via CODEOWNERS): er entscheidet,
|
||
welche Quelle mit welchem Scope aufgenommen wird. Der **Auto-Filter** danach ist ein
|
||
**Sicherheitsnetz** (kein Freigabe-Knopf) – standardmaessig wird approved.
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
MR[Merge Request<br/>Mensch: 4-Augen] --> E[Extract<br/>connectors/]
|
||
E --> T[Transform<br/>md_converter, tagger]
|
||
T --> G1{Auto-Filter<br/>content_filter}
|
||
G1 -->|approved = Default| REL[output/processed/ - live]
|
||
G1 -->|pending: Blacklist/zu kurz| RV[staging/pending]
|
||
RV -->|approvals.yaml Korrektur| REL
|
||
REL --> VDB[(Vektor-DB liest output/processed/<scope>/)]
|
||
```
|
||
|
||
## Wo liegt welches Wissen?
|
||
|
||
**Klare Trennung in zwei Top-Level-Ordner:**
|
||
- `output/` = **was raus darf** (Konsumenten-Feed). Eine einzige Regel: „lies aus `output/`, ignoriere alles andere".
|
||
- `staging/` = **intern** (Sichtung, Audit, optionale Roh-PDFs). Kein Wissen, das ein Anschliesser einlesen sollte.
|
||
|
||
| Pfad | Inhalt | Versioniert |
|
||
|------|--------|-------------|
|
||
| `output/processed/<scope>/<domaene>/[<tool>/]` | freigegebenes Wissen (Markdown) | ja |
|
||
| `staging/raw/<domaene>/` | heruntergeladene Roh-PDFs | ja |
|
||
| `staging/pending/` | wartet auf manuelle Sichtung | ja (Transparenz) |
|
||
| `output/chunks/<scope>/<domaene>/<docslug>/` | abgeleitete Chunks (optional, Default aus) | ja |
|
||
| `staging/review_report.json` | Audit/Report des letzten Laufs | ja |
|
||
| `output/_meta.json` | globale Metadatei: `last_run`, `last_change`, `documents`, `by_scope`, `content_signature` (fuer nachgelagerte Systeme) | ja |
|
||
| `output/_index.json` | dokument-genauer Katalog: pro Voll-Dokument Domaene/Tool/Scope, `last_updated`, `content_hash`, `kind` (`document`/`attachment`) und - falls vorhanden - die zugehoerigen Chunks (Anzahl/Pfad) und Anhang-Dokumente (Name/Pfad); Aggregate `documents_total`, `chunks_total`, `attachments_total`, `by_domain`, `by_scope` | ja |
|
||
| `output/run_log.jsonl` | Lauf-Historie (append-only, 1 Zeile je ETL-Lauf): Zeit, verarbeitete Dokumente, Status-Counts, Fehler je Quelle (gekappt auf letzte 500) | ja |
|
||
|
||
## Klassifikation intern/extern
|
||
|
||
Es gibt **keine Inhaltstrennung pro Seite**. Klassifiziert wird pro Tool/Quelle:
|
||
|
||
1. **Tool-`scope`** in `config/tools.yaml`: `intern` | `extern` | `allgemein` | `mixed`
|
||
(mixed = Quellen mit unterschiedlichem Scope; im Zweifel zwei Seiten).
|
||
2. **Source-`scope`**: `intern` | `extern` | `allgemein` | `"intern,extern"`
|
||
(ganze Seite fuer beide, dupliziert). Quellen erben sonst den Tool-Scope.
|
||
3. **Sicherheitsnetz** (`content_filter`): vertrauliche Inhalte in `extern/allgemein`
|
||
werden hart abgelehnt (ausser `trusted: true` fuer oeffentliche Quellen wie INB).
|
||
|
||
Allgemeines Wissen steht getrennt in `config/general.yaml`.
|
||
|
||
## Komponenten
|
||
|
||
- `src/connectors/` Extract: confluence (inkl. eingebundene PDF-Anhaenge als
|
||
eigene Dokumente `kind: attachment` mit `parent_url`/`attachment_name`; Bilder bleiben
|
||
als `[Bild: ...]`-Text), web_crawler (crawler+sitemap), pdf_parser (direkte PDF-URL,
|
||
PDF-Links einer Seite ODER Sitemap+Regex -> jeweils neueste Version), gitlab_md, file_source
|
||
- `src/transformers/` Transform: md_converter, tagger, content_filter (Filter/Redaction),
|
||
chunker (deterministisches, embedding-freies Heading-Chunking)
|
||
- `src/review/` Gate: staging (Routing approved/pending) + **Dedup** je
|
||
`(scope, domaene, page_identity)` - gleiche Seite aus mehreren Quellen landet nur
|
||
einmal im Feed (spezifischere Aufbereitung gewinnt: FAQ > Seite)
|
||
- `src/main.py` Orchestrator (`--only` fuer Vorschau)
|
||
- `src/chunk.py` Standalone-Chunking (offline auf `output/processed` -> `output/chunks/`;
|
||
Default aus, pro Quelle ueber `options.chunk` aktivierbar; zentrale Defaults in
|
||
`config/chunking.yaml`)
|
||
- `src/strategy_detect.py` erkennt pro URL die Strategie (unbekannt -> neue Strategie noetig)
|
||
- `src/store.py` liest den Bestand aus `output/processed` + `staging/pending`
|
||
(Frontmatter-Parser); inkrementelles
|
||
Re-Tagging bestehender Dateien (`reconcile_meta`), Aufraeumen alter Ablagen nach
|
||
Scope-Wechsel (`prune_scope_orphans`) und alter Seiten-Duplikate (`prune_duplicate_files`)
|
||
- `src/quality.py` Quality-Score (0-100) pro Dokument
|
||
- `src/site.py` GitLab-Pages-Seiten -> `public/` (Uebersicht, Hilfe, Chatbot, Wissensquellen)
|
||
|
||
## Chunking (optional, abgeleitetes Artefakt)
|
||
|
||
Grosse, stark gegliederte Dokumente (v.a. INB) werden zusaetzlich zur Voll-Datei in
|
||
**Chunks entlang der Ueberschriften** zerlegt. Grundsaetze:
|
||
|
||
- **Default = AUS.** Nur Quellen mit `options.chunk != off` werden gechunkt (aktuell INB).
|
||
- **Voll-Dokument bleibt unangetastet** in `output/processed/`. Chunks sind ein
|
||
**zusaetzliches, jederzeit neu erzeugbares** Artefakt in `output/chunks/<scope>/<domaene>/<docslug>/`
|
||
(Parent-Document-Muster). Der Anschliesser waehlt: Voll-Dokument, Chunks oder beides.
|
||
- **Nur deterministische, embedding-freie** Strategien (`headings | faq | recursive`).
|
||
Semantisches Chunking gehoert in die Vektor-DB des Anschliessers (die wir nicht stellen).
|
||
- **Contextual Retrieval (Anthropic, deterministisch):** jedem Chunk wird eine kurze
|
||
Kontextzeile (`> Kontext: <Dokument> > <Abschnitt>`) vorangestellt - ohne LLM/Embedding.
|
||
- Gemeinsame Defaults in **`config/chunking.yaml`**, pro Quelle in `options` ueberschreibbar.
|
||
Drei wichtige Feinsteuerungen (Default jeweils aus):
|
||
`chunk_min_doc_chars` (Dokumente unter dieser Zeichenzahl bleiben ganz),
|
||
`chunk_kind` (`""` alle, `"attachment"` nur Anhang-PDFs, `"document"` nur Voll-Seiten) und
|
||
`chunk_component` (`""` alle, sonst nur dieser component_type, z.B. `"faq"`).
|
||
**Mehrere Konfigurationen je Ort** sind erlaubt: pro Dokument greift die erste passende
|
||
(Filter `chunk_kind`/`chunk_component`).
|
||
- **Aktive Konfigurationen:** INB 2026/2027 (`chunk: headings`), pathOS am Ort `*/pathos`
|
||
zweigleisig: Anhang-PDFs via `chunk: headings, chunk_kind: attachment, chunk_min_doc_chars: 3000`
|
||
und die interne FAQ-Seite via `chunk: faq, chunk_component: faq` (ein Chunk je Frage);
|
||
normale Seiten bleiben ganz.
|
||
- **Inkrementell:** Chunking laeuft am Ende von `src.main` automatisch mit. Pro Dokument
|
||
wird nur neu gechunkt, wenn sich der Inhalt (`parent_hash`) ODER die wirksamen Optionen
|
||
(`chunk_fingerprint`, inkl. Strategie und Logik-Version `_CHUNKER_VERSION`) geaendert
|
||
haben. Deaktivierte Orte (`chunk: off`) und verwaiste Chunks (Voll-Dokument geloescht)
|
||
werden automatisch entfernt.
|
||
- Lauf: `python -m src.chunk --data output` (offline auf dem vorhandenen `output/processed`).
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
PROC[output/processed/ - Voll-Dokument] --> CK[chunker<br/>headings + Kontext-Vorspann]
|
||
CFG[config/chunking.yaml<br/>+ options.chunk je Quelle] --> CK
|
||
CK --> CH[output/chunks/<scope>/<domaene>/<docslug>/]
|
||
PROC --> VDB[(Vektor-DB: waehlt processed ODER chunks ODER beides)]
|
||
CH --> VDB
|
||
```
|