Planung und Skills für den Wissensbasis-RAG-Agenten

planung.md: Architektur (schlanker RAG-Service, SQLite-Index, Hybrid-Retrieval),
verbindliche Grounding-Regeln, Modell-Bake-off M3 (qwen3.8:27b, qwen3:32b,
gemma3:27b, mistral-small3.2:24b, qwen3:14b als Latenz-Untergrenze),
Meilensteine M1-M4 und Odoo-Integrationsoptionen.

.agents: neuer Skill pv-rag-agent (verbindliche Regeln für die Implementierung)
sowie bestehende Projekt-Skills (agent-memory, wissensbasis,
odoo19-development, opendataloader-pdf).
This commit is contained in:
2026-09-14 16:34:13 +02:00
parent 25eb285160
commit bf8191b013
10 changed files with 2776 additions and 0 deletions
+232
View File
@@ -0,0 +1,232 @@
## User
bitte plane das folgende:
Eine Wissensdatenbank und ein Agent der Fragen zu Oesterreichischer Personalverrechnung mit dem Wissen aus der Wissensdatenbank beantwortet.
Entwicklungsumgebung-GPU: AMD Radeon Ai Pro r9700 - 32GB vram
Ollama-Server: http://100.183.83.12:11435
Agent: lokales Modell (ollama): empfehle ein Modell. der Agent darf nur wissen aus der wissensbasis verwenden, kein trainingswissen, kein web search
Wissensdatenbank: bitte um einen Vorschlag fuer die Umsetzung. bereits vorhanden: [@wissensbasis](file:///home/fegger/Projects/odoo-projects/pv-agent/wissensbasis/)
in weiterer Folge soll der Agent in Odoo-Enterprise verwendet werden.
---
# Plan: Wissensbasis-Agent Österreichische Personalverrechnung
*Stand: 2026-09-14 — Planung, noch keine Implementierung.*
## 1. Ist-Zustand (verifiziert)
- **Wissensbasis** (`wissensbasis/`): **601 kuratierte Layer-2-Einträge**
(571 Lexis Briefings Personalrecht, 30 WIKU), verteilt über 69 Cluster
(`INDEX.md`). Median ~7,3 KB, max ~31 KB, gesamt ~4,8 MB — ideale
Größe für vollständige Indizierung.
- **Struktur retrieval-gerecht:** verbindliches Frontmatter-Schema
(`id`, `stand`, `topic`, `tags`, `legal_bases`, `cross_refs`, …),
`kb.json` als generierte/validierte Registry, fixer Dokumentaufbau
(`## Zusammenfassung``## Kernwerte & Fristen``## Rechtsgrundlagen`
`## Payroll-Relevanz (Odoo)``## Verweise`).
- **Layer-1-Volltexte:** `.lexis360/md/` (572 Dateien) lokal vorhanden,
lizenzbeschränkt + unversioniert. `.wiku/` fehlt in diesem Checkout —
für Phase A irrelevant (Retrieval läuft auf Layer 2).
- **Ollama-Server** `http://100.183.83.12:11435` (Custom-Port): aus der
Zed-Sandbox **nicht erreichbar** (Netzwerkrestriktion, Timeout) — ist
vom Host aus zu verifizieren (`curl http://100.183.83.12:11435/api/tags`).
- **GPU:** Radeon AI Pro R9700, 32 GB (Strix Halo / RDNA 5) — budgetiert
Modellwahl auf ~2628 GB nutzbar.
## 2. Zielbild
Ein RAG-Agent, der Fragen zur österreichischen Personalverrechnung
**ausschließlich** aus den Layer-2-Einträgen beantwortet:
- jede fachliche Aussage mit KB-ID und `stand` belegt,
- **kein** Trainingswissen, **kein** Web, **keine** Tools,
- ehrliche Verweigerung, wenn die Wissensbasis nichts hergibt,
- Korpuskonflikte (z. B. ATZ-Ersatzquote 28,5 % vs. 27,5 %, lb-atz-07/09/12)
werden **beidseitig mit ⚠** referenziert — nie still aufgelöst,
- später Chat-Oberfläche in Odoo Enterprise.
## 3. Architektur (Phase A — eigener schlanker RAG-Service)
```mermaid
flowchart TD
KB[wissensbasis/dokumente/*.md + kb.json] -->|Ingest: Frontmatter + H2-Sektionen| IDX[(data/index.db - SQLite: FTS5 BM25 + Vektoren + Metadaten)]
IDX -->|Hybrid-Retrieval: BM25 + Dense, Metadaten-Filter, cross_refs| CTX[Kontextblöcke 8-12]
CTX -->|Systemprompt: nur Kontext, Zitierpflicht| LLM[Ollama qwen3:32b]
LLM -->|Antwort-Entwurf| CHECK{Post-Validierung: zitierte IDs ⊆ retrieved IDs?}
CHECK -->|ja| A[Antwort + Quellenblock]
CHECK -->|nein, 1x| LLM
CHECK -->|nein, 2x| R[Antwort als unsicher markiert / verweigert]
A --> API[FastAPI: POST /ask, GET /health, POST /reindex]
R --> API
API --> CLI[CLI + Mini-Web-UI zum Testen]
```
**Warum kein LangChain/LlamaIndex:** 601 Dokumente, sauberes Schema —
die Pipeline ist als eigenständiger Python-Code (~400600 Zeilen)
überschaubar und gibt volle Kontrolle über die Grounding- und
Zitier-Regeln, die hier der kritische Teil sind. Frameworks würden
Abhängigkeiten einführen, ohne das Kernproblem (Grounding) abzunehmen.
**Warum Layer 2 als Retrieval-Korpus:** kuratiert, eigene Worte
(lizenzkonform), versioniert, Metadaten-annotiert. Layer-1-Volltexte
bleiben außen vor (offener Lizenz-/Provisioning-Punkt laut README);
eine spätere Erweiterung für Tiefenzitate ist möglich, ohne die
Architektur zu ändern.
## 4. Modell-Empfehlung (Ollama)
| Modell | Rolle | Größe (Q4) | Begründung |
|---|---|---|---|
| **`qwen3.8:27b`** | **primärer Bake-off-Kandidat** | ~18 GB · 256k ctx | neueste Qwen-Generation (Ollama-Library, verifiziert 2026-09); Thinking per Request abschaltbar; Vision vorhanden, hier ungenutzt |
| `qwen3:32b` | bekannte Größe / Fallback | ~20 GB | bestes Deutsch + Instruction-Following im ≤32B-Bereich; Zitierdisziplin entscheidender als Weltwissen (das wir unterdrücken) |
| `gemma3:27b` | Alternative (Bake-off) | ~17 GB | sehr gutes Deutsch, 128k Kontext |
| `mistral-small3.2:24b` | Bake-off (Deutsch-Kandidat) | ~15 GB · 128k ctx | europäischer Anbieter, Europasprachen-Fokus → starke Deutsch-Hypothese (im Bake-off verifizieren); starkes Instruction-Following + wenige Wiederholungsfehler; kein Thinking-Modus |
| `qwen3:30b-a3b` | Latenz-Alternative | ~18 GB | MoE (3,3B aktiv) → deutlich schneller, etwas schwächer |
| `qwen3:14b` | Dev/Bake-off | ~9 GB | falls Zitierqualität reicht → halbe Latenz |
| **`bge-m3`** | **Embeddings** | ~1,2 GB | multilingual (Deutsch stark), 8k Kontext, über Ollama `/api/embed` |
| `bge-reranker-v2-m3` | optionales Reranking | ~1,1 GB | Rerank-API der installierten Ollama-Version vorher verifizieren; Fallback: Hybrid-Score ohne Reranker |
**VRAM-Budget:** Antwortmodell (1520 GB) + bge-m3 (~1,5 GB) + KV-Cache für
RAG-Prompts (48k Tokens Kontext, ~16k Kontextfenster ≈ 34 GB) ⇒
~2026 GB von 32 GB — passt mit Reserve. Thinking-Modus abschalten
(Latenz; bei `qwen3.8:27b` ist Thinking Default **an** → per Request
deaktivieren, API-Option lt. Library: `reasoning_effort`,
`preserve_thinking` — beim Implementieren verifizieren).
**Empfehlung:** Bake-off-Feld (M3): `qwen3.8:27b` und `qwen3:32b`
(Front-Runner) sowie `gemma3:27b` und `mistral-small3.2:24b` als
Deutsch-Kandidaten — Deutsch-/Zitierqualität ist jeweils unverifiziert.
Verbindliche Entscheidung erst nach Bake-off auf dem Goldset — Kriterium
bleibt Zitier-Präzision vor Latenz; liegt `qwen3:14b` bei gleicher
Zitierqualität auf, gewinnt Latenz.
## 5. Grounding-Konzept (der kritische Teil)
1. **Systemprompt (deutsch):** antworte ausschließlich aus den
nummerierten Kontextblöcken; jede fachliche Aussage mit
`[kb-id]`-Beleg; Werte **immer mit** `(Stand YYYY-MM)`; fehlt etwas →
„Dazu enthält die Wissensbasis keine Aussage“ + ggf. verwandte
Cluster nennen; §-Zitate nur wenn die Quelle sie nennt; Korpus-
konflikte beidseitig mit ⚠ darstellen; keine Ergänzungen aus
Trainingswissen.
2. **Kontextblöcke** mit Metadatenkopf (ID · Titel · Stand · topic ·
Quellenwerk) — das Modell sieht nur, was im Retrieval war.
3. **Post-Validierung:** jede zitierte ID muss in der Retrieved-Menge
stehen; Verstoß → eine Regenerierung mit härterem Hinweis, dann
Verweigern/„unsicher“. Temperatur ~0,1.
4. **Kein Ausweg nach außen:** keine Tools, kein Browsing, kein
Web-Search-Hook — architektonisch gibt es nur Wissensbasis → Prompt.
## 6. Wissensdatenbank-Umsetzung (Vorschlag)
Die bestehende Wissensbasis ist bereits retrieval-gerecht — **kein
Umbau nötig**, nur ein Ingest-Index:
- **Chunking:** H2-Sektionen je Eintrag als Retrieval-Einheit (Parent-
Child: Treffer auf Sektion, Kontext = ganze Sektion + Metadatenkopf);
`Kernwerte & Fristen`-Tabellen als eigene Chunks (Zahlenfragen!);
Frontmatter im Index (topic, tags, legal_bases, stand).
- **Hybrid-Retrieval:** SQLite FTS5 (BM25; deutsche Normalisierung:
Umlaut-Folding beim Indexing) + Dense-Embeddings (bge-m3) + optional
Reranker; Reciprocal-Rank-Fusion; `cross_refs` der Top-Treffer als
kontrollierte Kontext-Erweiterung.
- **Metadaten-Filter:** `topic`-Vorfokus aus der Frage, Aktualitäts-
gewichtung über `stand`.
- **Quelle der Ingestion:** Layer-2-Frontmatter direkt (Single Source of
Truth); `kb.json` zusätzlich als Konsistenz-Gate (Anzahl/IDs müssen
matchen).
- **Update-Zyklus:** nach jedem neuen Batch einmal `POST /reindex`
(vollständiger Rebuild dauert bei 601 Einträgen Sekunden; Embeddings
gecacht, nur neue Einträge einbetten).
- **Speicherung:** eine SQLite-Datei `data/index.db` (gitignored) —
keine externe Vektor-DB nötig; Skalierungsreserve bis ~10.000
Einträge ohne Architekturwechsel.
## 7. Neue Dateien (Phase A)
```
agent/
config.py # Ollama-URL, Modellnamen, Ports (ENV-override)
ingest.py # Layer-2 → index.db (FTS5 + Vektoren via /api/embed)
retrieve.py # Hybrid-Suche + Filter + cross_refs (+ optional Rerank)
generate.py # Prompt-Bau, Ollama-Chat, Post-Validierung, Antwortformat
api.py # FastAPI: /ask, /health, /reindex
cli.py # Frage im Terminal (Dev-Loop)
eval/goldset.yaml # 3050 Fragen → Soll-IDs (inkl. Konfliktfälle)
eval/evaluate.py # Recall@k, Zitier-Präzision, Verweigerungsraten, Latenz
web/index.html # minimalistischer Test-Chat
data/ # index.db (gitignored)
tests/ # pytest: Ingest-, Retrieval-, Grounding-Unit-Tests
```
## 8. Validierung
- **Goldset:** 3050 Fragen mit Soll-IDs je Cluster, inkl. 35
Outside-KB-Fragen (Verweigerung!) und Konfliktfragen (ATZ-Quoten).
- **Metriken:** Retrieval-Recall@8 (Ziel >0,9), Zitier-Präzision
(100 % zitierte IDs ∈ retrieved), Verweigerungskorrektheit,
End-zu-End-Latenz.
- **Modell-Bake-off (M3):** qwen3.8:27b vs. qwen3:32b vs. gemma3:27b vs.
mistral-small3.2:24b (plus qwen3:14b als Latenz-Untergrenze) auf dem
Goldset; Entscheidung dokumentieren (analog D1/D2-Stil des Projekts).
- **Unit-Tests:** Ingest-Schema, Umlaut-Normalisierung, Post-Validierung
(Halluzinations-ID → Regenerierung), Konflikt-Darstellung.
## 9. Phase B: Odoo-Enterprise-Integration (später)
- **Option A (empfohlen):** dünnes Custom-Modul mit OWL-Chat-Panel,
`ir.config_parameter` für die Service-URL, rollenbasierter Zugriff.
Der RAG-Service bleibt Single Source of Truth für Grounding und
Zitate; Ollama bleibt extern. Unabhängig von Odoo-Version-Features.
- **Option B (zu prüfen):** nativer Odoo-LLM-Stack (in Odoo 19 neu
eingeführte `llm`/Agent-/Knowledge-Module) mit Ollama als
OpenAI-kompatiblem Provider. **Muss zuerst gegen Euren konkreten
Odoo-19-Quellstand verifiziert werden** (Modulnamen/APIs sind hier
nicht im Projekt und werden nicht aus Trainingswissen behauptet).
Striktes Grounding + Zitierdisziplin wären dort nachzubauen.
- Entscheidung erst nach Verifikation; Phase A läuft davon unabhängig
und wird von beiden Optionen unverändert genutzt.
- **Datenschutz-Bonus:** der Agent ist reiner Wissensassistent — es
fließen keine Mitarbeiter-/Abrechnungsdaten ins Modell, nur die
Frage und Layer-2-Fachtexte.
## 10. Risiken & offene Punkte
1. **Ollama-Erreichbarkeit** aus der Zed-Sandbox nicht gegeben —
Verifikation vom Host: `curl http://100.183.83.12:11435/api/tags`;
Modelle ggf. erst pullen (`qwen3:32b`, `bge-m3`, …).
2. **Ollama-Version:** `/api/embed` + allfällige Rerank-Unterstützung
prüfen; Fallback ohne Reranker ist unkritisch.
3. **Strix Halo (gfx-1151):** Ollama/ROCm muss die Karte unterstützen
(Server läuft offenbar bereits — im Bake-off Performance messen).
4. **Halluzination trotz allem:** Prompt + Post-Validierung reduzieren,
aber nicht eliminieren → Eval-Suite als Dauerschutz; Antworten
führen immer Quellen-IDs (Nachprüfbarkeit durch den Nutzer).
5. **WIKU-Layer-1** fehlt lokal — nur relevant, falls später Layer-1-
Tiefenzitate gewünscht (Lizenzpunkt aus README bleibt offen).
6. **Odoo-19-LLM-Module** unverifiziert → Phase B separat planen.
## 11. Meilensteine
| # | Inhalt | Ergebnis |
|---|---|---|
| M1 | Ingest + Index + Hybrid-Retrieval (ohne LLM) | Recall@8 auf Goldset messbar |
| M2 | Ollama-Anbindung (Embed + Generate), Grounding-Regeln, `/ask`-API, CLI | nutzbarer Agent im Terminal |
| M3 | Eval-Suite + Modell-Bake-off | dokumentierte Modell-Entscheidung |
| M4 | Odoo-Integration | separater Plan nach Odoo-19-Verifikation |
## 12. Entscheidungspunkte (an Dich)
1. **Modell:** `qwen3.8:27b` als primärer Bake-off-Kandidat ok — oder
gleich als Startmodell festlegen (und `qwen3:32b` nur als Fallback)?
2. **Bake-off:** vergleichst Du die drei Antwortmodelle auf dem Goldset
(empfohlen) oder legen wir qwen3:32b direkt fest?
3. **Layer 1:** bewusst außen vor in Phase A — einverstanden?
4. **Odoo-Version für Phase B:** Odoo 19 Enterprise (passend zu
`l10n_at_hr_payroll*`) — bitte bestätigen.