# Agent-Memory — pv-agent Rollender Übergabe-Log für agent-Threads. Workflow: `.agents/SKILL.md` (agent-memory-Skill). Ergänzen, nicht überschreiben. ## Current focus M1, M2 und **M3 (Bake-off) sind abgeschlossen** — `qwen3.8:27b` ist als Antwortmodell fixiert (D7). Offen: Fehlverweigerungs-Tuning (q-008, q-031 — beide Finalisten betreffend) und Odoo-Integration (M4, separat zu planen). ## Completed (2026-09-14) - **Planung** (`planung.md`): Architektur, Grounding-Regeln, Modellfeld, Meilensteine M1–M4; **Skill** `.agents/skills/pv-rag-agent/SKILL.md`. - **Commits**: `25eb285` (Wissensbasis-Import), `bf8191b` (Planung + Skills), `2cba72a` (M1+M2-Implementierung, 41 Tests). - **Implementierung M1+M2** (`agent/`): kb/ingest/retrieve/generate/ ollama_client/api/cli/eval, Goldset 31 Fragen, Test-Chat. - **Ollama-Anbindung verifiziert** (Ziel-Instanz `http://100.103.83.12:11435`, Ollama 0.32.13): `bge-m3` per API gepullt; `qwen3.8:27b` war bereits installiert. Hybrid-Index: 3.005 Chunks, alle eingebettet (144 s). - **M1-Akzeptanz erreicht**: Retrieval Hybrid Hit-Rate 0,968 · Recall@8 **0,952** (>0,9 ✓) · MRR 0,690 (BM25-only: 0,871/0,855/0,476). - **M2-Antwortmodus-Eval** (qwen3.8:27b, Thinking aus): Zitier-Präzision **100 %** (4 Regenerierungen, alle geheilt) · Verweigerung korrekt 94,3 % · erwartete Quelle zitiert 80,6 % · Latenz mean 32 s / p95 53 s. Report: `data/eval-qwen38.json`. - Der ATZ-Konfliktfall (28,5 vs. 27,5 %) wird korrekt mit ⚠ und beiden IDs beantwortet; harte Verweigerung (UStVA, Retrieval nicht leer) funktioniert. - **Topologie geklärt**: `100.103.83.12` ist die **Remote-GPU-Maschine** (Entwicklungsumgebung, R9700, Tailscale); die Dev-Maschine selbst hat einen eigenen, fast leeren Ollama auf localhost:11434 (dorthin ging der erste bge-m3-Pull — auf die GPU-Maschine neu gepullt). Ziel-Instanz ist ausschließlich `http://100.103.83.12:11435`. - **Bake-off M3 — abgeschlossen (D7)**: alle 6 Kandidaten gemessen (Tabelle in `planung.md` Abschnitt 13). **`qwen3.8:27b` gewinnt** (100 % Zitier-Präzision, 94,3 % Verweigerung korrekt, 80,6 % erwartete Quelle, 32 s mean). `gemma4:26b` = dokumentierter Latenz-Kandidat (7,9 s mean, 100 % Zitier-Präzision, aber 67,7 % Quellentreue, 3 Fehlverweigerungen). mistral-small3.1: 71,4 % Verweigerungskorrektheit — Deutsch-Hypothese praktisch widerlegt. **muse-glimmer:latest** (nachgereicht): 100 % Zitier-Präzision bei nur 1 Regenerierung (diszipliniertestes Modell), aber 8/35 falsche Verweigerungen (Überverweigerung teils trotz vorhandener Zitate) und 37,5 s mean — Rang 5 von 6, schlägt qwen3.8 in keiner Kennzahl. qwen3.6:27B: 2 dauerhafte Zitierverletzungen, 10 Regenerierungen. gemma4:12B: 2 Verletzungen. Reports: `data/eval-*.json`. q-008/q-031 verweigern alle Top-Kandidaten — Prompt-/Retrieval-Tuning (nicht modellspezifisch). - **Remote-GPU-Maschine**: nach `systemctl restart ollama` (User-Aktion) liefen alle Läufe stabil; zwischen Kandidaten wurde per `keep_alive: 0` entladen (Crash-Ursache war der Modell-Swap-Stress beim gemma4-Lauf). ## Completed (2026-09-15) - **KB-Erweiterung um WKO-Kollektivverträge + RIS-Gesetze** (User-Auftrag): `.firecrawl/wko-kv/docs/` (614 KV-Dokumente: Lohn-/Gehaltsordnungen mit Lohntabellen, KV-Abschlüsse, Erläuterungen, Zusatz-KVs) und `.ris/` (59 Gesetze, nur die im Lexis360-Bestand zitierten §-Ausschnitte, Stand 2026-09-13) → **1 274 Layer-2-Einträge** (`kv-kvt-001…614`, `ris--nn`), 14 984 Chunks, Reindex 8,5 min (11 947 neue Embeddings, bge-m3 auf :11435). - **D9 (2026-09-15):** kv/ris-Einträge sind **quellentreu generiert** (keine Eigene-Worte-Kuratierung — Gesetze sind amtliche Werke, KV- Lohntabellen zahlenexakt; Konvention 2 der Wissensbasis gilt nur für die lizenzierten Quellen lb/wk). Tool-Output: `tools/ingest_sources.py` + `tools/build_registry.py` (Registry in diesem Repo neu gebaut — das Lexis-Tool `build_lexis_kb.py` lebt im Schwesterprojekt), eingefrorene Kataloge `tools/catalogs/*.json` (nur Metadaten, versioniert). - **ID-Räume:** `kv-kvt-` (ein Cluster `kollektivvertraege`, Branche als Tag) und `ris--` auf der bestehenden Cluster-Map + 7 neue Cluster (kvt/zvr/avr/agg/lst/abo/nso); `LAW_MAP` in `tools/kb_common.py` dokumentiert die 59 Zuordnungen. - **D10 (Retrieval-Kalibrierung, Goldset-Sweep 2026-09-15):** Korpus- verdopplung drückte Recall@8 auf 0,851 — kalibriert auf `dense_weight=2.0` (Dense-Liste relativ zu BM25 gewichtet; BM25 ist durch KV-§-Titel-Matches inflationiert), `rrf_k=20`, `candidate_pool=150` → **Recall@8 0,923 (>0,9 ✓)**, Hit-Rate 0,973 (36/37), MRR 0,667. ENV: `PV_DENSE_WEIGHT`/`PV_RRF_K`/ `PV_CANDIDATE_POOL`. Entry-RRF-Variante getestet: kein Mehrwert. - **Antwortmodus-Eval (qwen3.8:27b, 42 Fragen):** Zitier-Präzision 95,2 % (2 Verletzungen), Verweigerung korrekt 90,5 % (4 Fehlver- weigerungen, u.a. q-022/q-029), erwartete Quelle zitiert 83,8 %, Latenz mean 31 s / p95 53 s, 9 Regenerierungen — **unter den M3- Gates** (100 % / 94,3 %): Korpusverdopplung macht Grounding härter; das laufende Fehlverweigerungs-Tuning (uncommittete Änderungen in generate.py/retrieve.py/goldset.yaml, unangetastet) ist weiteres Thema. Report: `data/eval-qwen38-kvris.json`. - **Goldset:** +7 Fragen (q-101–106 KV-Preise/§-Fragen, r-005 Branchen- Refusal) — append-only. q-021 rekalibriert: erwartete ID jetzt `lb-kar-04` („Karenz - Anspruch, Beginn und Dauer“, Top-1, deckt Beginn/Dauer vollständig; lb-kar-01 nur Nachbarschaft — dokumentiert im Goldset-Note). - **Tests:** 41 → 49, alle grün (neue ID-Räume, html-Source, Konverter, LAW_MAP-Vollabdeckung, Korpus-Integrationszahl 1 274). ## Open issues / blockers - **Push**: Remote localhost:3003 aus der Sandbox nicht erreichbar — User pusht vom Host. - **Fehlverweigerungen — Stand nach Prompt v2:** q-008 und q-031 sind **behoben** (Section-Priorität + Regel 8). Verbleibend: q-029 („Welche Neuerungen behandelt WIKU Personal aktuell 2026?“) — breite Survey-Frage über 12 Hefte; Kontext enthält echte Zusammenfassungen, Modell verweigert trotzdem (sicherer Fehlermodus). Mögliche spätere Hebel: Survey-Rule im Prompt, mehr Kontextblöcke oder Map-Reduce-artige Zusammenfassung. Weitere Iterationen erst mit neuen Evaluationsdaten. - **Latenz**: mean 32 s/ Antwort ist hoch (Dense 27B + große Prompts). Hebel: weniger Kontextblöcke (aktuell 8+6), schnellere Kandidaten. - **Cloud-Modelle** (`*:cloud` auf der Ollama-Instanz) sind für Antworten tabu (Anforderung: lokal). Nicht versehentlich konfigurieren. - **Bake-off M3 — erledigt** (siehe Completed; Entscheidung D7 in `planung.md`). Nach Tuning von Prompt/Retrieval: erneuter kurzer Bestätigungslauf nur mit dem Sieger. - **M4 Odoo**: native LLM-Module des konkreten Odoo-19-Stands verifizieren (keine API-Annahmen); Option A (dünnes Custom-Modul + Service-API) ist Default. - **Nach KV/RIS-Erweiterung (2026-09-15)**: Antwortmodus unter den Gates (Zitier-Präzision 95,2 % — 2 Verletzungen; Verweigerung 90,5 % — 4 Fehlverweigerungen, u.a. q-022/q-029; erwartete Quelle 83,8 %) — Report `data/eval-qwen38-kvris.json`. Retrieval-Gate erfüllt (Recall@8 0,923 nach D10-Kalibrierung). Weiteres Prompt-/Kontext-Tuning offen; der laufende Arbeitsstand in generate.py/retrieve.py/goldset.yaml wurde unangetastet gelassen. - **q-015 (Tagesgelder Dienstreisen)** — Branchen-Noise: 8 Branchen-KV- Einträge verdrängen lb-rei-01/09 (EStG-Taggeld-Abrechnung) aus Top-8; generische Branchen-Frage ist mehrdeutig geworden. Hebel: Frage präzisieren (Branche/Kontext) oder KV-§-Titel-Matches dämpfen. ## Decisions & conventions - **D1 (Planung):** Schlanke Eigen-Pipeline statt LangChain/LlamaIndex — Grounding-Kontrolle schlägt Framework-Komfort bei 601 Dokumenten. - **D2:** Retrieval-Korpus ist **nur Layer 2**; Layer 1 bleibt aus Prompts (Lizenz); Antworten zitieren `[kb-id]` + `(Stand YYYY-MM)`. - **D3:** Umlaut-Folding für FTS (NFKD, ß→ss) — gilt konsistent für Index und Query; ASCII-Slug-Konvention der Wissensbasis bleibt davon unberührt. - **D4:** Post-Validierung strikt: zitierte IDs ⊆ Retrieved-Set (Block-Kopf- IDs); Fließtext-Verweis-IDs sind KEINE Belege (Systemprompt-Regel 2) — Verstoß → 1× Regenerierung → Verweigerung (UNCERTAIN_MESSAGE). - **D5:** Vektoren-Tabelle ist Cache (Content-Hash × Modell), Rebuild löscht sie nicht; `--no-embed` setzt `embed_off` im Config-Copy. - **D6:** Leeres Retrieval → deterministische Verweigerung ohne LLM-Call. - **D7 (Bake-off 2026-09-14):** `qwen3.8:27b` ist das fixierte Antwortmodell (100 % Zitier-Präzision, 94,3 % Verweigerung korrekt). `gemma4:26b` als dokumentierter Latenz-Kandidat; ein Modellwechsel läuft nur erneut über das dokumentierte Protokoll (Skill). - **D8 (Prompt-Tuning 2026-09-14):** Prompt v2 + Kontext-Section- Priorität. (a) Regel 4 erlaubt Teilantworten bei unvollständiger Deckung; Regel 8 verlangt Prämisse-Korrektur statt Verweigerung (Muster-Beispiel „Mindestlohngesetz“). (b) `_representative_chunk` wählt pro Eintrag die beste **Inhaltssektion** (Zusammenfassung > Kernwerte > Rechtsgrundlagen > Payroll > sonstige; „Verweise“ nur als letzter Rückgriff — BM25 rangiert die dünnen Navigations-Chunks bevorzugt, q-008-Ursache). Ergebnis v1→v2: Zitier-Präzision 100 % gehalten; q-008 + q-031 behoben; erwartete Quelle 80,6 → 83,9 %; Verweigerung 94,3 % (Fehler getauscht: neu q-029 — breite Survey-Frage über 12 Hefte, sicherer Fehlermodus). Report `data/eval-qwen38-v2.json`. - **D9 (KV/RIS-Erweiterung, 2026-09-15):** kv-/ris-Einträge sind **quellentreu generiert** (keine Eigene-Worte-Kuratierung — Gesetze sind amtliche Werke, KV-Lohntabellen zahlenexakt; Konvention 2 der Wissensbasis gilt nur für die lizenzierten Quellen lb/wk). Tool-Output: `tools/ingest_sources.py` + `tools/build_registry.py` (Registry in diesem Repo neu gebaut — das Lexis-Tool `build_lexis_kb.py` lebt im Schwesterprojekt), eingefrorene Kataloge `tools/catalogs/*.json` (nur Metadaten, versioniert). IDs: `kv-kvt-` (ein Cluster `kollektivvertraege`, Branche als Tag), `ris--` auf der bestehenden Cluster-Map + 7 neue Cluster; `LAW_MAP` in `tools/kb_common.py` (59 Gesetze). - **D10 (Retrieval-Kalibrierung, 2026-09-15):** nach KV/RIS-Erweiterung (3.005 → 14 984 Chunks) dense_weight=2.0 (Dense relativ zu BM25 gewichtet — BM25 durch KV-§-Titel-Matches inflationiert), rrf_k=20, candidate_pool=150 → Recall@8 0,851 → 0,923 (>0,9 ✓), Hit-Rate 0,973, MRR 0,667. ENV: PV_DENSE_WEIGHT / PV_RRF_K / PV_CANDIDATE_POOL. Entry-RRF-Variante getestet: kein Mehrwert. - **Bake-off-Protokoll** (Skill): Modellwechsel nur über dokumentierten Goldset-Vergleich; Kriterium: Zitier-Präzision > Verweigerungs- korrektheit > Latenz. ## Files that matter right now - `planung.md` — Plan + Entscheidungspunkte (Abschnitt 12) + Stand. - `.agents/skills/pv-rag-agent/SKILL.md` — verbindliche Regeln. - `agent/README.md` — Betrieb, Konfiguration, Host-Schritte. - `agent/eval/goldset.yaml` — Goldset (IDs gegen kb.json verifiziert). - `agent/generate.py` — Grounding-Kern (Prompt, Post-Validierung). - `wissensbasis/README.md` — Layer-2-Schema (unverändert gültig).