mirror of
http://100.103.83.12:3003/fegger/pv-agent.git
synced 2026-09-17 16:06:23 +00:00
586 lines
39 KiB
Markdown
586 lines
39 KiB
Markdown
# 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/D25: M4.2 (Agent-Review-Modus) umgesetzt und committet (ba4bf57);
|
||
107 Tests grün; KV-Varianten-Mapping gebaut (439/614, Seeds getestet).
|
||
**M4.1-Gerüst steht** (2026-09-16): neues Odoo-19-Addon
|
||
`l10n_at_payroll_agent` (19.0.1.0.0) im odoo-at-payroll/addons-Repo — über
|
||
den Symlink gebaut, 11 Dateien: `pv.agent.client` (stdlib urllib,
|
||
res.company.pv_agent_url/api_key statt unverifiziertem ir.config_parameter),
|
||
`pv.agent.context.builder` (Draft→Review-Kontext; ATP_PRAMIE, version.wage/
|
||
kv_id, SVDG_*/LST_*/LNK-Linien), `pv.agent.review.wizard` (+Views/ACL/Menu)
|
||
und TransactionCase-Tests (patched `_post_json`). Alle APIs gegen den
|
||
Bestand verifiziert; Syntax/XML/CSV-Checks grün — Odoo-Test-Session und
|
||
Pilot-Verifikation am echten Draft-Lohnzettel folgen (User-Host).
|
||
|
||
## Completed (2026-09-16, Modul-Review/D25-Planung)
|
||
|
||
- **`.oddo-module/` verlinkt** (Symlink → ../odoo-at-payroll/addons, in
|
||
`.gitignore` aufgenommen). Review gegen M4: Odoo 19.0 (Kern 19.0.10.0.0 auf
|
||
`hr_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 via `ir.rule` (company_ids), Feldgruppen
|
||
`group_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-Katalog `l10n.at.payroll.kv` mit versionierten `kv.wert`, Gruppen/Stufen
|
||
und CSV-Import-Wizard (Sprungwarnung >10 %); `library_variant_id` verlinkt
|
||
auf die KV-Library (SI-2203/SI-2748). D25-Planung steht in `planung.md`
|
||
Abschnitt 14: neues Modul `l10n_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=review` plus context-Schema, drei Beweisklassen, Injection-Abgrenzung
|
||
und Feature-Flag `PV_REVIEW_MODE` (default aus). Nicht-Ziele fixiert.
|
||
- **M4.2 Agent-Review-Modus (2026-09-16, D25):** `AskRequest.mode`
|
||
`knowledge|review` + `context` (StrictModel: facts ≤40, key-Muster,
|
||
computation + components ≤40; keine freien Objekte). `answer_question`
|
||
nimmt `context` an: 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_checks` extrahiert 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 mit
|
||
`not_checkable`-Verdict bestehen (keine UNCERTAIN-Eskalation). API-Gating:
|
||
review ohne `PV_REVIEW_MODE` → 422; knowledge+context → 422; review ohne
|
||
context → 422. `grounding.data_scope` review:
|
||
`knowledge_base_plus_review_context`. Audit: `context_json`-Spalte mit
|
||
idempotenter Migration, Metadatenmodus ohne Kontext-Freitext. CLI:
|
||
`ask --context FILE`. Response-Felder `mode` + `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.py` erzeugt daraus
|
||
`tools/catalogs/kv_variant_map.json`: 105 Varianten (98 matched, 7 low),
|
||
439/614 KB-Einträge abgedeckt; je Variante `docs` mit kv_kvt_id + slug +
|
||
doctype als Paare, Low-Confidence markiert, Rest in `unmatched_kb_entries`
|
||
(WKO-aktuelle Dokumente ohne ÖGB-Gegenstück, z. B. KV-Abschluss-News).
|
||
Odoo kann pro `library_variant_id` die zugehörigen KB-Einträge auflösen;
|
||
Seed-Abdeckung SI-2203/SI-2748 testet
|
||
`tests/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-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/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.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-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).
|
||
|
||
- **D15 (Rechtsprechungs-Intake, 2026-09-15):** `.rechtsprechung/` → neuer
|
||
ID-Raum `rj-rjs-*`, gemeinsamer Cluster `rechtsprechung`: 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.json` friert die IDs ein;
|
||
Registry/Index und Agent-Zitatvalidierung kennen `rj-*`. 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; Report
|
||
`data/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.py` erkennt Decision-Support deterministisch und zerlegt
|
||
in drei gesetzlich gescopte Queries: Mitarbeiterprämie samt §-49-Konflikt,
|
||
Zukunftssicherung sowie Sach-/zweckgebundene Leistungen. Decision-Support
|
||
läuft als `specific`, 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-04` nennt SV/BV/DB/DZ/KommSt-Pflicht, `lb-sva-03` ordnet 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 --check` sauber.
|
||
- **D16 Voll-Eval (2026-09-16):** 53 Fragen mit `qwen3.8:27b`; Report
|
||
`data/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
|
||
zu `UNCERTAIN` (`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-03` und
|
||
`wk-akt-04` formulierte ⚠-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), Report
|
||
`data/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 `.env` getestet (Zugangsdaten/URLs nicht dokumentiert oder
|
||
versioniert); nur das LLM wurde gewechselt, Retrieval und bge-m3-Index
|
||
blieben unverändert. llama.cpp benötigt
|
||
`chat_template_kwargs.enable_thinking=false`; Chatmodell meldet sich als
|
||
`qwen3.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 Index `data/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). Vollreport
|
||
`data/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 `.env` bleiben unversioniert; keine Integration in die
|
||
Produktionskonfiguration.
|
||
|
||
- **Finaler Ollama-54-Eval (2026-09-16):** Nach Rückkehr zum Ziel-Stack
|
||
`qwen3.8:27b` + `bge-m3`, Report `data/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-01` plus KVs) statt erwarteter
|
||
`lb-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** (`*: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).
|
||
- **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.
|
||
Report `data/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 bei `done_reason=length` abgschnitten (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. Report `data/eval-qwen38-lengthfix.json`.
|
||
- **D19 (API-first-Vertrag, 2026-09-16):** `/v1/ask`, `/v1/health` und
|
||
`/v1/reindex` sind 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 über `PV_API_KEY`; Reindex kann mit `PV_ADMIN_API_KEY` getrennt
|
||
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 durch `check_same_thread=False` plus `RLock` worker-thread-sicher. Neue
|
||
Nicht-lokaler CLI-Bind ohne `PV_API_KEY` wird 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 aus `web/` aus. Es nutzt same-origin
|
||
`/v1/ask` und `/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 im `sessionStorage` des
|
||
Tabs; kein Secret wird in die Assets injiziert. Modelltext wird ohne
|
||
`innerHTML` gerendert. CSP gilt gezielt für UI/Assets, damit `/docs` nutzbar
|
||
bleibt; globale Header setzen `nosniff`, `DENY` und `no-referrer`. Betrieb
|
||
auf dem Tailscale-Interface: `python -m agent.cli serve --host
|
||
100.103.83.12` mit gesetztem `PV_API_KEY`; UI auf Port 8080. Tests 82 → 84.
|
||
- **D21 (Docker-Compose-Deployment, 2026-09-16):** `compose.yaml` baut einen
|
||
gemeinsamen UI-/API-Container, bindet Port 8080 nur an `100.103.83.12` und
|
||
trat zunächst dem externen Netz `ollama-default` bei; D22 korrigiert den
|
||
tatsächlichen Namen auf `ollama_default`. Ollama wird nicht dupliziert;
|
||
`OLLAMA_URL` ist konfigurierbar (Beispiel `http://ollama:11434`, Alias auf
|
||
Zielhost noch zu verifizieren). `data/` ist schreibbar, `wissensbasis/`
|
||
read-only; Root-FS read-only, Capabilities entfernt, no-new-privileges,
|
||
unprivilegierter `PUID:PGID`, verpflichtender `PV_API_KEY`. `.dockerignore`
|
||
hält `.env`, Index, Layer-1-Korpora und KB aus dem Image; Runtime-Image nutzt
|
||
`requirements-runtime.txt`. Compose `config --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.bootstrap` aus. Ein Index gilt nur bei vorhandenen
|
||
Chunks und vollständiger Vektorabdeckung für `PV_EMBED_MODEL` als bereit;
|
||
andernfalls wird er im externen Netz `ollama_default` automatisch aufgebaut.
|
||
Embedding-Fehler stoppen den Container statt BM25-only in Produktion zu
|
||
starten. `agent.audit` protokolliert Interaktionen und Bewertungen in
|
||
`data/audit.db` mit konfigurierbarer 30-Tage-Aufbewahrung und optionalen
|
||
`AUDIT`-JSON-Zeilen nach stdout. `PV_AUDIT_LOG_CONTENT=false` entfernt alle
|
||
Freitexte inklusive indirekter Inhalte in Suchplan/Quellen/Konflikten. Die
|
||
authentisierte API `/v1/ratings` speichert `up|down` plus 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|down` besitzt
|
||
jede protokollierte Antwort eine immer sichtbare Kommentarbox. Der
|
||
authentisierte Endpunkt `/v1/comments` speichert mehrere, jeweils datierte
|
||
Kommentare pro Request-ID in der separaten Audit-Tabelle `comments`; leere
|
||
Texte werden abgewiesen, Maximallänge 2.000 Zeichen. `agent.cli audit` gibt
|
||
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_support` matcht auf `normalize_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änzt `cost_tax` (einmalige Bezüge,
|
||
Jahressechstel 6 %, 620 — trifft lb-son-04) und `cost_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.md` Abschnitt 14
|
||
— M4/D25-Planung; `l10n_at_hr_payroll_private/models/kollektivvertrag.py` —
|
||
KV-Katalog mit `library_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. |