rag_mode: RAG-first als Default + Persistenz, Router haertet persoenliche Fragen

rag_mode.py:
 - Default fuer neue/unbekannte Chats: RAG-first (True statt False)
 - State wird auf Disk geschrieben (/opt/homelab-ai-bot/data/rag_mode.json),
   ueberlebt Bot-Restarts; threadsicher.

llm.py:
 - _LOCAL_OVERRIDES erweitert um persoenliche Possessiv-/Besitz-Marker:
   wohnung(en), apartment, condo/kondo, immobilie, kambodscha/cambodia,
   phnom penh, arakawa, gekostet, kaufpreis, bezahlt, ausgegeben, ueberweisung,
   meine/mein/meines/..., was haben, wie viel habe ich, ich fuer/für.
   Damit werden klar persoenliche Fragen nie mehr faelschlich an Sonar
   geroutet, selbst wenn Web-Trigger wie "wie viel" im Text vorkommen.

Hintergrund: Eine Frage der Form "wie viel habe ich fuer die Wohnungen in
Kambodscha bezahlt" wurde an Perplexity/Sonar geroutet (Websuche) statt an
RAG, weil der Mode-Schalter durch einen Bot-Restart im RAM verloren ging und
der Router bei "wie viel" sofort MODEL_ONLINE waehlte.
This commit is contained in:
root 2026-04-17 21:57:42 +02:00
parent c63b3621c0
commit 10f3c8323a
2 changed files with 56 additions and 6 deletions

View file

@ -48,6 +48,16 @@ _LOCAL_OVERRIDES = [
"habe ich", "welche habe", "was habe ich",
"jahreskosten", "jährlichen", "jährliche", "jaehrlichen", "jaehrliche",
"monatliche kosten", "versicherungskosten", "beitragsrechnung",
# Possessiv/Persoenlich (2026-04-16)
"meine", "mein ", "meiner", "meines", "meinem", "meinen",
"wohnung", "wohnungen", "apartment", "apartments",
"condo", "condos", "kondo", "kondos", "immobilie", "immobilien",
"kambodscha", "cambodia", "phnom penh", "arakawa",
"gekostet", "gekauft", "kaufpreis", "kaufpreise", "bezahlt",
"ausgegeben", "ueberweisung", "überweisung",
"was haben", "wieviel habe ich", "wie viel habe ich",
"fuer die wohnung", "für die wohnung",
"ich fuer", "ich für",
]
_WEB_TRIGGERS = [
"recherche", "recherchiere", "suche im internet", "web search",

View file

@ -1,24 +1,64 @@
"""Pro-Chat: Betriebsart Unterlagen zuerst (RAG vor Web)."""
"""Pro-Chat: Betriebsart Unterlagen zuerst (RAG vor Web).
Persistenz: /opt/homelab-ai-bot/data/rag_mode.json (ueberlebt Bot-Restarts).
Default fuer neue Chats: True (RAG-first, keine Web-Suche ohne Zutun).
"""
from __future__ import annotations
import json
import logging
import os
import threading
from pathlib import Path
from typing import Optional, Tuple
log = logging.getLogger("rag_mode")
_STATE_PATH = Path(os.environ.get("RAG_MODE_STATE", "/opt/homelab-ai-bot/data/rag_mode.json"))
_DEFAULT_ON = True
_lock = threading.Lock()
_active: dict[str, bool] = {}
_loaded = False
BTN_OFF = "📁 Unterlagen: AUS"
BTN_ON = "📁 Unterlagen: AN"
def _load() -> None:
global _loaded, _active
if _loaded:
return
try:
if _STATE_PATH.exists():
data = json.loads(_STATE_PATH.read_text(encoding="utf-8") or "{}")
if isinstance(data, dict):
_active = {str(k): bool(v) for k, v in data.items()}
log.info("rag_mode geladen: %s Eintraege aus %s", len(_active), _STATE_PATH)
except Exception as e:
log.warning("rag_mode konnte State nicht laden: %s", e)
_loaded = True
def _save() -> None:
try:
_STATE_PATH.parent.mkdir(parents=True, exist_ok=True)
_STATE_PATH.write_text(json.dumps(_active, ensure_ascii=False, indent=2), encoding="utf-8")
except Exception as e:
log.warning("rag_mode konnte State nicht schreiben: %s", e)
def is_document_mode(channel_key: str) -> bool:
return _active.get(channel_key, False)
with _lock:
_load()
return _active.get(channel_key, _DEFAULT_ON)
def set_document_mode(channel_key: str, on: bool) -> None:
if on:
_active[channel_key] = True
else:
_active.pop(channel_key, None)
with _lock:
_load()
_active[channel_key] = bool(on)
_save()
def toggle_document_mode(channel_key: str) -> bool: