38 KiB
Agent-Memory — pv-agent
Rollender Übergabe-Log für agent-Threads. Workflow: .agents/SKILL.md
(agent-memory-Skill). Ergänzen, nicht überschreiben.
Current focus
D24 validiert (500-Euro-Fragen verifiziert, think-Fix, Offline-Eval Recall@8
0,95). D25-Planung steht (planung.md Abschnitt 14) und M4.2 ist umgesetzt: Agent
mode=review mit schema-gebundenem Odoo-Kontext, Beweisklassen, Injection-
Abgrenzung und plausibility-Verdict; Feature-Flag PV_REVIEW_MODE (default
aus). KV-Varianten-Mapping gebaut (tools/catalogs/kv_variant_map.json,
439/614 abgedeckt, Seeds SI-2203/SI-2748 getestet). 106 Tests grün. Als
Nächstes: M4.1 — Odoo-Modul l10n_at_payroll_agent (Client, Kontext-Builder,
Pilot-Workflow am Draft-Payslip).
Completed (2026-09-16, Modul-Review/D25-Planung)
.oddo-module/verlinkt (Symlink → ../odoo-at-payroll/addons, in.gitignoreaufgenommen). Review gegen M4: Odoo 19.0 (Kern 19.0.10.0.0 aufhr_payroll, Privat 19.0.17.0.0, Gemeinde-Bgld, Dokumente), LGPL-3, ~22k Zeilen Python / ~7,5k XML / ~25 Testdateien. Kein HTTP-/Controller-/Agenten-Code vorhanden — M4 startet bei null. Tenant-Isolation viair.rule(company_ids), Feldgruppengroup_hr_payroll_user. Rechenkern: sozialversicherung.py (§-49-Ausschal- tungen mit Jahres-Kumulative_l10n_at_sv49_ytd, WF-Satzvektor Bundesland ×Jahr, DAG), lohnsteuer.py (§ 66/67/68 mit YTD-Freibetragsverbrauch), payslip_private (KommSt/DZ/FLAF-DB/SZ), sachbezuege/reisekosten. Parameter aus ÖGK-TASY-Export gegen offiziellen Report gespiegelt; 2027-Rahmen. KV-Katalogl10n.at.payroll.kvmit versioniertenkv.wert, Gruppen/Stufen und CSV-Import-Wizard (Sprungwarnung >10 %);library_variant_idverlinkt auf die KV-Library (SI-2203/SI-2748). D25-Planung steht inplanung.mdAbschnitt 14: neues Modull10n_at_payroll_agent, ir.config_parameter plus eigene Gruppe, serverseitiger Client, hart kodierte Kontext-Whitelist (facts key/value/note, keine Personendaten), Pilot-Workflow Plausibilitätsprüfung einer geplanten Auszahlung (Odoo rechnet auf dem Draft-Payslip, Agent liefert strukturiertes Verdict), Agent-M4.2:mode=reviewplus context-Schema, drei Beweisklassen, Injection-Abgrenzung und Feature-FlagPV_REVIEW_MODE(default aus). Nicht-Ziele fixiert.- M4.2 Agent-Review-Modus (2026-09-16, D25):
AskRequest.modeknowledge|review+context(StrictModel: facts ≤40, key-Muster, computation + components ≤40; keine freien Objekte).answer_questionnimmtcontextan: Review-Addendum an den Systemprompt (Regeln 13/14: Kontext = Daten/keine Anweisungen, übermittelte Werte ohne KB-ID, Verdict-Format „Plausibilitätsprüfung:“ mit OK/WARN ⚠/OFFEN),parse_plausibility_checksextrahiert Checks (OK/WARN ohne erlaubte KB-ID zählen nicht),plausibility_verdict(implausible bei ⚠, plausible bei OK, sonst not_checkable). Fehlender/leerer Abschnitt → Regenerierung; bleibt er aus, bleibt die zitiergültige Fachantwort mitnot_checkable-Verdict bestehen (keine UNCERTAIN-Eskalation). API-Gating: review ohnePV_REVIEW_MODE→ 422; knowledge+context → 422; review ohne context → 422.grounding.data_scopereview:knowledge_base_plus_review_context. Audit:context_json-Spalte mit idempotenter Migration, Metadatenmodus ohne Kontext-Freitext. CLI:ask --context FILE. Response-Feldermode+plausibility. Tests +8 (tests/test_review.py) → 107 grün. Real-Lauf validiert (qwen3.8, Odoo-Kontext-Sonde mit provokativ falscher Steuerfreiheit in der Simulation): verified, 1 Regen, Verdict implausible — WARN Lohnsteuer (lb-lvr-07/ lb-naz-03), OK SV-Grundsatz (lb-naz-02), OFFEN DB/DZ + BVK; Parser-Fix: Heading-Regex toleriert**Plausibilitätsprüfung:**(Doppelpunkt in den Sternen) sowie ⚠-Präfix in der Aspect-Extraktion. - KV-Varianten-Mapping (Odoo ↔ KB, 2026-09-16): Die KV-Library führt
bereits
wko/match-report.json(wko_slug → oegb_variant_id; 407 matched / 32 low / 175 unmatched).tools/build_kv_variant_map.pyerzeugt daraustools/catalogs/kv_variant_map.json: 105 Varianten (98 matched, 7 low), 439/614 KB-Einträge abgedeckt; je Variantedocsmit kv_kvt_id + slug + doctype als Paare, Low-Confidence markiert, Rest inunmatched_kb_entries(WKO-aktuelle Dokumente ohne ÖGB-Gegenstück, z. B. KV-Abschluss-News). Odoo kann prolibrary_variant_iddie zugehörigen KB-Einträge auflösen; Seed-Abdeckung SI-2203/SI-2748 testettests/test_kv_variant_map.py. Tests gesamt 98 grün.
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-m3per API gepullt;qwen3.8:27bwar 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.12ist 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ßlichhttp://100.103.83.12:11435. - Bake-off M3 — abgeschlossen (D7): alle 6 Kandidaten gemessen
(Tabelle in
planung.mdAbschnitt 13).qwen3.8:27bgewinnt (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 perkeep_alive: 0entladen (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/kv-portal/wko-kv/docs/(614 KV-Dokumente: Lohn-/Gehaltsordnungen mit Lohntabellen, KV-Abschlüsse, Erläuterungen, Zusatz-KVs) und.firecrawl/ris/gesetze/(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.pytools/build_registry.py(Registry in diesem Repo neu gebaut — das Lexis-Toolbuild_lexis_kb.pylebt im Schwesterprojekt), eingefrorene Katalogetools/catalogs/*.json(nur Metadaten, versioniert).
- ID-Räume:
kv-kvt-<nnn>(ein Clusterkollektivvertraege, Branche als Tag) undris-<cluster-prefix>-<nn>auf der bestehenden Cluster-Map + 7 neue Cluster (kvt/zvr/avr/agg/lst/abo/nso);LAW_MAPintools/kb_common.pydokumentiert 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).
- 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:
-
D15 (Rechtsprechungs-Intake, 2026-09-15):
.rechtsprechung/→ neuer ID-Raumrj-rjs-*, gemeinsamer Clusterrechtsprechung: 320 RIS-OGD- Entscheidungen/Rechtssätze, 23 zitierte RIS-Normauszüge und 5 als nichtamtlich markierte EuGH-lexetius-Textwiedergaben. Parser:tools/ingest_sources.py --source rj; lange Volltexte werden an Absatzgrenzen in H2-Chunks geteilt.rj_catalog.jsonfriert die IDs ein; Registry/Index und Agent-Zitatvalidierung kennenrj-*. Korpus 1.274 → 1.622 Einträge / 77 Cluster; Reindex: 16.480 Chunks, 1.496 neue Embeddings in 75 s. Retrieval-Goldset erweitert um q-120–123: Hit-Rate 0,956 · Recall@8 0,922 (Gate ✓) · MRR 0,661, alle vier neuen Fälle gefunden. Gezielte Antwortläufe q-120–123: alle zitiergültig, nicht verweigert, keine Regenerierung; Systemprompt verlangt für als nicht amtlich markierte Quellen die gleiche Einschränkung in der Antwort (q-123 verifiziert). Voller Antwortmodus-Eval (50 Fragen): 100 % Zitier-Präzision, 100 % Verweigerung korrekt, erwartete Quelle 93,3 %, mean 39,4 s / p95 82,2 s, 5 Regenerierungen; Reportdata/eval-qwen38-rj.json(lokal/unversioniert). Offline-Tests: 65 grün. Nicht als generelle Commit-Freigabe lesen: Die gelieferten OGH/VwGH/VfGH-Dateien nennen überwiegend RIS-OGD, der User sprach jedoch von Lexis/opendataloader; die Publikations-/Lizenzfreigabe der quellentreuen Volltexte ist vor Commit ausdrücklich zu prüfen. EuGH-Wiedergaben sind als nichtamtlich markiert und verweisen auf EUR-Lex.
Completed (2026-09-16)
-
D16 (Gestaltungsfragen / Retrieval-Tuning): Goldset um q-124–126 erweitert (500-Euro-Zusatzzahlung, Alternativen, Mitarbeiterprämie 2026).
agent/query_planner.pyerkennt Decision-Support deterministisch und zerlegt in drei gesetzlich gescopte Queries: Mitarbeiterprämie samt §-49-Konflikt, Zukunftssicherung sowie Sach-/zweckgebundene Leistungen. Decision-Support läuft alsspecific, nicht als Survey/Map-Reduce.Retriever.search()nutzt denselben Plan im Offline-Eval;search_multi()behält Scope/Jahr auch bei einer einzelnen Query. Ergebnis (53 Goldsetfragen / 48 Retrieval-Fälle): q-124/q-125/q-126 jeweils Recall@8 1,00, gesamt Recall@8 0,9271 (Gate >0,9), Hit-Rate 0,9583, MRR 0,6158. Bekannte Altfehler q-015/q-113 bleiben unverändert. -
Decision-Support-Grounding: Systemprompt trennt Barzahlung von zweckgebundenen Leistungen, verbietet pauschale Sieger ohne Kontext, verlangt vergleichbare Abgabendimensionen und genau eine Rückfrage. Der bekannte Konflikt Mitarbeiterprämie 2026 wird offen dargestellt:
wk-akt-04nennt SV/BV/DB/DZ/KommSt-Pflicht,lb-sva-03ordnet die Prämie systematisch in den taxativen Katalog beitragsfreier Bezüge ein. Zusätzlich erzwingt ein semantischer Post-Validation-Gate ⚠ + beide IDs + korrekte Rollen und verhindert interne Regelverweise bzw. Quellenpriorisierung. Gezielte Real-Läufe: q-124/q-125 nicht verweigert, zitiergültig; q-126 war bereits sauber. Tests 72 grün;git diff --checksauber. -
D16 Voll-Eval (2026-09-16): 53 Fragen mit
qwen3.8:27b; Reportdata/eval-qwen38-decision-support.json(lokal/gitignored). Retrieval: Hit-Rate 0,9583, Recall@8 0,9271, MRR 0,6266. Antworten: Zitier-Präzision 98,11 %, Verweigerung korrekt 98,11 %, erwartete Quelle 91,67 %, mean 40,3 s / p95 98,4 s, 4 Regenerierungen. Einziger Gate-Fehler: q-125 eskalierte nach zwei semantisch unzureichenden Antworten zuUNCERTAIN(verified=false). Direkte Wiederholung von q-125 war mit einer Regenerierung vollständig, zitiergültig und stellte den Konflikt korrekt dar — verbleibend ist stochastische Gate-/Regenerierungs-Flakiness, kein Retrieval-Fehler. q-124 und q-126 bestanden im Voll-Eval. -
D16 Stabilisierung/Bestätigung (2026-09-16): Bei vollständig ausgelassenem, aber retrieved Mitarbeiterprämien-Konflikt ergänzt die Pipeline deterministisch eine feste, ausschließlich aus
lb-sva-03undwk-akt-04formulierte ⚠-Notiz. Eigene Konfliktversuche bleiben ungeändert und werden weiter auf Rollenfehler/Priorisierung geprüft. Der semantische Gate akzeptiert gleichwertige Verben (ordnet,listet,führt) statt fragiler exakter Wortwahl. Sonden: q-124 3/3 ohne Regenerierung, q-125 3/3 verifiziert, q-126 verifiziert. Voller Bestätigungslauf (53 Fragen), Reportdata/eval-qwen38-decision-support-confirm.json: Zitier-Präzision 100 %, erwartete Quelle 93,75 %, mean 40,3 s / p95 69,6 s, 3 Regenerierungen; q-124–126 alle bestanden. Verweigerungskorrektheit 98,11 % nur wegen der bekannten stochastischen Survey-Fehlverweigerung q-029; direkte q-029- Wiederholung antwortete verifiziert (aber sehr langsam, 280 s). -
q-015 fachlich rekalibriert: Eine allgemeine Tagesgeldfrage mischt zwei Ebenen: Der KV regelt vorrangig den arbeitsrechtlichen Anspruch, das EStG den steuerfreien Satz. Branchen-KV-Treffer sind deshalb korrekt; q-015 hat keine künstliche Einzel-Pflicht-ID mehr. Neue q-127 prüft ausdrücklich nur die steuerliche Höhe und findet
lb-rei-09. Goldset 54 Fragen; Offline-Retrieval nun Hit-Rate 0,9792, Recall@8 0,9479, MRR 0,6653. Tests 75 grün. -
llama.cpp-LLM-Eval (2026-09-16): Lokaler/privater OpenAI-kompatibler Server aus
.envgetestet (Zugangsdaten/URLs nicht dokumentiert oder versioniert); nur das LLM wurde gewechselt, Retrieval und bge-m3-Index blieben unverändert. llama.cpp benötigtchat_template_kwargs.enable_thinking=false; Chatmodell meldet sich alsqwen3.8. 54-Fragen-Report:data/eval-llamacpp-qwen38.json(lokal/gitignored). Zitier-Präzision 100 %, Verweigerung korrekt 96,3 %, erwartete Quelle 91,67 %, mean 54,9 s / p95 104,8 s, 2 Regenerierungen. q-124–126 bestanden alle ohne Regenerierung. Fehlverweigerungen: q-029 (bekannte Survey-Flakiness, 357 s) und q-102. q-102 ist kein LLM-Defizit: Mit Planner lieferte der KV-Scope viele ähnlich benannte KVs und nur einen irrelevanten Abschnitt von kv-kvt-197; ohne Planner beantwortete dasselbe llama.cpp-Modell die Frage in 14,8 s korrekt aus kv-kvt-056. Schluss: llama.cpp ist grounding-stabil, aber langsamer als die Ollama-Basislinie; q-102 erfordert später Planner-/Retrieval-Tuning, nicht Modell-Tuning. -
llama.cpp-Rerun nach Server-Tuning (2026-09-16): Report
data/eval-llamacpp-qwen38-rerun.json(lokal/gitignored), gleicher Aufbau wie zuvor: nur LLM über llama.cpp, Retrieval/bge-m3 unverändert. Ergebnis: Zitier-Präzision 100 %, Verweigerung korrekt 98,15 %, erwartete Quelle 95,83 %, mean 53,5 s / p95 105,4 s, 6 Regenerierungen. Gegenüber dem ersten Lauf: q-029 geheilt, erwartete Quelle +4,16 Prozentpunkte, mean ca. 1,3 s schneller; q-102 bleibt als einzige Fehlverweigerung reproduzierbar (Planner-/Kontextproblem). q-124–126 bestehen weiterhin; q-125/q-126 benötigten diesmal je eine Regenerierung. Das Server-Tuning ist damit qualitativ besser, erhöht aber die Regenerierungen (2 → 6); Latenz bleibt deutlich über der Ollama-Basislinie. -
llama.cpp Full-Stack (Chat + Embeddings, 2026-09-16): llama.cpp- Embeddings sind trotz gleicher Dimension 1024 inkompatibel zu Ollama
bge-m3(Same-Text-Cosinus nur ca. -0,004 bis 0,017); deshalb separater, lokaler Indexdata/index-llamacpp.db. Vollständig 16.480 Chunks; der Embedding-Server lehnt einzelne Texte > ca. 9.000 Zeichen ab, daher wurden nur für diesen Test längere Embedding-Inputs deterministisch auf 9.000 Zeichen gekürzt (KB und Produktionsindex unverändert). Indexbau ca. 17,4 min. Retrieval ohne Neukalibrierung: Hit-Rate 0,9583, Recall@8 0,9323, MRR 0,5977 (Gate >0,9 erfüllt). Vollreportdata/eval-llamacpp-fullstack.json(lokal/gitignored): Zitier-Präzision 100 %, Verweigerung korrekt 94,44 %, erwartete Quelle 87,5 %, mean 44,6 s, p95 130,8 s, 3 Regenerierungen. Full-Stack ist schneller als llama.cpp-LLM + bge-m3 (53,5 s), aber fachlich schwächer: Fehlverweigerungen q-029, q-102, q-111. q-102: korrektes Dokument kv-kvt-056, aber falscher repräsentativer Abschnitt; q-111: Embedding-Retrieval verfehlt kv-kvt-001 komplett und liefert fremde Lehrlingstabellen. Decision-Support q-124–126 besteht weiter. Fazit: Full-Stack ist testfähig und erfüllt das Retrieval- Recall-Gate, ersetzt bge-m3 aber noch nicht; zuerst eigene RRF-/Dense- Kalibrierung und KV-Metadaten-/Representative-Section-Tuning nötig. -
llama.cpp Full-Stack Rerun (2026-09-16): identischer separater Index und unveränderte Parameter; Report
data/eval-llamacpp-fullstack-rerun.json. Zitier-Präzision 100 %, Verweigerung korrekt 98,15 %, erwartete Quelle 91,67 %, mean 49,5 s / p95 101,2 s, nur 1 Regenerierung. Gegenüber erstem Full-Stack-Lauf: q-029 und q-111 geheilt, Fehlverweigerungen 3 → 1, erwartete Quelle +4,17 Prozentpunkte, Regenerierungen 3 → 1; Latenz dagegen 44,6 → 49,5 s. Einziger reproduzierbarer Fehler bleibt q-102 (korrektes Dokument, falscher Representative-Section-Kontext). q-124–126 alle ohne Regenerierung bestanden. Full-Stack erreicht damit dieselbe Verweigerungs- korrektheit wie der aktualisierte llama.cpp-LLM+bge-m3-Lauf, bleibt aber bei erwarteter Quelle darunter (91,67 % vs. 95,83 %). -
D17 (Runtime-Entscheidung, 2026-09-16): Nach den llama.cpp-LLM- und Full-Stack-Vergleichen bleibt der Agent bei Ollama mit
qwen3.8:27b+bge-m3. Gründe: beste bzw. stabilere Gesamtbalance aus erwarteter Quellentreue, Verweigerungskorrektheit und Latenz; llama.cpp- Full-Stack zeigte embedding-spezifische KV-/Representative-Section-Fehler und höhere Flakiness. Der letzte angeforderte Full-Stack-Rerun wurde nach drei Fragen vom User abgebrochen und nicht gewertet. Lokale llama.cpp- Indizes/Reports und.envbleiben unversioniert; keine Integration in die Produktionskonfiguration. -
Finaler Ollama-54-Eval (2026-09-16): Nach Rückkehr zum Ziel-Stack
qwen3.8:27b+bge-m3, Reportdata/eval-qwen38-final-54.json(lokal/gitignored). Retrieval: Hit-Rate 0,9792, Recall@8 0,9479, MRR 0,6378. Antworten: Zitier-Präzision 100 %, Verweigerung korrekt 100 %, erwartete Quelle 95,83 %, mean 38,8 s, p95 67,2 s, 2 Regenerierungen. q-029 sowie q-124–127 bestanden; damit beide Haupt-Gates erstmals im finalen 54er-Set vollständig erfüllt. Zwei Quellentreue- Abweichungen ohne Grounding-Verstoß: q-127 zitiert alternative Reisekosten- Quellen (lb-rei-01/03,wk-rei-01plus KVs) statt erwarteterlb-rei-09; q-025 zitiert Betriebsübergangs-/Insolvenzquellen statt der bisherigen Expected-ID. Optional später Goldset-Expected-IDs fachlich rekalibrieren, aber kein Release-Blocker. -
D18 (Rechtsprechungsnutzung, 2026-09-16, User-Freigabe): Auf gerichtliche Entscheidungen darf in Antworten verwiesen werden. Ihr Inhalt darf in eigenen Worten wiedergegeben und stellenweise zitiert werden. Die Agentenantwort muss weiterhin die retrieved
rj-*-/RIS-KB-ID nennen, nichtamtliche Wiedergaben ausdrücklich kennzeichnen und darf keine nicht retrieved Entscheidung ergänzen. Diese Freigabe umfasst Referenz, Zusammenfassung und auszugsweise Zitate; sie ist keine pauschale Freigabe zur Veröffentlichung vollständiger quellentreuer Entscheidungstexte.
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 (
*:cloudauf 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 — Reportdata/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-embedsetztembed_offim Config-Copy. - D6: Leeres Retrieval → deterministische Verweigerung ohne LLM-Call.
- D7 (Bake-off 2026-09-14):
qwen3.8:27bist das fixierte Antwortmodell (100 % Zitier-Präzision, 94,3 % Verweigerung korrekt).gemma4:26bals 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_chunkwählt pro Eintrag die beste Inhaltssektion (Zusammenfassung > Kernwerte > RechtsgrundlagenPayroll > 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-Toolbuild_lexis_kb.pylebt im Schwesterprojekt), eingefrorene Katalogetools/catalogs/*.json(nur Metadaten, versioniert). IDs:kv-kvt-<nnn>(ein Clusterkollektivvertraege, Branche als Tag),ris-<cluster-prefix>-<nn>auf der bestehenden Cluster-Map + 7 neue Cluster;LAW_MAPintools/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. Reportdata/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-YYYYreichte 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 matchenjahr-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). - D13 (Antworttyp-Routing / Stufe 2, 2026-09-15): (a) Planer liefert
jetzt
type: survey|specific; Survey-Fragen („Welche Neuerungen …“) laufen ueber Map-Reduce: breiteres Retrieval (survey_blocks=16, PV_SURVEY_BLOCKS), ein Map-Call destilliert JE Block als Stichpunkte mit seiner KB-ID (MAP_SYSTEM_PROMPT), ein Reduce-Call synthetisiert daraus die Antwort mit dem normalen Grounding-Prompt; Zitier- Validierung weiterhin strikt ueber die Retrieved-Union, leerer Map-Output -> Fallback Einzelantwort. (b) Systemprompt-Regel 9: bei wesentlicher Kontextabhaengigkeit (Branche, Bundesland, Zeitraum) belegte allgemeine Aussage + EINE Rueckfrage statt Verweigerung (API-first; Odoo-Chat kann die Rueckfrage als Follow-up nutzen). Ergebnis: q-029 geheilt (vorher jahrelange Fehlverweigerung; jetzt Teilantwort mit 5 belegten Heften, 95 s — Map-Reduce-Latenz nur bei Survey-Fragen), q-015 antwortet mit expliziter KV-Abhaengigkeit + Rueckfrage statt Branchen-Noise. Eval (46 Fragen): Zitier-Praezision 97,8 %, Verweigerung 97,8 % (Gate erfuellt), erwartete Quelle 90,2 %, Latenz mean 34,2 s. Tests 57 -> 59. Reportdata/eval-qwen38-stage2.json. Verbleibend: q-024 transiente Flakiness (Think-Ghost-Verdacht, 2/3 Laeufe sauber). - D14 (Output-Budget + length-Retry, 2026-09-15): q-024-Flakiness
Ursache gefunden — NICHT Thinking (Hypothese widerlegt: thinking-Feld
leer, keine Tags), sondern
num_predict=1024: lange belegte Antworten wurden beidone_reason=lengthabgschnitten (q-024: 3/3 Sondenlaeufe) → unvollstaendige Zitationen → CITE_RE matcht partielle IDs → Verletzung → Regen-Eskalation → UNCERTAIN. Fix: (a) num_predict 1024 → 2048; (b)OllamaClient.chat_full()liefert (content, done_reason); (c)chat_with_length_retry: ein technischer Retry mit 2× num_predict bei length (zaehlt nicht als Regel-Regenerierung, laeuft auch im Map- und im Regenerierungspfad). Voll-Eval: Zitier-Praezision 100 %, Verweigerung korrekt 100 % (46/46 — alle M3-Gates erfuellt, erstmals ueber Basislinie), erwartete Quelle 92,7 %, Latenz mean 39,6 s / p95 78 s (+5 s: vollstaendige statt abgeschnittener Antworten). q-024: 4/4 stabil. Tests 59 → 60. Reportdata/eval-qwen38-lengthfix.json. - D19 (API-first-Vertrag, 2026-09-16):
/v1/ask,/v1/healthund/v1/reindexsind die stabilen Endpunkte; alte Pfade bleiben deprecated. Der Ask-Response enthält Status, Quellen, belegte Konflikte, extrahierte Rückfrage, Planungs- und Grounding-Metadaten sowie eine Request-ID. Optionaler Bearer-Schutz überPV_API_KEY; Reindex kann mitPV_ADMIN_API_KEYgetrennt werden. Leere Keys sind nur lokaler Entwicklungsmodus. Health und öffentliche Fehler nennen keine internen Hosts/Exceptions. v1 ist zustandslos,knowledge_base_only, lehnt unbekannte JSON-Felder ab und akzeptiert keine Payroll-/Mitarbeiterobjekte. Odoo-Lohndaten erfordern später einen separaten tenant-autorisierten Vertrag mit Datensatzregeln, Datenminimierung, Audit und Cross-Tenant-Tests. Vertrag:docs/API.md. Der gemeinsame SQLite-Retriever ist durchcheck_same_thread=FalseplusRLockworker-thread-sicher. Neue Nicht-lokaler CLI-Bind ohnePV_API_KEYwird fail-closed abgelehnt. Neue API-/Concurrency-Tests erhöhen die Offline-Suite von 75 auf 82 grüne Tests. - D20 (Test-Frontend, 2026-09-16): FastAPI liefert unter
/ein dependency-freies, responsives Frontend ausweb/aus. Es nutzt same-origin/v1/askund/v1/health, zeigt Status, Quellen, Konflikte, Rückfragen, Suchplan und Grounding-Metadaten und hält den Verlauf nur im DOM. Ein optional gemerkter Service-Key liegt ausschließlich imsessionStoragedes Tabs; kein Secret wird in die Assets injiziert. Modelltext wird ohneinnerHTMLgerendert. CSP gilt gezielt für UI/Assets, damit/docsnutzbar bleibt; globale Header setzennosniff,DENYundno-referrer. Betrieb auf dem Tailscale-Interface:python -m agent.cli serve --host 100.103.83.12mit gesetztemPV_API_KEY; UI auf Port 8080. Tests 82 → 84. - D21 (Docker-Compose-Deployment, 2026-09-16):
compose.yamlbaut einen gemeinsamen UI-/API-Container, bindet Port 8080 nur an100.103.83.12und trat zunächst dem externen Netzollama-defaultbei; D22 korrigiert den tatsächlichen Namen aufollama_default. Ollama wird nicht dupliziert;OLLAMA_URList konfigurierbar (Beispielhttp://ollama:11434, Alias auf Zielhost noch zu verifizieren).data/ist schreibbar,wissensbasis/read-only; Root-FS read-only, Capabilities entfernt, no-new-privileges, unprivilegierterPUID:PGID, verpflichtenderPV_API_KEY..dockerignorehält.env, Index, Layer-1-Korpora und KB aus dem Image; Runtime-Image nutztrequirements-runtime.txt. Composeconfig --quiet, Image-Build und read-only Import-/Asset-Smoke-Test bestanden. Deployment:docs/DOCKER.md. Statische Deploymenttests erhöhen die Suite von 84 auf 87 Tests. - D22 (Bootstrap, Audit und Bewertungen, 2026-09-16): Das Container-CMD
führt vor FastAPI
agent.bootstrapaus. Ein Index gilt nur bei vorhandenen Chunks und vollständiger Vektorabdeckung fürPV_EMBED_MODELals bereit; andernfalls wird er im externen Netzollama_defaultautomatisch aufgebaut. Embedding-Fehler stoppen den Container statt BM25-only in Produktion zu starten.agent.auditprotokolliert Interaktionen und Bewertungen indata/audit.dbmit konfigurierbarer 30-Tage-Aufbewahrung und optionalenAUDIT-JSON-Zeilen nach stdout.PV_AUDIT_LOG_CONTENT=falseentfernt alle Freitexte inklusive indirekter Inhalte in Suchplan/Quellen/Konflikten. Die authentisierte API/v1/ratingsspeichertup|downplus optionalen Kommentar; das Frontend zeigt die Funktion nur bei aktiviertem Audit. Keys/Header werden nie geloggt. Docker-JSON-Logs rotieren bei 50 MB × 5. Letzte Einträge:python -m agent.cli audit --limit 20. Offline-Suite 93 Tests; Compose- Validierung, Image-Rebuild und unprivilegierter read-only Bootstrap-Smoke-Test gegen den bestehenden vollständigen Index bestanden. - D23 (Antwortkommentare, 2026-09-16): Zusätzlich zu
up|downbesitzt jede protokollierte Antwort eine immer sichtbare Kommentarbox. Der authentisierte Endpunkt/v1/commentsspeichert mehrere, jeweils datierte Kommentare pro Request-ID in der separaten Audit-Tabellecomments; leere Texte werden abgewiesen, Maximallänge 2.000 Zeichen.agent.cli auditgibt Kommentare gemeinsam mit Interaktion und Bewertung aus. Bei deaktivierter Inhaltsprotokollierung bleiben Kommentarereignis und ID sichtbar, der Text wird weder in SQLite noch stdout gespeichert. - D24 (Kostenaufstellung + think-Fix, 2026-09-16): (a)
is_decision_supportmatcht aufnormalize_text(question); die Regex deckt neben NFKD-Folding (gunstig/losung) auch ue-Schreibweisen (guenstigste loesung) ab — vorher liefen solche Fragen in den generischen LLM-Planer und wurden verweigert. (b) Neue Trigger: "einmalig ... auszah", "bar auszah", "wieviel/wie viel ... kostet", "kostet mich", "mitarbeiterpra(e)m". (c) COST_INTENT: deterministischer Plan ergänztcost_tax(einmalige Bezüge, Jahressechstel 6 %, 620 — trifft lb-son-04) undcost_lnk(Beitragssätze DN- Dienstgeberanteil, DB/DZ, KommSt — trifft lb-sva-06, lb-lnk-02/07); bei Kostennnabsicht fällt Zukunftssicherung weg (Slots), Cap 4 Queries. (d) Regel 11: konkrete Eckdaten → Arbeitgeberkosten Schritt für Schritt aus belegten Sätzen rechnen, Annahmen nennen, Rückfrage nur bei wesentlichem Fehlen. (e) generate.chat(): OllamaError bei think=true (leerer content, Antwort nur im thinking-Feld) → einmaliger Retry ohne thinking. (f) Goldset q-128/q-129 (beide recall=1,00). Offline-Eval 56 Fragen: Hit-Rate 0,98 · Recall@8 0,95 · MRR 0,67. Real-Läufe: Q1 (günstigste) verified, 1 Regen; Q2 (Kosten) verified mit AG-SV-Rechnung; PV_THINK=true verified (281 s).
- 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..oddo-module/(Symlink) — Odoo-19-Addon-Bestand;planung.mdAbschnitt 14 — M4/D25-Planung;l10n_at_hr_payroll_private/models/kollektivvertrag.py— KV-Katalog mitlibrary_variant_id(Brücke zu KB).docs/API.md— v1-Vertrag, Authentisierung, Privacy-Grenze und Odoo-Aufruf.agent/api.py— versionierte Service-Oberfläche, UI-Auslieferung und Sicherheitsgrenzen.web/— dependency-freies Test-Frontend.compose.yaml,Dockerfile,.env.example,.dockerignore— Zielhost-Stack und automatischer Bootstrap.agent/bootstrap.py,agent/audit.py— Indexbereitschaft, Q&A-Log und Bewertungen.docs/DOCKER.md— Deployment, Indexaufbau und Smoke-Tests.agent/eval/goldset.yaml— Goldset (IDs gegen kb.json verifiziert).agent/generate.py— Grounding-Kern (Prompt, Post-Validierung).wissensbasis/README.md— Layer-2-Schema + Rechtsprechungs-Provenance.tools/ingest_sources.py/tools/catalogs/rj_catalog.json— rj-Intake und gefrorene IDs.agent/eval/goldset.yaml— q-120–123; als Nächstes Antwortmodus-Eval.