Files
pv-agent/.agents/MEMORY.md
T
fegger a8234771cb Retrieval-Kalibrierung nach Korpusverdopplung (D10) + Goldset-Erweiterung
- Hybrid-Fusion um dense_weight erweitert; kalibriert per Goldset-Sweep:
  dense_weight=2.0 (BM25 durch KV-S-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.
- CITE_RE um kv|ris erweitert (Post-Validierung deckt neue ID-Raeume).
- Goldset: +6 KV/RIS-Fragen (q-101-106) + Branchen-Refusal r-005;
  q-021 auf lb-kar-04 rekalibriert (Top-1, deckt Beginn/Dauer voll -
  dokumentiert im Note).
- Antwortmodus-Eval (qwen3.8:27b, 42 Fragen): Zitier-Praezision 95,2 %,
  Verweigerung 90,5 % - unter den M3-Gates, Tuning folgt
  (Report data/eval-qwen38-kvris.json, lokal).
- Docs: agent/README.md Baseline, planung.md Umsetzungsstand,
  .agents/MEMORY.md (D9/D10, offene Punkte).
2026-09-15 07:45:04 +02:00

190 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 M1M4; **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-<prefix>-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-<nnn>` (ein Cluster `kollektivvertraege`,
Branche als Tag) und `ris-<cluster-prefix>-<nn>` 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-101106 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-<nnn>` (ein Cluster `kollektivvertraege`, Branche als Tag),
`ris-<cluster-prefix>-<nn>` 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).