fix: enforce assistant data quality disclosures
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-15 07:51:23 +02:00
parent 01785a0f95
commit c7faea430f
4 changed files with 98 additions and 0 deletions
@@ -37,12 +37,48 @@ class GeoAssistantService:
"gedaald",
"gestegen",
)
ESTIMATE_TOPIC_TERMS = {
"population": ("bevolk", "inwoner"),
}
ESTIMATE_TOPIC_LABELS = {
"population": "bevolkingswaarden",
}
@classmethod
def history_requested(cls, question: str) -> bool:
normalized = question.casefold()
return any(keyword in normalized for keyword in cls.HISTORY_KEYWORDS)
@classmethod
def ensure_estimate_disclosure(
cls,
answer: str,
metrics: list[AssistantContextMetric],
) -> str:
normalized = answer.casefold()
if "schat" in normalized:
return answer
disclosed_themes = {
metric.theme
for metric in metrics
if metric.is_estimate
and any(
term in normalized
for term in cls.ESTIMATE_TOPIC_TERMS.get(metric.theme, (metric.label.casefold(),))
)
}
if not disclosed_themes:
return answer
labels = ", ".join(
cls.ESTIMATE_TOPIC_LABELS.get(theme, theme)
for theme in sorted(disclosed_themes)
)
return (
f"Datakwaliteit: {labels} in dit antwoord zijn schattingen volgens de bronmetadata, "
"geen exacte tellingen.\n\n"
f"{answer}"
)
def __init__(self, settings: Settings | None = None):
self.settings = settings or get_settings()
@@ -262,6 +298,9 @@ class GeoAssistantService:
)
context_metrics.append(item)
serialized_metrics.append(item.model_dump(mode="json"))
serialized_metrics[-1]["measurement_quality"] = (
"schatting" if item.is_estimate else "exact_binnen_bronrepresentatie"
)
source_dataset_ids.append(dataset.id)
current_context.append(
{
@@ -307,6 +346,9 @@ class GeoAssistantService:
"value": summary["metric_value"],
"unit": summary["metric_unit"],
"is_estimate": summary["is_estimate"],
"measurement_quality": (
"schatting" if summary["is_estimate"] else "exact_binnen_bronrepresentatie"
),
}
)
if dataset.id not in source_dataset_ids:
@@ -356,6 +398,7 @@ class GeoAssistantService:
"Als is_estimate true is, noem de waarde verplicht een schatting en nooit exact. "
"Objectaantallen zijn ondersteunend; geef betekenisvolle oppervlakte-, lengte- of bevolkingsmetriek voorrang. "
"Beschrijf alleen waargenomen verschillen; verzin geen oorzaak, voorspelling, verzadiging of andere verklaring. "
"Neem waarden en jaren letterlijk over en bereken zelf geen gemiddelde, tempo, oorzaak of afgeleide trend. "
"Gebruik platte tekst met korte alinea's en opsommingen, zonder Markdown-symbolen. "
"Bereken of suggereer nooit watervolume zonder gekoppelde diepte of bathymetrie. "
"Als de gevraagde informatie niet in de context staat, zeg precies welke bron of meting ontbreekt. "
@@ -393,6 +436,7 @@ class GeoAssistantService:
answer = str(message.get("content") or "").strip()
if not answer:
raise AppError(code="OLLAMA_EMPTY_RESPONSE", message="Ollama gaf geen antwoord terug.", status_code=502)
answer = self.ensure_estimate_disclosure(answer, metrics)
return AssistantQueryResponse(
answer=answer,
model=model,