feat(local-llm): B1b — lokale Tools (web_search via SearXNG, Timer, Spotify, Memory)
Das lokale Tier kann jetzt Werkzeuge nutzen — Wetter/News/Fakten laufen lokal
statt ueber Claudes langsamen Web-Fetch.
- SearXNG-Container (aria VM, aria-net): self-hosted Meta-Suche, keyless,
JSON-API aktiviert (aria-data/searxng/settings.yml), Rate-Limiter aus.
Brain-Env SEARXNG_URL.
- web_search-Tool in META_TOOLS + _dispatch_tool (_web_search fragt SearXNG,
gibt Titel/Snippet/URL der Top-Treffer). Steht auch Claude zur Verfuegung.
- Lokaler Tool-Loop (_try_local_fast_lane): kuratiertes Set web_search /
memory_search / trigger_timer / run_spotify; max 3 Runden, sonst → Claude.
Break-/Escalate-Guard bleibt.
- Router: should_try_local schliesst nur noch CLAUDE-ONLY-Themen aus (Bild,
Skill, Projekt, OAuth, Licht, Kalender/Mail). Wetter/Timer/News/Musik/Memory
gehen jetzt lokal. Verifiziert (alle Testfaelle korrekt).
- Schlanker Local-Prompt mit Tool-Guidance ("nur nutzen wenn noetig, sonst
Smalltalk direkt beantworten"). Skill-BAUEN bleibt Claude-only.
Deploy: ARIA-VM brain+bridge+searxng, Gamebox llm-adapter (tool-passthrough).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+40
-22
@@ -57,15 +57,17 @@ def load_config() -> dict:
|
||||
# lokale Tier soll nur die klaren Plauder-Turns abgreifen; Fehlklassifikation
|
||||
# faengt zusaetzlich das <<ESCALATE>> im Modell selbst ab.
|
||||
|
||||
# Wortstämme, die auf Tool-/Aktionsbedarf hindeuten → nicht lokal (in B1a).
|
||||
# CLAUDE-ONLY-Themen → nicht lokal. Seit B1b hat das lokale Tier Werkzeuge
|
||||
# (web_search, memory_search, trigger_timer, Spotify), daher gehen Wetter, News,
|
||||
# Fakten, Timer, Musik, Gedaechtnis-Suche jetzt LOKAL. Nur was das lokale Tier
|
||||
# nicht kann bleibt hier: Bilder, Skills, Projekte, OAuth, Smart-Home (keine
|
||||
# Anbindung), Kalender/Mail (kein Tool).
|
||||
_TOOL_HINTS = re.compile(
|
||||
r"\b(wetter|temperatur|regne|timer|erinner|weck|licht|lampe|steckdose|"
|
||||
r"spotify|musik|lied|song|playlist|lauter|leiser|"
|
||||
r"bild|generier|male?\b|zeichne|foto|"
|
||||
r"merk dir|memory|gedächtnis|erinnere dich|"
|
||||
r"skill|trigger|projekt|oauth|spotify|kalender|termin|"
|
||||
r"such(e|st)?\b|google|internet|news|nachrichten|aktie|kurs|"
|
||||
r"maild?|email|nachricht schreiben|sende)\b",
|
||||
r"\b(bild|generier|male?\b|malen|zeichne|foto|"
|
||||
r"skill|projekt|oauth|"
|
||||
r"licht|lampe|steckdose|rollade|heizung|"
|
||||
r"kalender|termin|"
|
||||
r"maild?|e-?mail|nachricht schreiben)\b",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
@@ -104,31 +106,47 @@ def should_try_local(user_message: str, cfg: dict) -> bool:
|
||||
# (WAS ARIA kann, ohne volle Schemas) + Escalation-Regel. KEINE Tool-Schemas,
|
||||
# kein volles Memory (B1a).
|
||||
|
||||
# Was das lokale Tier NICHT selbst kann → dafuer eskaliert es an Claude.
|
||||
_AWARENESS = (
|
||||
"ARIA kann ausserdem (ueber ihr grosses Backend, nicht in diesem schnellen "
|
||||
"Modus): Wetter/Zeit/Websuche, Timer & Erinnerungen, Musik (Spotify) & Licht "
|
||||
"steuern, Bilder generieren, ins Gedaechtnis schreiben/suchen, Skills bauen, "
|
||||
"Projekte & OAuth verwalten."
|
||||
"Nur das grosse Modell (nicht du im Schnell-Modus) kann: Bilder generieren, "
|
||||
"Skills bauen/aendern, Projekte & OAuth verwalten, ins Gedaechtnis SCHREIBEN, "
|
||||
"sowie tiefe/technische Analysen und langen Code."
|
||||
)
|
||||
|
||||
|
||||
def build_local_system_prompt(identity_anchor: str, pinned_persona: str = "") -> str:
|
||||
def build_local_system_prompt(identity_anchor: str, has_tools: bool = False,
|
||||
pinned_persona: str = "") -> str:
|
||||
"""Schlanker System-Prompt fuers lokale LLM. identity_anchor = derselbe
|
||||
Anker wie bei Claude (Rolle haelt); pinned_persona optional kurz."""
|
||||
Anker wie bei Claude (Rolle haelt)."""
|
||||
parts = [
|
||||
identity_anchor.strip(),
|
||||
"",
|
||||
"## SCHNELL-MODUS",
|
||||
"Du laeufst gerade als schnelles lokales Modell fuer einfache, kurze "
|
||||
"Alltags-Konversation. Antworte knapp, freundlich, auf Deutsch, als ARIA.",
|
||||
"Du laeufst gerade als schnelles lokales Modell fuer Alltags-Konversation "
|
||||
"und einfache Aufgaben. Antworte knapp, freundlich, auf Deutsch, als ARIA.",
|
||||
]
|
||||
if has_tools:
|
||||
parts += [
|
||||
"",
|
||||
"## DEINE WERKZEUGE — nur nutzen wenn die Frage es WIRKLICH braucht",
|
||||
"- `web_search`: aktuelle Infos aus dem Netz — Wetter, News, Fakten, "
|
||||
"Preise, Oeffnungszeiten. Bei Wetter: nimm Stefans Ort aus dem "
|
||||
"GPS-Hinweis in der Nachricht.",
|
||||
"- `memory_search`: in ARIAs Gedaechtnis nachsehen (lesen).",
|
||||
"- `trigger_timer`: Timer/Erinnerung setzen ('in 10 Minuten…').",
|
||||
"- `run_spotify`: Musik steuern (naechster Titel, Pause, weiter).",
|
||||
"WICHTIG: Bei reinem Smalltalk ('wie gehts', Begruessung, Meinung) "
|
||||
"KEIN Werkzeug — einfach direkt antworten. Werkzeuge nur bei echtem "
|
||||
"Bedarf; erfinde keine.",
|
||||
]
|
||||
parts += [
|
||||
"",
|
||||
"## WAS DU HIER NICHT TUST",
|
||||
"## WAS DU HIER NICHT KANNST",
|
||||
_AWARENESS,
|
||||
"Fuer alles, was ein Werkzeug/eine Aktion braucht, tiefer/technischer wird, "
|
||||
"aktuelles Wissen oder Nachschlagen verlangt, oder wo du unsicher bist: "
|
||||
f"antworte AUSSCHLIESSLICH mit exakt `{ESCALATE_MARKER}` (nichts sonst). "
|
||||
"Dann uebernimmt automatisch das grosse Modell mit vollem Zugriff. "
|
||||
"Lieber einmal eskalieren als falsch raten.",
|
||||
"Dafuer — und bei tiefen/technischen Fragen, langem Code, oder wenn du "
|
||||
f"unsicher bist — antworte AUSSCHLIESSLICH mit exakt `{ESCALATE_MARKER}` "
|
||||
"(nichts sonst). Dann uebernimmt das grosse Modell mit vollem Zugriff. "
|
||||
"Lieber einmal eskalieren als falsch raten oder ein Werkzeug erfinden.",
|
||||
]
|
||||
if pinned_persona.strip():
|
||||
parts += ["", "## PERSONA", pinned_persona.strip()]
|
||||
|
||||
Reference in New Issue
Block a user