Files

161 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```