Files
pv-agent/.agents/MEMORY.md
T
fegger 062e010d7b Stufe 1: komplexe Fragen via Query-Planer, Per-Query-Slots, Scope-Filter (D12, M6)
- Query-Planer (agent/query_planner.py): Heuristik-Gate (Jahr, Vergleichs-/
  Aggregationsmarker, Laenge) entscheidet ueber einen kleinen LLM-Call,
  der komplexe Fragen in 1-3 Sub-Queries zerlegt (JSON, temp 0; Fehler ->
  Original als Einzel-Query). Je Sub-Query optional stand_year und scope.
- Multi-Query-Retrieval: je Sub-Query BM25+Dense mit RRF-Summe;
  Per-Query-Slots (2 je Sub-Query) sichern jeden Frageaspekt im Kontext
  (sonst dominieren Eintraege, die in mehreren Sub-Queries mittelgut
  matchen — q-113-Befund). Scope-Filter: 'gesetz' (nur Lexis/WIKU/RIS)
  und 'kv' (nur Branchen-KV) mit Fallback auf unscoped bei leerem
  Ergebnis. Temporal-Intent: stand_year + temporal_boost (default 0,
  FTS-jahr-Tag-Signal reichte).
- Grounding unveraendert: eine Retrieved-Menge (Union), eine Antwort,
  Post-Validierung ueber die Union, Verweigerungspflicht unveraendert.
- Goldset 42 -> 46: q-110 (Temporal 2023; 2024er-Lohnordnung existiert
  im Korpus nicht - Mantelvertrag ohne Lohntabelle, korrekt verweigert),
  q-111 (2025), q-112 (Abfertigung-Vergleich), q-113 (Gesetz+KV).
- Eval (46 Fragen): Zitier-Praezision 97,8 %, Verweigerung 97,8 %
  (Gate >94,3 % erfuellt), erwartete Quelle 90,2 %, Latenz mean 33,5 s.
- Tests 50 -> 57. Reports lokal: data/eval-qwen38-stage1*.json.
  API-first festgehalten (D13-Vorbereitung): Odoo bleibt duenner Client;
  Lohndaten-Zugriff in M4 erfordert Privacy-Neubewertung.
2026-09-15 09:58:25 +02:00

14 KiB
Raw Blame History

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 abgeschlossenqwen3.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=150Recall@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 vor dem Tuning (D10-Follow-up) unter den Gates (Zitier-Präzision 95,2 % — 2 Verlet- zungen; Verweigerung 90,5 % — 4 Fehlverweigerungen, u.a. q-022/q-029; erwartete Quelle 83,8 %) — Report data/eval-qwen38-kvris.json. D11-Fix behoben die 4 Fehlverweigerungen: Antwortmodus jetzt Zitier-Präzision 97,6 %, Verweigerung 97,6 % (>94,3 %-Gate ✓), erwartete Quelle 91,9 %, Retrieval Recall@8 0,946 — Report data/eval-qwen38-kvris-tuned.json. Verbleibend: q-015 (Branchen- Noise) und q-024 als transiente Flakiness (leerer Draft — Think-Ghost- Verdacht bei 32k-Kontext; beobachten).
  • 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.
  • D11 (Prompt-Budget + Kontext-Abdeckung, 2026-09-15): lange KV-Chunks ueberlieferten num_ctx=16384 (q-022: 62,7 KB Prompt ≈ 18k Tokens) — Ollama trunciert den Systemprompt vorn, das Modell verliert die Zitierregeln („Block 8“-Zitate statt IDs → Regenerierung → Verweigerung). Fix: num_ctx 32 768, trim_results (max_context_chars=90 000, Tail- Bloecke ganz weg statt trunciert, Mindestbestand 6) und cross_ref_expand 3 → 6 (die Top-3 sind oft Branchen-KV-Bloecke mit leeren cross_refs — kuratierte Nachbarn kamen sonst nie nach). Ergebnis: alle 4 Fehlverweigerungs-Faelle (q-001/q-019/q-022/q-029) geheilt, 10/10 Bestaetigungslaeufe OK. Eval: Zitier-Praezision 97,6 %, Verweigerung 97,6 % (> 94,3 %-Gate ✓), erwartete Quelle 91,9 % (vorher 83,8 %), Retrieval Recall@8 0,946 (cross_ref-Extras bringen Expected-IDs nach), MRR 0,671. Latenz mean 33 s. Report data/eval-qwen38-kvris-tuned.json. Restrisiko: q-024 flaky (1/3 Laeufe — transienter leerer Draft, Think-Ghost-Verdacht); q-015 Branchen-Noise bleibt offen.
  • D12 (Komplexe-Fragen-Stufe 1 / M6, 2026-09-15): Query-Planer vor dem Retrieval: Heuristik-Gate (Jahreszahl, Vergleichs-/Aggregationsmarker, Laenge) entscheidet, ob ein kleiner LLM-Call die Frage in 1-3 Sub-Queries zerlegt (JSON, temp 0, num_predict 220; Fehler -> Original als Einzel- Query). Multi-Query-Retrieval: je Sub-Query BM25+Dense, Beitraege summieren; Per-Query-Slots (2 je Sub-Query) sichern jeden Frage- aspekt im Kontext — ohne sie dominieren Eintraege, die in mehreren Sub-Queries mittelgut matchen (q-113: 5 KV-Urlaubs-SS schlugen lb-url-05 (Rang 6) und ris-url-01 (>Top-12) ueber beide Sub-Queries). Scope-Filter je Sub-Query: Planer markiert "gesetz" (nur Lexis/WIKU/ RIS-Chunks) bzw. "kv" (nur Branchen-KV) — q-113 geheilt (ris-url-01/ lb-url-05 + KV-Ss im selben Kontext). Scope-Fallback: gefilterte Suche leer -> unscoped. Temporal-Intent: stand_year je Sub-Query, kv-Eintraege im Geltungsjahr erhalten temporal_boost (default 0 — FTS-Tag-Signal jahr-YYYY reichte in der Messung). Grounding unveraendert: ein Kontext aus der Union, Post-Validierung ueber die gesamte Retrieved- Menge, Verweigerungspflicht unveraendert. Eval (46 Fragen): Zitier-Praezision 97,8 %, Verweigerung 97,8 % (Gate > 94,3 % erfuellt), erwartete Quelle 90,2 %, Latenz mean 33,5 s. Temporal-Fragen laufen sogar ohne Planer gut (Jahr-Toknen matchen jahr-YYYY-Tags). Neue komplexe Fragen im Goldset: q-110 (Temporal 2023, nach Korrektur — eine 2024er-Friseur-Lohnordnung existiert im Korpus NICHT: kv-kvt-161 ist der Mantelvertrag ohne Lohntabelle; korrekt verweigert), q-111 (Temporal 2025), q-112 (Abfertigung Vergleich), q-113 (Gesetz+KV Multi-Source). Tests 50 -> 57. Offen: q-029 Survey (Stufe-2-Hebel: Map-Reduce), q-113 Planer- Scope flaky (1/2 Laeufe ohne gesetz-Marker).
  • 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).