Files
pv-agent/planung.md
T
fegger bf8191b013 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).
2026-09-14 16:34:13 +02:00

12 KiB
Raw Blame History

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

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)

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.