From 9827db8a49fb6e4ace76650454bbe96de595f0e5 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Sun, 1 Feb 2026 05:30:34 -0300 Subject: [PATCH] atlasbot: guard metric answers with facts --- atlasbot/engine/answerer.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/atlasbot/engine/answerer.py b/atlasbot/engine/answerer.py index 9a17843..0c51fbd 100644 --- a/atlasbot/engine/answerer.py +++ b/atlasbot/engine/answerer.py @@ -414,8 +414,8 @@ class AnswerEngine: best_line = line break best_line = best_line or metric_facts[0] - reply_numbers = set(re.findall(r"\\d+(?:\\.\\d+)?", reply)) - fact_numbers = set(re.findall(r"\\d+(?:\\.\\d+)?", " ".join(metric_facts))) + reply_numbers = set(re.findall(r"\d+(?:\.\d+)?", reply)) + fact_numbers = set(re.findall(r"\d+(?:\.\d+)?", " ".join(metric_facts))) if not reply_numbers or (fact_numbers and not (reply_numbers & fact_numbers)): reply = f"From the latest snapshot: {best_line}." @@ -447,6 +447,9 @@ class AnswerEngine: if note: reply = f"{reply}\n\n{note}" + if classify.get("question_type") in {"metric", "diagnostic"} and metric_facts: + reply = _metric_fact_guard(reply, metric_facts, keyword_tokens) + scores = await self._score_answer(normalized, reply, plan, call_llm) claims = await self._extract_claims(normalized, reply, summary, call_llm) except LLMLimitReached: @@ -898,6 +901,24 @@ def _key_fact_lines(lines: list[str], keywords: list[str] | None, limit: int = 6 return matches +def _metric_fact_guard(reply: str, metric_facts: list[str], keywords: list[str]) -> str: + if not metric_facts: + return reply + best_line = None + lowered_keywords = [kw.lower() for kw in keywords if kw] + for line in metric_facts: + line_lower = line.lower() + if any(kw in line_lower for kw in lowered_keywords): + best_line = line + break + best_line = best_line or metric_facts[0] + reply_numbers = set(re.findall(r"\d+(?:\.\d+)?", reply)) + fact_numbers = set(re.findall(r"\d+(?:\.\d+)?", " ".join(metric_facts))) + if not reply_numbers or (fact_numbers and not (reply_numbers & fact_numbers)): + return f"From the latest snapshot: {best_line}." + return reply + + def _lexicon_context(summary: dict[str, Any]) -> str: if not isinstance(summary, dict): return ""