feat(kb): ingest rechtsprechung corpus

This commit is contained in:
2026-09-15 15:27:28 +02:00
parent 1594aa9cbd
commit 5209539ba3
365 changed files with 33112 additions and 51 deletions
+24 -8
View File
@@ -1,10 +1,10 @@
# PV RAG Agent
Lokaler RAG-Agent für österreichische Personalverrechnung: beantwortet
Fragen **ausschließlich** aus der kuratierten Wissensbasis (Layer 2,
`wissensbasis/`, **1274 Einträge**: 601 lb/wk-Kuratierung + 614 WKO-KV-
Dokumente + 59 RIS-Gesetze) — mit ID- und Stand-Beleg, ohne
Trainingswissen, ohne Web-Zugriff. Verbindliche Regeln:
Fragen **ausschließlich** aus der Wissensbasis (Layer 2,
`wissensbasis/`, **1622 Einträge**: 601 lb/wk-Kuratierung + 614 WKO-KV-
Dokumente + 59 RIS-Gesetze + 348 Rechtsprechungs-/Normquellen) — mit ID-
und Stand-Beleg, ohne Trainingswissen, ohne Web-Zugriff. Verbindliche Regeln:
`.agents/skills/pv-rag-agent/SKILL.md`, Plan: `planung.md`.
## Architektur (Kurzfassung)
@@ -180,6 +180,19 @@ Report: `data/eval-qwen38-lengthfix.json`. Offene Restfälle: keine
Fehlverweigerungen/Verletzungen mehr; 3-4 Fragen zitiert gültige,
aber nicht die erwartete Quelle (q-015-Klasse).
**Rechtsprechungs-Intake (2026-09-15, D15):** Korpus 1.274 → **1.622**
Einträge: 320 RIS-OGD-Entscheidungen/Rechtssätze, 23 zitierte RIS-
Normauszüge und 5 als nichtamtlich markierte EuGH-Textwiedergaben im neuen
`rj-rjs-*`-ID-Raum. Der Reindex erzeugte **16.480 Chunks** (1.496 neue
`bge-m3`-Embeddings, 75 s). Retrieval mit dem erweiterten 50-Fragen-Goldset:
Hit-Rate **0,956** · Recall@8 **0,922** · MRR 0,661; das Recall-Gate >0,9
bleibt erfüllt, alle vier neuen Rechtsprechungsfälle werden gefunden. Vier
gezielte Antwortläufe (q-120123) sind zitiergültig, ohne Verweigerung und
ohne Regenerierung; der volle Antwortmodus-Eval für den erweiterten Korpus
steht noch aus. EuGH-Texte sind im Kontext und in der Quelle explizit als
nichtamtliche lexetius-Wiedergabe gekennzeichnet; der Systemprompt verlangt
nun dieselbe Einschränkung auch in der Antwort.
## Dateien
```
@@ -196,7 +209,7 @@ agent/
eval/ goldset.yaml + evaluate.py
web/index.html Minimaler Test-Chat
tools/ Intake + Registry (build_registry.py, ingest_sources.py)
tests/ 49 Tests (offline, Fake-Ollama)
tests/ 64 Tests (offline, Fake-Ollama)
data/ index.db (gitignored)
```
@@ -208,6 +221,9 @@ python -m pytest -q # 49 Tests, alle offline
## Lizenz-Disziplin
`.lexis360/`, `.wiku/`, `.firecrawl/`, `.ris/` sind lokal und unversioniert
(`.gitignore`). Der Index enthält ausschließlich Layer-2-Kuratierung;
Layer-1-Prompts wären ein Lizenzverstoß und sind im Code nicht vorgesehen.
`.lexis360/`, `.wiku/`, `.firecrawl/`, `.ris/`, `.rechtsprechung/` sind lokal
und unversioniert (`.gitignore`). Der Index enthält ausschließlich Layer-2-
Inhalte; Layer-1-Prompts wären ein Lizenzverstoß und sind im Code nicht
vorgesehen. Die quellentreuen `rj_*.md` sind vor einer Versionierung anhand
von Provenance und Lizenzfreigabe der gelieferten Volltexte zu prüfen; die
EuGH-Wiedergaben sind ausdrücklich nicht amtlich.
+16
View File
@@ -146,6 +146,22 @@ questions:
expect_refusal: true
note: "Branche nicht im KV-Korpus — Retrieval darf nicht leer sein, Antwort muss verweigern."
# --- Rechtsprechung / Normauszüge (Batch rj 1, 2026-09-15) ---
- id: q-120
question: "Rechtfertigt eine schriftliche Rüge eines Hauptbuchhalters den vorzeitigen Austritt?"
expected_ids: [rj-rjs-020]
note: "OGH-Rechtssatz; nur die konkret dokumentierte Rüge und Verschuldensabwägung behaupten."
- id: q-121
question: "Was entschied der Verfassungsgerichtshof zur Strafbestimmung des AVRAG bei nicht bereitgestellten Lohnunterlagen?"
expected_ids: [rj-rjs-006]
- id: q-122
question: "Wann ist das fortlaufende Gehalt nach § 15 AngG zu zahlen?"
expected_ids: [rj-rjs-333]
- id: q-123
question: "Welche Bedeutung hat nach EuGH C-29/91 der Übergang von Tätigkeiten nach einer Subventionsverlagerung?"
expected_ids: [rj-rjs-002]
note: "Nur als nichtamtliche lexetius-Textwiedergabe im Korpus; Antwort muss den Stand 1992-05 führen."
# --- Komplexe Fragen (Stufe 1, M6: Multi-Query + Temporal-Intent) ---
- id: q-110
question: "Wie hoch war der kollektivvertragliche Mindestmonatslohn für angelernte Friseurinnen und Friseure ab 1.4.2023?"
+4 -2
View File
@@ -54,8 +54,10 @@ Verbindliche Regeln:
allgemeine Aussage für die im Kontext vertretenen Fälle und frage am
Ende in EINEM kurzen Satz nach dem fehlenden Kontext. Verweigere in
diesem Fall nicht.
10. Ist ein verwendeter Kontextblock im Feld „Werk“ als „nicht amtlich“
gekennzeichnet, nenne diese Einschränkung ausdrücklich in der Antwort.
Verletze Regel 2 oder Regel 4 niemals — im Zweifel verweigere die Antwort."""
Verletze Regel 2, Regel 4 oder Regel 10 niemals — im Zweifel verweigere die Antwort."""
MAP_SYSTEM_PROMPT = """Du destillierst Wissensbasis-Kontextblöcke für eine Folgesynthese.
Erstelle für JEDEN Kontextblock 1-3 prägnante Stichpunkte. Beginne jede
@@ -63,7 +65,7 @@ Zusammenfassung mit der Zeile "[<KB-ID>] <Kurzthema>:" — verwende exakt
die KB-ID aus dem Block-Kopf. Behalte konkrete Werte mit ihrem Stand.
Lasse keinen Block aus; keine Einleitung, keine Schlussbemerkung."""
CITE_RE = re.compile(r"\b(?:lb|wk|kv|ris)-[a-z0-9]+-\d+\b")
CITE_RE = re.compile(r"\b(?:lb|wk|kv|ris|rj)-[a-z0-9]+-\d+\b")
_THINK_RE = re.compile(r"<think>.*?</think>", re.DOTALL)
+1 -1
View File
@@ -13,7 +13,7 @@ from pathlib import Path
import yaml
ID_RE = re.compile(r"^(lb|wk|kv|ris)-[a-z0-9]+-\d+$")
ID_RE = re.compile(r"^(lb|wk|kv|ris|rj)-[a-z0-9]+-\d+$")
STAND_RE = re.compile(r"^\d{4}-\d{2}$")
REQUIRED_KEYS = (
"id", "batch", "title", "work", "chapter", "topic", "author",