Stufe 1: komplexe Fragen via Query-Planer, Per-Query-Slots, Scope-Filter (D12, M6)

- Query-Planer (agent/query_planner.py): Heuristik-Gate (Jahr, Vergleichs-/
  Aggregationsmarker, Laenge) entscheidet ueber einen kleinen LLM-Call,
  der komplexe Fragen in 1-3 Sub-Queries zerlegt (JSON, temp 0; Fehler ->
  Original als Einzel-Query). Je Sub-Query optional stand_year und scope.
- Multi-Query-Retrieval: je Sub-Query BM25+Dense mit RRF-Summe;
  Per-Query-Slots (2 je Sub-Query) sichern jeden Frageaspekt im Kontext
  (sonst dominieren Eintraege, die in mehreren Sub-Queries mittelgut
  matchen — q-113-Befund). Scope-Filter: 'gesetz' (nur Lexis/WIKU/RIS)
  und 'kv' (nur Branchen-KV) mit Fallback auf unscoped bei leerem
  Ergebnis. Temporal-Intent: stand_year + temporal_boost (default 0,
  FTS-jahr-Tag-Signal reichte).
- Grounding unveraendert: eine Retrieved-Menge (Union), eine Antwort,
  Post-Validierung ueber die Union, Verweigerungspflicht unveraendert.
- Goldset 42 -> 46: q-110 (Temporal 2023; 2024er-Lohnordnung existiert
  im Korpus nicht - Mantelvertrag ohne Lohntabelle, korrekt verweigert),
  q-111 (2025), q-112 (Abfertigung-Vergleich), q-113 (Gesetz+KV).
- Eval (46 Fragen): Zitier-Praezision 97,8 %, Verweigerung 97,8 %
  (Gate >94,3 % erfuellt), erwartete Quelle 90,2 %, Latenz mean 33,5 s.
- Tests 50 -> 57. Reports lokal: data/eval-qwen38-stage1*.json.
  API-first festgehalten (D13-Vorbereitung): Odoo bleibt duenner Client;
  Lohndaten-Zugriff in M4 erfordert Privacy-Neubewertung.
This commit is contained in:
2026-09-15 09:58:25 +02:00
parent c594c553b5
commit 062e010d7b
10 changed files with 532 additions and 33 deletions
+16
View File
@@ -73,6 +73,16 @@ class Config:
# (BM25 ist durch KV-§-Titel-Matches inflationiert)
recency_boost: float = 0.005 # additiv auf RRF-Score, gewichtet nach Stand
# Query-Planer (Stufe 1, M6): komplexe Fragen -> 1-3 Sub-Queries
planner_enabled: bool = True # Heuristik-Gate entscheidet je Frage
planner_max_queries: int = 3
planner_num_predict: int = 220
planner_model: str = "" # leer = Antwortmodell
per_query_slots: int = 2 # Multi-Query: garantierte Kontext-Slots
# je Sub-Query (Multi-Hop-Abdeckung)
temporal_boost: float = 0.0 # Bonus fuer kv-Eintraege im gefragten
# Geltungsjahr (0 = nur FTS-Tag-Signal)
# Service
port: int = 8080
@@ -100,5 +110,11 @@ class Config:
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),
planner_enabled=_env_bool("PV_QUERY_PLANNER", d.planner_enabled),
planner_max_queries=_env_int("PV_PLANNER_MAX_QUERIES", d.planner_max_queries),
planner_num_predict=_env_int("PV_PLANNER_NUM_PREDICT", d.planner_num_predict),
planner_model=_env_str("PV_PLANNER_MODEL", d.planner_model),
per_query_slots=_env_int("PV_PER_QUERY_SLOTS", d.per_query_slots),
temporal_boost=_env_float("PV_TEMPORAL_BOOST", d.temporal_boost),
port=_env_int("PV_PORT", d.port),
)