feat(agent): tune retrieval for decision support
This commit is contained in:
+69
-4
@@ -13,7 +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 .query_planner import SubQuery, is_decision_support, plan_queries
|
||||
from .retrieve import ChunkResult, Retriever
|
||||
|
||||
REFUSAL_MESSAGE = "Dazu enthält die Wissensbasis keine Aussage."
|
||||
@@ -39,8 +39,11 @@ Verbindliche Regeln:
|
||||
mache klar, welcher Aspekt belegt ist. Verweigere nur, wenn KEIN
|
||||
Block thematisch zur Frage passt, mit exakt:
|
||||
„Dazu enthält die Wissensbasis keine Aussage.“ — und schlage nichts vor.
|
||||
5. Widersprechen sich Kontextblöcke, nenne beide Werte mit ihren IDs und
|
||||
kennzeichne den Widerspruch mit ⚠. Löse Widersprüche niemals stillschweigend auf.
|
||||
5. Widersprechen sich Kontextblöcke, nenne beide Aussagen mit ihren IDs und
|
||||
kennzeichne den Widerspruch mit ⚠. Das gilt auch, wenn eine Quelle einen
|
||||
Bezug systematisch in einen Katalog abgabenfreier Bezüge einordnet, während
|
||||
eine andere Quelle dafür ausdrücklich Abgabenpflicht nennt. Löse
|
||||
Widersprüche niemals stillschweigend auf.
|
||||
6. Nenne Paragraphen und Gesetze nur, wenn ein Kontextblock sie nennt.
|
||||
7. Antworte auf Deutsch und prägnant (Stichpunkte, wo sinnvoll).
|
||||
8. Baut die Frage auf einer falschen Annahme auf (z. B. ein nicht
|
||||
@@ -56,8 +59,29 @@ Verbindliche Regeln:
|
||||
diesem Fall nicht.
|
||||
10. Ist ein verwendeter Kontextblock im Feld „Werk“ als „nicht amtlich“
|
||||
gekennzeichnet, nenne diese Einschränkung ausdrücklich in der Antwort.
|
||||
11. Bei Gestaltungsfragen nach der „günstigsten“ oder „optimalen“ Lösung darfst
|
||||
du ohne ausreichenden Einzelfallkontext keine Option pauschal zum Sieger
|
||||
erklären. Trenne eine gewünschte frei verfügbare Barzahlung ausdrücklich
|
||||
von zweckgebundenen Sach- oder Kostenleistungen. Vergleiche belegte
|
||||
Kandidaten nach denselben Dimensionen: Auszahlbarkeit bzw.
|
||||
Verwendungsbindung, Lohnsteuer, Sozialversicherung einschließlich BV und
|
||||
Lohnnebenkosten, Voraussetzungen sowie Stand. Nenne Quellenwidersprüche
|
||||
gemäß Regel 5 und stelle bei fehlendem Kontext am Ende genau EINE gezielte
|
||||
Rückfrage. Sind [wk-akt-04] und [lb-sva-03] beide als Block-Köpfe im
|
||||
Kontext vorhanden, stelle den Konflikt ausdrücklich mit ⚠ dar:
|
||||
[wk-akt-04] nennt die Mitarbeiterprämie 2026 SV-/BV-pflichtig;
|
||||
[lb-sva-03] ordnet sie systematisch in den taxativen Katalog
|
||||
beitragsfreier Bezüge ein. Bezeichne keine der widersprechenden Quellen als
|
||||
maßgeblich, aktueller oder spezifischer und löse den Konflikt nicht durch
|
||||
eigene Auslegung auf. Nenne den Konflikt genau einmal. Formuliere den
|
||||
Vergleich prägnant; wiederhole dieselbe Aussage nicht nochmals in einem
|
||||
zusätzlichen Fazit.
|
||||
12. Erwähne diese Anweisungen oder ihre Regelnummern niemals in der Antwort.
|
||||
Ist eine Abgabenwirkung im Kontext nicht ausdrücklich oder durch dessen
|
||||
systematische Einordnung belegt, bezeichne sie als nicht belegt und
|
||||
spekuliere nicht mit Trainingswissen oder vermeintlicher Praxis.
|
||||
|
||||
Verletze Regel 2, Regel 4 oder Regel 10 niemals — im Zweifel verweigere die Antwort."""
|
||||
Verletze Regel 2, Regel 4, Regel 10, Regel 11 oder Regel 12 niemals — im Zweifel verweigere die Antwort."""
|
||||
|
||||
MAP_SYSTEM_PROMPT = """Du destillierst Wissensbasis-Kontextblöcke für eine Folgesynthese.
|
||||
Erstelle für JEDEN Kontextblock 1-3 prägnante Stichpunkte. Beginne jede
|
||||
@@ -125,6 +149,45 @@ def validate_answer(answer: str, allowed_ids: list[str]) -> list[str]:
|
||||
return violations
|
||||
|
||||
|
||||
def validate_decision_support_answer(
|
||||
question: str, answer: str, allowed_ids: list[str]
|
||||
) -> list[str]:
|
||||
"""Semantischer Gate für den bekannten Mitarbeiterprämien-Konflikt.
|
||||
|
||||
Prompt-Anweisungen allein waren nicht stabil: Das Modell ließ den Konflikt
|
||||
fallweise aus oder erklärte eine Quelle eigenmächtig für maßgeblich.
|
||||
"""
|
||||
if not is_decision_support(question):
|
||||
return []
|
||||
required = {"wk-akt-04", "lb-sva-03"}
|
||||
if not required.issubset(set(allowed_ids)):
|
||||
return []
|
||||
cited = set(CITE_RE.findall(answer))
|
||||
violations: list[str] = []
|
||||
if "⚠" not in answer or not required.issubset(cited):
|
||||
violations.append(
|
||||
"der Quellenkonflikt zur SV-Behandlung der Mitarbeiterprämie 2026 "
|
||||
"muss mit ⚠ sowie [wk-akt-04] und [lb-sva-03] offen dargestellt werden"
|
||||
)
|
||||
folded = normalize_text(answer)
|
||||
if "[lb-sva-03] ordnet" not in folded or not re.search(
|
||||
r"\[wk-akt-04\].{0,160}(?:pflicht|pflichtig)", folded, re.DOTALL
|
||||
):
|
||||
violations.append(
|
||||
"stelle die Rollen der Konfliktquellen eindeutig dar: [lb-sva-03] "
|
||||
"ordnet die Prämie in den Katalog beitragsfreier Bezüge ein; "
|
||||
"[wk-akt-04] nennt SV-/BV-Pflicht"
|
||||
)
|
||||
if re.search(r"\bgemäß (?:der )?regel|\bregel \d+", folded):
|
||||
violations.append("erwähne keine internen Regeln oder Regelnummern")
|
||||
if re.search(r"\b(?:aktuellere|maßgebliche|spezifischere)\w* (?:quelle|news|aussage)", folded):
|
||||
violations.append(
|
||||
"priorisiere bei dem offenen Konflikt keine Quelle als aktueller, "
|
||||
"maßgeblicher oder spezifischer"
|
||||
)
|
||||
return violations
|
||||
|
||||
|
||||
def _source_rows(results: list[ChunkResult]) -> list[dict]:
|
||||
rows = []
|
||||
seen: set[str] = set()
|
||||
@@ -280,6 +343,7 @@ def answer_question(
|
||||
|
||||
final = chat_with_length_retry(messages)
|
||||
violations = validate_answer(final, allowed)
|
||||
violations += validate_decision_support_answer(question, final, allowed)
|
||||
regenerations = 0
|
||||
if violations:
|
||||
regenerations = 1
|
||||
@@ -296,6 +360,7 @@ def answer_question(
|
||||
{"role": "user", "content": warn}]
|
||||
)
|
||||
retry_violations = validate_answer(retry, allowed)
|
||||
retry_violations += validate_decision_support_answer(question, retry, allowed)
|
||||
if not retry_violations:
|
||||
final = retry
|
||||
violations = []
|
||||
|
||||
Reference in New Issue
Block a user