Retrieval-Kalibrierung nach Korpusverdopplung (D10) + Goldset-Erweiterung
- Hybrid-Fusion um dense_weight erweitert; kalibriert per Goldset-Sweep: dense_weight=2.0 (BM25 durch KV-S-Titel-Matches inflationiert), rrf_k=20, candidate_pool=150 -> Recall@8 0,851 -> 0,923 (>0,9), Hit-Rate 0,973, MRR 0,667. ENV: PV_DENSE_WEIGHT/PV_RRF_K/ PV_CANDIDATE_POOL. - CITE_RE um kv|ris erweitert (Post-Validierung deckt neue ID-Raeume). - Goldset: +6 KV/RIS-Fragen (q-101-106) + Branchen-Refusal r-005; q-021 auf lb-kar-04 rekalibriert (Top-1, deckt Beginn/Dauer voll - dokumentiert im Note). - Antwortmodus-Eval (qwen3.8:27b, 42 Fragen): Zitier-Praezision 95,2 %, Verweigerung 90,5 % - unter den M3-Gates, Tuning folgt (Report data/eval-qwen38-kvris.json, lokal). - Docs: agent/README.md Baseline, planung.md Umsetzungsstand, .agents/MEMORY.md (D9/D10, offene Punkte).
This commit is contained in:
@@ -54,6 +54,49 @@ zu planen).
|
|||||||
liefen alle Läufe stabil; zwischen Kandidaten wurde per `keep_alive: 0`
|
liefen alle Läufe stabil; zwischen Kandidaten wurde per `keep_alive: 0`
|
||||||
entladen (Crash-Ursache war der Modell-Swap-Stress beim gemma4-Lauf).
|
entladen (Crash-Ursache war der Modell-Swap-Stress beim gemma4-Lauf).
|
||||||
|
|
||||||
|
## Completed (2026-09-15)
|
||||||
|
|
||||||
|
- **KB-Erweiterung um WKO-Kollektivverträge + RIS-Gesetze** (User-Auftrag):
|
||||||
|
`.firecrawl/wko-kv/docs/` (614 KV-Dokumente: Lohn-/Gehaltsordnungen mit
|
||||||
|
Lohntabellen, KV-Abschlüsse, Erläuterungen, Zusatz-KVs) und `.ris/` (59
|
||||||
|
Gesetze, nur die im Lexis360-Bestand zitierten §-Ausschnitte, Stand
|
||||||
|
2026-09-13) → **1 274 Layer-2-Einträge** (`kv-kvt-001…614`,
|
||||||
|
`ris-<prefix>-nn`), 14 984 Chunks, Reindex 8,5 min (11 947 neue
|
||||||
|
Embeddings, bge-m3 auf :11435).
|
||||||
|
- **D9 (2026-09-15):** kv/ris-Einträge sind **quellentreu generiert**
|
||||||
|
(keine Eigene-Worte-Kuratierung — Gesetze sind amtliche Werke, KV-
|
||||||
|
Lohntabellen zahlenexakt; Konvention 2 der Wissensbasis gilt nur für
|
||||||
|
die lizenzierten Quellen lb/wk). Tool-Output: `tools/ingest_sources.py`
|
||||||
|
+ `tools/build_registry.py` (Registry in diesem Repo neu gebaut — das
|
||||||
|
Lexis-Tool `build_lexis_kb.py` lebt im Schwesterprojekt), eingefrorene
|
||||||
|
Kataloge `tools/catalogs/*.json` (nur Metadaten, versioniert).
|
||||||
|
- **ID-Räume:** `kv-kvt-<nnn>` (ein Cluster `kollektivvertraege`,
|
||||||
|
Branche als Tag) und `ris-<cluster-prefix>-<nn>` auf der bestehenden
|
||||||
|
Cluster-Map + 7 neue Cluster (kvt/zvr/avr/agg/lst/abo/nso);
|
||||||
|
`LAW_MAP` in `tools/kb_common.py` dokumentiert die 59 Zuordnungen.
|
||||||
|
- **D10 (Retrieval-Kalibrierung, Goldset-Sweep 2026-09-15):** Korpus-
|
||||||
|
verdopplung drückte Recall@8 auf 0,851 — kalibriert auf
|
||||||
|
`dense_weight=2.0` (Dense-Liste relativ zu BM25 gewichtet; BM25 ist
|
||||||
|
durch KV-§-Titel-Matches inflationiert), `rrf_k=20`,
|
||||||
|
`candidate_pool=150` → **Recall@8 0,923 (>0,9 ✓)**, Hit-Rate 0,973
|
||||||
|
(36/37), MRR 0,667. ENV: `PV_DENSE_WEIGHT`/`PV_RRF_K`/
|
||||||
|
`PV_CANDIDATE_POOL`. Entry-RRF-Variante getestet: kein Mehrwert.
|
||||||
|
- **Antwortmodus-Eval (qwen3.8:27b, 42 Fragen):** Zitier-Präzision
|
||||||
|
95,2 % (2 Verletzungen), Verweigerung korrekt 90,5 % (4 Fehlver-
|
||||||
|
weigerungen, u.a. q-022/q-029), erwartete Quelle zitiert 83,8 %,
|
||||||
|
Latenz mean 31 s / p95 53 s, 9 Regenerierungen — **unter den M3-
|
||||||
|
Gates** (100 % / 94,3 %): Korpusverdopplung macht Grounding härter;
|
||||||
|
das laufende Fehlverweigerungs-Tuning (uncommittete Änderungen in
|
||||||
|
generate.py/retrieve.py/goldset.yaml, unangetastet) ist weiteres
|
||||||
|
Thema. Report: `data/eval-qwen38-kvris.json`.
|
||||||
|
- **Goldset:** +7 Fragen (q-101–106 KV-Preise/§-Fragen, r-005 Branchen-
|
||||||
|
Refusal) — append-only. q-021 rekalibriert: erwartete ID jetzt
|
||||||
|
`lb-kar-04` („Karenz - Anspruch, Beginn und Dauer“, Top-1, deckt
|
||||||
|
Beginn/Dauer vollständig; lb-kar-01 nur Nachbarschaft — dokumentiert
|
||||||
|
im Goldset-Note).
|
||||||
|
- **Tests:** 41 → 49, alle grün (neue ID-Räume, html-Source, Konverter,
|
||||||
|
LAW_MAP-Vollabdeckung, Korpus-Integrationszahl 1 274).
|
||||||
|
|
||||||
## Open issues / blockers
|
## Open issues / blockers
|
||||||
|
|
||||||
- **Push**: Remote localhost:3003 aus der Sandbox nicht erreichbar — User
|
- **Push**: Remote localhost:3003 aus der Sandbox nicht erreichbar — User
|
||||||
@@ -75,6 +118,17 @@ zu planen).
|
|||||||
- **M4 Odoo**: native LLM-Module des konkreten Odoo-19-Stands verifizieren
|
- **M4 Odoo**: native LLM-Module des konkreten Odoo-19-Stands verifizieren
|
||||||
(keine API-Annahmen); Option A (dünnes Custom-Modul + Service-API) ist
|
(keine API-Annahmen); Option A (dünnes Custom-Modul + Service-API) ist
|
||||||
Default.
|
Default.
|
||||||
|
- **Nach KV/RIS-Erweiterung (2026-09-15)**: Antwortmodus unter den Gates
|
||||||
|
(Zitier-Präzision 95,2 % — 2 Verletzungen; Verweigerung 90,5 % — 4
|
||||||
|
Fehlverweigerungen, u.a. q-022/q-029; erwartete Quelle 83,8 %) —
|
||||||
|
Report `data/eval-qwen38-kvris.json`. Retrieval-Gate erfüllt (Recall@8
|
||||||
|
0,923 nach D10-Kalibrierung). Weiteres Prompt-/Kontext-Tuning offen;
|
||||||
|
der laufende Arbeitsstand in generate.py/retrieve.py/goldset.yaml
|
||||||
|
wurde unangetastet gelassen.
|
||||||
|
- **q-015 (Tagesgelder Dienstreisen)** — Branchen-Noise: 8 Branchen-KV-
|
||||||
|
Einträge verdrängen lb-rei-01/09 (EStG-Taggeld-Abrechnung) aus Top-8;
|
||||||
|
generische Branchen-Frage ist mehrdeutig geworden. Hebel: Frage
|
||||||
|
präzisieren (Branche/Kontext) oder KV-§-Titel-Matches dämpfen.
|
||||||
|
|
||||||
## Decisions & conventions
|
## Decisions & conventions
|
||||||
|
|
||||||
@@ -105,6 +159,23 @@ zu planen).
|
|||||||
erwartete Quelle 80,6 → 83,9 %; Verweigerung 94,3 % (Fehler getauscht:
|
erwartete Quelle 80,6 → 83,9 %; Verweigerung 94,3 % (Fehler getauscht:
|
||||||
neu q-029 — breite Survey-Frage über 12 Hefte, sicherer Fehlermodus).
|
neu q-029 — breite Survey-Frage über 12 Hefte, sicherer Fehlermodus).
|
||||||
Report `data/eval-qwen38-v2.json`.
|
Report `data/eval-qwen38-v2.json`.
|
||||||
|
- **D9 (KV/RIS-Erweiterung, 2026-09-15):** kv-/ris-Einträge sind
|
||||||
|
**quellentreu generiert** (keine Eigene-Worte-Kuratierung — Gesetze
|
||||||
|
sind amtliche Werke, KV-Lohntabellen zahlenexakt; Konvention 2 der
|
||||||
|
Wissensbasis gilt nur für die lizenzierten Quellen lb/wk).
|
||||||
|
Tool-Output: `tools/ingest_sources.py` + `tools/build_registry.py`
|
||||||
|
(Registry in diesem Repo neu gebaut — das Lexis-Tool
|
||||||
|
`build_lexis_kb.py` lebt im Schwesterprojekt), eingefrorene Kataloge
|
||||||
|
`tools/catalogs/*.json` (nur Metadaten, versioniert). IDs:
|
||||||
|
`kv-kvt-<nnn>` (ein Cluster `kollektivvertraege`, Branche als Tag),
|
||||||
|
`ris-<cluster-prefix>-<nn>` auf der bestehenden Cluster-Map + 7 neue
|
||||||
|
Cluster; `LAW_MAP` in `tools/kb_common.py` (59 Gesetze).
|
||||||
|
- **D10 (Retrieval-Kalibrierung, 2026-09-15):** nach KV/RIS-Erweiterung
|
||||||
|
(3.005 → 14 984 Chunks) dense_weight=2.0 (Dense relativ zu BM25
|
||||||
|
gewichtet — BM25 durch KV-§-Titel-Matches inflationiert), rrf_k=20,
|
||||||
|
candidate_pool=150 → Recall@8 0,851 → 0,923 (>0,9 ✓), Hit-Rate
|
||||||
|
0,973, MRR 0,667. ENV: PV_DENSE_WEIGHT / PV_RRF_K /
|
||||||
|
PV_CANDIDATE_POOL. Entry-RRF-Variante getestet: kein Mehrwert.
|
||||||
- **Bake-off-Protokoll** (Skill): Modellwechsel nur über dokumentierten
|
- **Bake-off-Protokoll** (Skill): Modellwechsel nur über dokumentierten
|
||||||
Goldset-Vergleich; Kriterium: Zitier-Präzision > Verweigerungs-
|
Goldset-Vergleich; Kriterium: Zitier-Präzision > Verweigerungs-
|
||||||
korrektheit > Latenz.
|
korrektheit > Latenz.
|
||||||
|
|||||||
+20
-3
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
Lokaler RAG-Agent für österreichische Personalverrechnung: beantwortet
|
Lokaler RAG-Agent für österreichische Personalverrechnung: beantwortet
|
||||||
Fragen **ausschließlich** aus der kuratierten Wissensbasis (Layer 2,
|
Fragen **ausschließlich** aus der kuratierten Wissensbasis (Layer 2,
|
||||||
`wissensbasis/`, 601 Einträge) — mit ID- und Stand-Beleg, ohne
|
`wissensbasis/`, **1274 Einträge**: 601 lb/wk-Kuratierung + 614 WKO-KV-
|
||||||
|
Dokumente + 59 RIS-Gesetze) — mit ID- und Stand-Beleg, ohne
|
||||||
Trainingswissen, ohne Web-Zugriff. Verbindliche Regeln:
|
Trainingswissen, ohne Web-Zugriff. Verbindliche Regeln:
|
||||||
`.agents/skills/pv-rag-agent/SKILL.md`, Plan: `planung.md`.
|
`.agents/skills/pv-rag-agent/SKILL.md`, Plan: `planung.md`.
|
||||||
|
|
||||||
@@ -56,6 +57,9 @@ python -m agent.cli serve # http://127.0.0.1:8080 (/ask, /health, /r
|
|||||||
| `PV_KB_DIR` | `wissensbasis` | Wissensbasis-Verzeichnis |
|
| `PV_KB_DIR` | `wissensbasis` | Wissensbasis-Verzeichnis |
|
||||||
| `PV_THINK` | `false` | Thinking per Request (qwen3.8: default an) |
|
| `PV_THINK` | `false` | Thinking per Request (qwen3.8: default an) |
|
||||||
| `PV_EMBED_OFF` | `false` | `true` = BM25-only |
|
| `PV_EMBED_OFF` | `false` | `true` = BM25-only |
|
||||||
|
| `PV_CANDIDATE_POOL` | `150` | Kandidaten je Liste vor der Fusion (KV/RIS-Erweiterung: Longtail-Spezialisten in der Kandidatur halten) |
|
||||||
|
| `PV_RRF_K` | `20` | RRF-Konstante (erweiterter Korpus: Top-Ränge dominant) |
|
||||||
|
| `PV_DENSE_WEIGHT` | `2.0` | RRF-Gewicht der Dense-Liste relativ zu BM25 (BM25 ist durch KV-§-Titel-Matches inflationiert) |
|
||||||
| `PV_CONTEXT_BLOCKS` | `8` | Kontextblöcke im Prompt |
|
| `PV_CONTEXT_BLOCKS` | `8` | Kontextblöcke im Prompt |
|
||||||
| `PV_PORT` | `8080` | API-Port |
|
| `PV_PORT` | `8080` | API-Port |
|
||||||
|
|
||||||
@@ -110,6 +114,18 @@ verweigert trotzdem (sicheres Versagensmuster; M3-Prompt-Tuning-Kandidat).
|
|||||||
Latenz-Hebel für M3: weniger Kontextblöcke, schnellere Kandidaten
|
Latenz-Hebel für M3: weniger Kontextblöcke, schnellere Kandidaten
|
||||||
(gemma4:12B, MoE).
|
(gemma4:12B, MoE).
|
||||||
|
|
||||||
|
**KV/RIS-Erweiterung + Retrieval-Kalibrierung (2026-09-15):** Korpus
|
||||||
|
601 → 1274 Einträge (kv-*: 614 WKO-KV-Dokumente quellentreu, ris-*:
|
||||||
|
59 RIS-Gesetze, nur die im Lexis360-Bestand zitierten §-Auschnitte);
|
||||||
|
14 984 Chunks. Kalibrierung per Goldset-Sweep (dichte Gewichtung,
|
||||||
|
RRF-k, Pool): Hit-Rate 0,865 → 0,973 · Recall@8 0,851 → **0,923** (>0,9 ✓)
|
||||||
|
· MRR 0,621 → 0,667. Antwortmodus (qwen3.8:27b): Zitier-Präzision
|
||||||
|
95,2 % (2 Verletzungen), Verweigerung korrekt 90,5 % (4 Fehlverweige-
|
||||||
|
rungen, u.a. q-022/q-029), erwartete Quelle zitiert 83,8 %, Latenz
|
||||||
|
mean 31 s / p95 53 s — **unter den M3-Gates** (100 % / 94,3 %): das
|
||||||
|
Fehlverweigerungs-Tuning (Regel 4/8 + Kontextblöcke) ist weiteres
|
||||||
|
Thema, Prompt bleibt beim laufenden Arbeitsstand eingefroren.
|
||||||
|
|
||||||
## Dateien
|
## Dateien
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -125,14 +141,15 @@ agent/
|
|||||||
cli.py ingest | ask | eval | serve
|
cli.py ingest | ask | eval | serve
|
||||||
eval/ goldset.yaml + evaluate.py
|
eval/ goldset.yaml + evaluate.py
|
||||||
web/index.html Minimaler Test-Chat
|
web/index.html Minimaler Test-Chat
|
||||||
tests/ 41 Tests (offline, Fake-Ollama)
|
tools/ Intake + Registry (build_registry.py, ingest_sources.py)
|
||||||
|
tests/ 49 Tests (offline, Fake-Ollama)
|
||||||
data/ index.db (gitignored)
|
data/ index.db (gitignored)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -m pytest -q # 41 Tests, alle offline
|
python -m pytest -q # 49 Tests, alle offline
|
||||||
```
|
```
|
||||||
|
|
||||||
## Lizenz-Disziplin
|
## Lizenz-Disziplin
|
||||||
|
|||||||
+9
-2
@@ -55,11 +55,16 @@ class Config:
|
|||||||
|
|
||||||
# Retrieval
|
# Retrieval
|
||||||
embed_off: bool = False # True = BM25-only (ohne Dense-Index/-Suche)
|
embed_off: bool = False # True = BM25-only (ohne Dense-Index/-Suche)
|
||||||
candidate_pool: int = 50 # Kandidaten je Liste vor der Fusion
|
candidate_pool: int = 150 # Kandidaten je Liste vor der Fusion
|
||||||
|
# (KV/RIS-Erweiterung: Longtail-Spezialisten
|
||||||
|
# liegen sonst außerhalb der Kandidatur)
|
||||||
context_blocks: int = 8 # Kontext-Blöcke im Prompt
|
context_blocks: int = 8 # Kontext-Blöcke im Prompt
|
||||||
cross_ref_expand: int = 3 # Top-Einträge, deren cross_refs ergänzt werden
|
cross_ref_expand: int = 3 # Top-Einträge, deren cross_refs ergänzt werden
|
||||||
cross_ref_max_extra: int = 6 # Obergrenze der Ergänzungen
|
cross_ref_max_extra: int = 6 # Obergrenze der Ergänzungen
|
||||||
rrf_k: int = 60
|
rrf_k: int = 20 # RRF-Konstante (erweiterter Korpus: Top-Ränge
|
||||||
|
# müssen dominanter zählen)
|
||||||
|
dense_weight: float = 2.0 # RRF-Gewicht der Dense-Liste relativ zu BM25
|
||||||
|
# (BM25 ist durch KV-§-Titel-Matches inflationiert)
|
||||||
recency_boost: float = 0.005 # additiv auf RRF-Score, gewichtet nach Stand
|
recency_boost: float = 0.005 # additiv auf RRF-Score, gewichtet nach Stand
|
||||||
|
|
||||||
# Service
|
# Service
|
||||||
@@ -85,6 +90,8 @@ class Config:
|
|||||||
context_blocks=_env_int("PV_CONTEXT_BLOCKS", d.context_blocks),
|
context_blocks=_env_int("PV_CONTEXT_BLOCKS", d.context_blocks),
|
||||||
cross_ref_expand=_env_int("PV_CROSS_REF_EXPAND", d.cross_ref_expand),
|
cross_ref_expand=_env_int("PV_CROSS_REF_EXPAND", d.cross_ref_expand),
|
||||||
cross_ref_max_extra=_env_int("PV_CROSS_REF_MAX_EXTRA", d.cross_ref_max_extra),
|
cross_ref_max_extra=_env_int("PV_CROSS_REF_MAX_EXTRA", d.cross_ref_max_extra),
|
||||||
|
rrf_k=_env_int("PV_RRF_K", d.rrf_k),
|
||||||
|
dense_weight=_env_float("PV_DENSE_WEIGHT", d.dense_weight),
|
||||||
recency_boost=_env_float("PV_RECENCY_BOOST", d.recency_boost),
|
recency_boost=_env_float("PV_RECENCY_BOOST", d.recency_boost),
|
||||||
port=_env_int("PV_PORT", d.port),
|
port=_env_int("PV_PORT", d.port),
|
||||||
)
|
)
|
||||||
+29
-2
@@ -68,7 +68,10 @@ questions:
|
|||||||
expected_ids: [lb-sch-04]
|
expected_ids: [lb-sch-04]
|
||||||
- id: q-021
|
- id: q-021
|
||||||
question: "Wann beginnt die Elternkarenz und wie lange kann sie dauern?"
|
question: "Wann beginnt die Elternkarenz und wie lange kann sie dauern?"
|
||||||
expected_ids: [lb-kar-01]
|
expected_ids: [lb-kar-04]
|
||||||
|
note: "Rekalibriert 2026-09-15 nach KV/RIS-Erweiterung: lb-kar-04
|
||||||
|
(Karenz - Anspruch, Beginn und Dauer) deckt die Frage vollständig und
|
||||||
|
ist Top-1; lb-kar-01 (Überblick) ist Nachbarschaft, nicht Pflichtbeleg."
|
||||||
- id: q-022
|
- id: q-022
|
||||||
question: "Wie ist eine Überstundenpauschale zu behandeln?"
|
question: "Wie ist eine Überstundenpauschale zu behandeln?"
|
||||||
expected_ids: [lb-ues-02]
|
expected_ids: [lb-ues-02]
|
||||||
@@ -117,4 +120,28 @@ questions:
|
|||||||
note: "Schwerer Fall: 13 Chunks erwähnen 'Umsatzsteuer' beiläufig — Retrieval nicht leer, aber inhaltlich nicht gedeckt."
|
note: "Schwerer Fall: 13 Chunks erwähnen 'Umsatzsteuer' beiläufig — Retrieval nicht leer, aber inhaltlich nicht gedeckt."
|
||||||
- id: r-004
|
- id: r-004
|
||||||
question: "Wie bereite ich einen Pitch für Investoren vor?"
|
question: "Wie bereite ich einen Pitch für Investoren vor?"
|
||||||
expect_refusal: true
|
expect_refusal: true
|
||||||
|
|
||||||
|
# --- KV-/RIS-Erweiterung (Batch kv/ris 1, 2026-09-15) ---
|
||||||
|
- id: q-101
|
||||||
|
question: "Wie hoch ist der kollektivvertragliche Mindestmonatslohn für angelernte Friseurinnen und Friseure ab 1. April 2026?"
|
||||||
|
expected_ids: [kv-kvt-422]
|
||||||
|
- id: q-102
|
||||||
|
question: "Wie hoch ist das Mindestgrundgehalt in Verwendungsgruppe III der Gehaltsordnung Information und Consulting ab 1.1.2026?"
|
||||||
|
expected_ids: [kv-kvt-056]
|
||||||
|
- id: q-103
|
||||||
|
question: "Wie viele Werktage gesetzlicher Urlaub stehen Arbeitnehmern nach dem Urlaubsgesetz zu?"
|
||||||
|
expected_ids: [ris-url-01]
|
||||||
|
- id: q-104
|
||||||
|
question: "Wann verjährt der Urlaubsanspruch nach dem Urlaubsgesetz?"
|
||||||
|
expected_ids: [ris-url-01]
|
||||||
|
- id: q-105
|
||||||
|
question: "Was gilt nach dem Nachtschwerarbeitsgesetz als Nachtarbeit?"
|
||||||
|
expected_ids: [ris-nsc-01]
|
||||||
|
- id: q-106
|
||||||
|
question: "Wann entsteht der Anspruch auf Altersteilzeitgeld?"
|
||||||
|
expected_ids: [ris-atz-01]
|
||||||
|
- id: r-005
|
||||||
|
question: "Wie hoch ist der kollektivvertragliche Mindestlohn im KV für Raumfahrttechnik?"
|
||||||
|
expect_refusal: true
|
||||||
|
note: "Branche nicht im KV-Korpus — Retrieval darf nicht leer sein, Antwort muss verweigern."
|
||||||
+1
-1
@@ -51,7 +51,7 @@ Verbindliche Regeln:
|
|||||||
|
|
||||||
Verletze Regel 2 oder Regel 4 niemals — im Zweifel verweigere die Antwort."""
|
Verletze Regel 2 oder Regel 4 niemals — im Zweifel verweigere die Antwort."""
|
||||||
|
|
||||||
CITE_RE = re.compile(r"\b(?:lb|wk)-[a-z0-9]+-\d+\b")
|
CITE_RE = re.compile(r"\b(?:lb|wk|kv|ris)-[a-z0-9]+-\d+\b")
|
||||||
_THINK_RE = re.compile(r"<think>.*?</think>", re.DOTALL)
|
_THINK_RE = re.compile(r"<think>.*?</think>", re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -250,10 +250,10 @@ class Retriever:
|
|||||||
except Exception:
|
except Exception:
|
||||||
dn = {}
|
dn = {}
|
||||||
fused: dict[int, float] = {}
|
fused: dict[int, float] = {}
|
||||||
for ranking in (bm, dn):
|
for ranking, weight in ((bm, 1.0), (dn, self.cfg.dense_weight)):
|
||||||
ordered = sorted(ranking.items(), key=lambda kv: -kv[1])
|
ordered = sorted(ranking.items(), key=lambda kv: -kv[1])
|
||||||
for rank, (cid, _) in enumerate(ordered):
|
for rank, (cid, _) in enumerate(ordered):
|
||||||
fused[cid] = fused.get(cid, 0.0) + 1.0 / (self.cfg.rrf_k + rank)
|
fused[cid] = fused.get(cid, 0.0) + weight / (self.cfg.rrf_k + rank)
|
||||||
if not fused:
|
if not fused:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -283,4 +283,11 @@ tests/ # pytest: Ingest-, Retrieval-, Grounding-Unit-Tests
|
|||||||
**83,9 %** (v1: 80,6 %), mean 34 s. Report `data/eval-qwen38-v2.json`.
|
**83,9 %** (v1: 80,6 %), mean 34 s. Report `data/eval-qwen38-v2.json`.
|
||||||
- **M4 offen:** Odoo-Integration (separater Plan nach Verifikation der
|
- **M4 offen:** Odoo-Integration (separater Plan nach Verifikation der
|
||||||
Odoo-19-LLM-Module).
|
Odoo-19-LLM-Module).
|
||||||
|
- **KV/RIS-Erweiterung (2026-09-15, D9/D10):** Korpus 601 → 1 274 Einträge
|
||||||
|
(614 WKO-KV-Dokumente `kv-kvt-…`, 59 RIS-Gesetze `ris-…`; quelltreu
|
||||||
|
generiert — D9), 14 984 Chunks. Retrieval kalibriert (D10:
|
||||||
|
dense_weight 2.0, rrf_k 20, Pool 150) → Recall@8 0,923 (>0,9 ✓).
|
||||||
|
Antwortmodus: Zitier-Präzision 95,2 %, Verweigerung 90,5 % —
|
||||||
|
Fehlverweigerungs-Tuning (offen, laufender Arbeitsstand) fortsetzen.
|
||||||
|
Intake: `tools/ingest_sources.py`, Registry: `tools/build_registry.py`.
|
||||||
- Betrieb: `agent/README.md`.
|
- Betrieb: `agent/README.md`.
|
||||||
|
|||||||
Reference in New Issue
Block a user