agent/-Paket: Ingest (601 Layer-2-Eintraege -> 3005 Chunks, FTS5-BM25 + Vektoren-Cache), Hybrid-Retrieval (RRF, Stand-Boost, cross_ref-Erweiterung), Ollama-Client (embed/chat, think-Flag-Fallback, kurzes Connect-Budget), Systemprompt mit Zitierpflicht, Post-Validierung (zitierte IDs gemaess Retrieved-Set, 1x Regenerierung, dann Verweigerung), FastAPI (/ask, /health, /reindex), CLI, Goldset (31 Fragen, IDs gegen kb.json verifiziert, inkl. ATZ-Konfliktfall + 4 Verweigerungsfaelle), Eval-Suite, Test-Chat. 41 Offline-Tests gruen. Baseline BM25-only: Hit-Rate 0,871 / Recall@8 0,855 / MRR 0,476. Hybrid-Messung, Antwortmodus-Eval und Modell-Bake-off (M3) auf dem Host ausstaendig (Ollama aus der Zed-Sandbox nicht erreichbar). MEMORY.md und planung.md Umsetzungsstand aktualisiert.
13 KiB
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.jsonals 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 ~26–28 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
standbelegt, - 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 (~400–600 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 (15–20 GB) + bge-m3 (~1,5 GB) + KV-Cache für
RAG-Prompts (4–8k Tokens Kontext, ~16k Kontextfenster ≈ 3–4 GB) ⇒
~20–26 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)
- 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. - Kontextblöcke mit Metadatenkopf (ID · Titel · Stand · topic · Quellenwerk) — das Modell sieht nur, was im Retrieval war.
- Post-Validierung: jede zitierte ID muss in der Retrieved-Menge stehen; Verstoß → eine Regenerierung mit härterem Hinweis, dann Verweigern/„unsicher“. Temperatur ~0,1.
- 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_refsder Top-Treffer als kontrollierte Kontext-Erweiterung. - Metadaten-Filter:
topic-Vorfokus aus der Frage, Aktualitäts- gewichtung überstand. - Quelle der Ingestion: Layer-2-Frontmatter direkt (Single Source of
Truth);
kb.jsonzusä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 # 30–50 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: 30–50 Fragen mit Soll-IDs je Cluster, inkl. 3–5 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_parameterfü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
- 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, …). - Ollama-Version:
/api/embed+ allfällige Rerank-Unterstützung prüfen; Fallback ohne Reranker ist unkritisch. - Strix Halo (gfx-1151): Ollama/ROCm muss die Karte unterstützen (Server läuft offenbar bereits — im Bake-off Performance messen).
- 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).
- WIKU-Layer-1 fehlt lokal — nur relevant, falls später Layer-1- Tiefenzitate gewünscht (Lizenzpunkt aus README bleibt offen).
- 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)
- Modell:
qwen3.8:27bals primärer Bake-off-Kandidat ok — oder gleich als Startmodell festlegen (undqwen3:32bnur als Fallback)? - Bake-off: vergleichst Du die drei Antwortmodelle auf dem Goldset (empfohlen) oder legen wir qwen3:32b direkt fest?
- Layer 1: bewusst außen vor in Phase A — einverstanden?
- Odoo-Version für Phase B: Odoo 19 Enterprise (passend zu
l10n_at_hr_payroll*) — bitte bestätigen.
13. Umsetzungsstand (2026-09-14)
- M1 erledigt (offline): Ingest + Index (601 Einträge → 3.005 Chunks, FTS5-BM25) + Hybrid-Retrieval (Dense-Code vorhanden, am Host zu messen). Goldset 31 Fragen (IDs gegen kb.json verifiziert, inkl. ATZ-Konfliktfall und 4 Verweigerungsfälle). Baseline BM25-only: Hit-Rate 0,871 · Recall@8 0,855 · MRR 0,476 — 4 Fehltreffer sind Komposita-/Stamm- Muster, die die Dense-Suche abdecken soll. 41 Unit-Tests grün.
- M2 implementiert: Ollama-Client (embed/chat, think-Fallback),
Systemprompt mit Zitierpflicht, Post-Validierung (1× Regenerierung, dann
Verweigerung),
/ask-API + CLI + Test-Chat. Host-Validierung mit echtem Ollama noch offen (aus der Zed-Sandbox nicht erreichbar). - M3 offen: Bake-off auf dem Host (qwen3.8:27b vs. qwen3:32b vs. gemma3:27b vs. mistral-small3.2:24b; qwen3:14b als Latenz-Untergrenze).
- Betrieb/Host-Schritte:
agent/README.md.