Merge commit 'cfaf67010017eab368216aded483a64126dbcb2e' as 'bahn/wissensdatenbank'
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
# 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
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
# Changelog & Versionierung (verbindlich)
|
||||
|
||||
Diese Regel steuert, **wann und wie** `CHANGELOG.md` und `VERSION` zu pflegen sind.
|
||||
Sie gilt fuer jede Code-/Config-/Doku-Aenderung in diesem Repo.
|
||||
|
||||
## Single Source of Truth
|
||||
- **`VERSION`** (Repo-Root): genau eine Zeile, `MAJOR.MINOR.PATCH` (SemVer).
|
||||
- **`CHANGELOG.md`** (Repo-Root): Format „Keep a Changelog". Oben steht immer ein
|
||||
Abschnitt `## [Unreleased]`.
|
||||
- Die GitLab-Pages-Seite **„Changelog"** (`changelog.html`) wird aus `CHANGELOG.md`
|
||||
erzeugt; `src/site.py` zeigt die `VERSION` in der Navigation an. Beides wird beim
|
||||
Pages-Build automatisch aktuell – **es ist also keine HTML-Datei von Hand zu pflegen**,
|
||||
nur `CHANGELOG.md` und `VERSION`.
|
||||
|
||||
## Bei JEDER inhaltlichen Aenderung (vor dem Commit)
|
||||
Trage einen kurzen, nutzerverstaendlichen Eintrag unter `## [Unreleased]` ein,
|
||||
gruppiert in **Added** / **Changed** / **Fixed** (bei Bedarf **Removed**):
|
||||
|
||||
```
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- <was neu ist>
|
||||
### Fixed
|
||||
- <was korrigiert wurde>
|
||||
```
|
||||
|
||||
Reine interne Nebensaechlichkeiten (Tippfehler in Kommentaren o.ae.) muessen nicht
|
||||
ins Changelog.
|
||||
|
||||
## Beim Abschluss eines Merge Requests (Release schneiden)
|
||||
Wenn ein MR gemergt werden soll und `[Unreleased]` Eintraege enthaelt:
|
||||
|
||||
1. **Version bestimmen** (SemVer, ausgehend vom aktuellen `VERSION`):
|
||||
- **MAJOR** +1: inkompatible Aenderung an Datenmodell/Frontmatter/Output-Struktur
|
||||
(`output/processed/<scope>/<domaene>`), an Strategien-Semantik oder Pipeline-Verhalten.
|
||||
- **MINOR** +1: neue Strategie/Quelle/Funktion/Seite, abwaertskompatibel.
|
||||
- **PATCH** +1: Bugfix, Doku, kleine Korrektur.
|
||||
2. **`VERSION`** auf die neue Nummer setzen.
|
||||
3. In `CHANGELOG.md` den Block `## [Unreleased]` in `## [X.Y.Z] - JJJJ-MM-TT`
|
||||
umbenennen (Datum = heute) und **einen neuen leeren `## [Unreleased]`** darueber anlegen.
|
||||
4. Commit-Message: `chore(release): vX.Y.Z`.
|
||||
|
||||
## Hinweise
|
||||
- Im Zweifel die kleinere Erhoehung waehlen (lieber MINOR als MAJOR), aber
|
||||
inkompatible Aenderungen ehrlich als MAJOR markieren.
|
||||
- Den automatischen Daten-Commit des Bots (`chore(data): ...`) NICHT versionieren –
|
||||
er aendert nur `data/`, nicht Code/Verhalten.
|
||||
- Wird die Output-/Frontmatter-Struktur geaendert, zusaetzlich `.kiro/steering/architecture.md`,
|
||||
`README.md` und Tests anpassen (siehe AGENTS.md).
|
||||
Reference in New Issue
Block a user