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:
+27
-8
@@ -13,6 +13,7 @@ import time
|
||||
from .config import Config
|
||||
from .normalize import normalize_text
|
||||
from .ollama_client import OllamaClient
|
||||
from .query_planner import SubQuery, plan_queries
|
||||
from .retrieve import ChunkResult, Retriever
|
||||
|
||||
REFUSAL_MESSAGE = "Dazu enthält die Wissensbasis keine Aussage."
|
||||
@@ -138,13 +139,33 @@ def answer_question(
|
||||
retriever: Retriever | None = None,
|
||||
top_k: int | None = None,
|
||||
) -> dict:
|
||||
"""Vollständiger Ask-Zyklus: Retrieval -> Prompt -> LLM -> Post-Validierung."""
|
||||
"""Vollständiger Ask-Zyklus: Query-Planung -> Retrieval -> Prompt -> LLM ->
|
||||
Post-Validierung. Der Planer läuft vor dem Retrieval (Heuristik-Gate,
|
||||
nur bei komplexen Fragen); seine Sub-Queries fusionieren in EINER
|
||||
Retrieved-Menge, gegen die die Post-Validierung prüft."""
|
||||
t0 = time.perf_counter()
|
||||
own_retriever = retriever is None
|
||||
if retriever is None:
|
||||
retriever = Retriever(cfg)
|
||||
|
||||
if client is None:
|
||||
client = OllamaClient(
|
||||
cfg.ollama_url,
|
||||
embed_timeout_s=cfg.embed_timeout_s,
|
||||
chat_timeout_s=cfg.chat_timeout_s,
|
||||
)
|
||||
|
||||
sub_queries = [SubQuery(text=question)]
|
||||
planned = False
|
||||
if cfg.planner_enabled:
|
||||
try:
|
||||
sub_queries, planned = plan_queries(question, client, cfg)
|
||||
sub_queries = sub_queries[: cfg.planner_max_queries] or sub_queries[:1]
|
||||
except Exception:
|
||||
sub_queries, planned = [SubQuery(text=question)], False
|
||||
|
||||
try:
|
||||
results = retriever.search(question, n_entries=top_k)
|
||||
results = retriever.search_multi(sub_queries, n_entries=top_k)
|
||||
finally:
|
||||
if own_retriever:
|
||||
retriever.close()
|
||||
@@ -164,6 +185,10 @@ def answer_question(
|
||||
"regenerations": regenerations,
|
||||
"latency_ms": round((time.perf_counter() - t0) * 1000),
|
||||
"draft": draft,
|
||||
"planned_queries": [
|
||||
{"text": sq.text, "stand_year": sq.stand_year}
|
||||
for sq in sub_queries
|
||||
],
|
||||
}
|
||||
|
||||
if not results:
|
||||
@@ -173,12 +198,6 @@ def answer_question(
|
||||
allowed = [r.entry_id for r in results]
|
||||
by_id = {r.entry_id: r for r in results}
|
||||
|
||||
if client is None:
|
||||
client = OllamaClient(
|
||||
cfg.ollama_url,
|
||||
embed_timeout_s=cfg.embed_timeout_s,
|
||||
chat_timeout_s=cfg.chat_timeout_s,
|
||||
)
|
||||
messages = [
|
||||
{"role": "system", "content": SYSTEM_PROMPT},
|
||||
{"role": "user", "content": build_user_content(question, results)},
|
||||
|
||||
Reference in New Issue
Block a user