Stufe 2: Antworttyp-Routing — Survey Map-Reduce + Rueckfrage-Regel (D13, M6)
- Planer liefert jetzt type: survey|specific. Survey-Fragen (Uebersicht ueber viele Dokumente) laufen ueber Map-Reduce: Retrieval auf survey_blocks=16 erweitert, ein Map-Call destilliert JE Block als Stichpunkte mit seiner KB-ID (MAP_SYSTEM_PROMPT), ein Reduce-Call synthetisiert die Endantwort. Grounding unveraendert: Zitier-Validierung strikt ueber die Retrieved-Union; leerer Map-Output -> Fallback auf Einzelantwort. - Systemprompt-Regel 9: haengt die Antwort wesentlich von nicht genanntem Kontext ab (Branche, Bundesland, Zeitraum), belegte allgemeine Aussage plus EINE Rueckfrage statt Verweigerung (API-first; Odoo-Chat kann die Rueckfrage als Follow-up nutzen). - Ergebnis: q-029 (WIKU-Survey, bisher hartnaeckigste Fehlverweigerung) geheilt - Teilantwort mit 5 belegten Heften; 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 (Map-Reduce nur bei Survey-Fragen, ~95 s). Report lokal data/eval-qwen38-stage2.json. - Tests 57 -> 59 (Survey-Integration, Typ-Parsing).
This commit is contained in:
+18
-12
@@ -37,9 +37,11 @@ beantworten. Regeln:
|
||||
- Setze "scope" je Suchanfrage: "gesetz", wenn nach der gesetzlichen/
|
||||
allgemeinen Grundlage gefragt ist (nur Gesetze und Fachbriefings, ohne
|
||||
Branchen-Kollektivverträge); "kv", wenn ausdrücklich nach kollektivvertrag-
|
||||
lichen Branchenregelungen gefragt ist; null für alles andere.
|
||||
lichen Branchenregelungen gefragt ist; null für alles anderes.
|
||||
- Setze "type" auf "survey", wenn die Frage eine Übersicht über viele
|
||||
Dokumente verlangt (Neuerungen, Entwicklungen, alle …); sonst "specific".
|
||||
- Antworte ausschließlich mit JSON, ohne Erklärung:
|
||||
{{"queries": [{{"text": "...", "stand_year": null, "scope": null}}]}}"""
|
||||
{{"type": "specific", "queries": [{{"text": "...", "stand_year": null, "scope": null}}]}}"""
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -69,8 +71,9 @@ def should_plan(question: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def parse_plan(raw: str, original: str) -> list[SubQuery]:
|
||||
"""Robustes JSON-Parsing; jeder Fehler → [Originalfrage]."""
|
||||
def parse_plan(raw: str, original: str) -> tuple[list[SubQuery], str]:
|
||||
"""Robustes JSON-Parsing; jeder Fehler → [Originalfrage]. Liefert
|
||||
(Sub-Queries, Fragetyp 'survey' | 'specific')."""
|
||||
try:
|
||||
match = JSON_RE.search(raw)
|
||||
if not match:
|
||||
@@ -89,8 +92,10 @@ def parse_plan(raw: str, original: str) -> list[SubQuery]:
|
||||
scope = item.get("scope")
|
||||
scope = scope if scope in ("gesetz", "kv") else None
|
||||
subs.append(SubQuery(text=text, stand_year=year, scope=scope))
|
||||
return subs
|
||||
qtype = data.get("type") if data.get("type") in ("survey", "specific") else "specific"
|
||||
return subs, qtype
|
||||
except (ValueError, TypeError, KeyError, json.JSONDecodeError):
|
||||
return [SubQuery(text=original)], "specific"
|
||||
return [SubQuery(text=original)]
|
||||
|
||||
|
||||
@@ -98,12 +103,12 @@ def plan_queries(
|
||||
question: str,
|
||||
client,
|
||||
cfg,
|
||||
) -> tuple[list[SubQuery], bool]:
|
||||
"""Liefert (Sub-Queries, geplant?) — Call-/Parse-Fehler → Original als
|
||||
Einzel-Query. Der Planer-Call ist klein (Frage ohne Kontext, kurzes
|
||||
num_predict); Temperature 0."""
|
||||
) -> tuple[list[SubQuery], bool, str]:
|
||||
"""Liefert (Sub-Queries, geplant?, Fragetyp) — Call-/Parse-Fehler →
|
||||
Original als Einzel-Query, Typ 'specific'. Der Planer-Call ist klein
|
||||
(Frage ohne Kontext, kurzes num_predict); Temperature 0."""
|
||||
if not should_plan(question):
|
||||
return [SubQuery(text=question)], False
|
||||
return [SubQuery(text=question)], False, "specific"
|
||||
prompt = PLANNER_PROMPT.format(question=question.strip())
|
||||
try:
|
||||
raw = client.chat(
|
||||
@@ -118,5 +123,6 @@ def plan_queries(
|
||||
think=False,
|
||||
)
|
||||
except Exception:
|
||||
return [SubQuery(text=question)], False
|
||||
return parse_plan(raw, question), True
|
||||
return [SubQuery(text=question)], False, "specific"
|
||||
subs, qtype = parse_plan(raw, question)
|
||||
return subs, True, qtype
|
||||
Reference in New Issue
Block a user