feat(matching): implement two-stage matching with DeepSeek arbiter, fail-stop guard, and zero-probability filter
This commit is contained in:
+12
-5
@@ -16,6 +16,11 @@ from app.config import Settings
|
||||
|
||||
logger = logging.getLogger("bot.nlu")
|
||||
|
||||
|
||||
class NLUFailureError(Exception):
|
||||
"""Raised when NLU understanding fails due to LLM / network failure."""
|
||||
pass
|
||||
|
||||
PERSIAN_DIGITS = str.maketrans("۰۱۲۳۴۵۶۷۸۹٠١٢٣٤٥٦٧٨٩", "01234567890123456789")
|
||||
|
||||
|
||||
@@ -233,14 +238,14 @@ async def understand(settings: Settings, text: str | list[dict], draft_summary:
|
||||
logger.error("LLM HTTP %s: %s", resp.status_code, resp.text[:300])
|
||||
await obs.event(trace_id, "nlu.result", ok=False, model=settings.LLM_MODEL,
|
||||
payload={"error": f"HTTP {resp.status_code}", "body": resp.text[:300]})
|
||||
return fallback
|
||||
raise NLUFailureError(f"HTTP {resp.status_code}")
|
||||
content = ((resp.json() or {}).get("choices") or [{}])[0].get("message", {}).get("content", "")
|
||||
parsed = _extract_json(content)
|
||||
if not parsed or parsed.get("intent") not in INTENTS:
|
||||
logger.warning("unparseable LLM output: %r", content[:200])
|
||||
await obs.event(trace_id, "nlu.result", ok=False, model=settings.LLM_MODEL,
|
||||
payload={"error": "unparseable", "raw": content[:500]})
|
||||
return fallback
|
||||
raise NLUFailureError("unparseable LLM output")
|
||||
parsed.setdefault("patch", {})
|
||||
parsed["entity_mentions"] = sanitize_mentions(parsed.get("entity_mentions"))
|
||||
if not parsed.get("consensus_text"):
|
||||
@@ -253,8 +258,10 @@ async def understand(settings: Settings, text: str | list[dict], draft_summary:
|
||||
"entity_mentions": parsed.get("entity_mentions"),
|
||||
})
|
||||
return parsed
|
||||
except (httpx.HTTPError, json.JSONDecodeError, KeyError, TypeError):
|
||||
except Exception as exc:
|
||||
if isinstance(exc, NLUFailureError):
|
||||
raise
|
||||
logger.exception("NLU failure")
|
||||
await obs.event(trace_id, "nlu.result", ok=False, model=settings.LLM_MODEL,
|
||||
payload={"error": "exception"})
|
||||
return fallback
|
||||
payload={"error": "exception", "details": str(exc)})
|
||||
raise NLUFailureError(f"NLU exception: {exc}") from exc
|
||||
|
||||
Reference in New Issue
Block a user