Memory-Guards + Voice-Sidecar-Install robuster
- mem0_service: Junk-Fact-Guard post-extraction (Regex + sofortiges Delete), custom_instructions praezisiert - mc2-memory-Plugin: Recall-Schwelle 0.3->0.5, Trivial-Turn-Filter (Begruessung/Quittungen nicht lernen) - voice_service/install.sh: Python-3.12-venv via uv, Piper-Binary + DE-Stimmen, Chatterbox best-effort Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+51
-6
@@ -20,6 +20,7 @@ Bind: 127.0.0.1 (nur lokal; MC2 proxyt nach außen).
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
@@ -95,12 +96,19 @@ def build_memory() -> Memory:
|
||||
"custom_instructions": (
|
||||
"RELEVANZ (ZWINGEND, WICHTIGSTE REGEL): Extrahiere NUR dauerhaft nützliche Fakten ÜBER DEN "
|
||||
"NUTZER (Identität, Vorlieben, Arbeitsweise), seine Projekte/Entscheidungen/Stände, stabile "
|
||||
"Fakten über Stack/Tools/Infrastruktur sowie verbindliche Regeln und Workflows. IGNORIERE "
|
||||
"VOLLSTÄNDIG und gib KEINE Fakten zurück bei: Tagesnachrichten und Welt-/Politik-/Börsen-/"
|
||||
"Promi-Ereignissen, Wetter, allgemeinem Weltwissen ohne Bezug zum Nutzer, vom Assistenten "
|
||||
"erzeugten Zusammenfassungen oder Recherche-Ergebnissen, Smalltalk, sowie Meta-Aussagen über "
|
||||
"den Gesprächsverlauf (z.B. 'der Nutzer fragt nach X', 'der Nutzer möchte Y prüfen', 'der "
|
||||
"Assistent tat Z'). Speichere nur, was in Wochen noch nützlich ist; im Zweifel NICHT speichern. "
|
||||
"Fakten über Stack/Tools/Infrastruktur sowie verbindliche Regeln und Workflows. "
|
||||
"NIEMALS FAKTEN ÜBER DEN ASSISTENTEN SELBST (ZWINGEND): Extrahiere KEINE Aussagen über den "
|
||||
"Assistenten/die KI (Hermes, Lucy), seine Fähigkeiten, seinen Zustand, seine Tools/MCP-Server, "
|
||||
"seine Cronjobs, Commit-/Versionsstände oder welche Modelle er nutzt. Das Subjekt eines Fakts "
|
||||
"ist IMMER der Nutzer oder sein Projekt — niemals 'der Assistent', 'Hermes' oder 'Lucy'. "
|
||||
"KEINE ZEITGEBUNDENEN ZUSTÄNDE: Ignoriere transiente Momentaufnahmen (Fehler-/Job-Läufe, "
|
||||
"Commit-Rückstand, Versions-Updates, 'gerade dabei'-/'hochgefahren'-/'aufgewärmt'-Status, "
|
||||
"Test- und Onboarding-Fragen). IGNORIERE VOLLSTÄNDIG und gib KEINE Fakten zurück bei: "
|
||||
"Tagesnachrichten und Welt-/Politik-/Börsen-/Promi-Ereignissen, Wetter, allgemeinem Weltwissen "
|
||||
"ohne Bezug zum Nutzer, vom Assistenten erzeugten Zusammenfassungen oder Recherche-Ergebnissen, "
|
||||
"Smalltalk, sowie Meta-Aussagen über den Gesprächsverlauf (z.B. 'der Nutzer fragt nach X', "
|
||||
"'der Nutzer möchte Y prüfen', 'der Assistent tat Z'). Speichere nur, was in Wochen noch "
|
||||
"nützlich ist; im Zweifel NICHT speichern. "
|
||||
"SPRACHE (ZWINGEND): Formuliere ALLE Fakten auf DEUTSCH — unabhängig von der "
|
||||
"Eingabesprache, niemals auf Englisch übersetzen. Eigennamen, Befehle, Pfade, Modell- und "
|
||||
"Produktnamen sowie etablierte Fachbegriffe (z.B. PowerShell-Push, Deploy, Qwen3.6, Neovim, "
|
||||
@@ -327,6 +335,30 @@ def classify_facts(facts: list[tuple[str, str]]) -> dict:
|
||||
return {}
|
||||
|
||||
|
||||
# Deterministischer Guard: mem0-OSS extrahiert trotz custom_instructions hartnäckig Fakten ÜBER
|
||||
# den Assistenten selbst (Hermes/Lucy) und transiente Zustände (Commit-Rückstand, Cronjob-Läufe,
|
||||
# Onboarding-/Test-Fragen). Diese Muster werden nach der Extraktion verworfen (der Fakt wird wieder
|
||||
# gelöscht) — reine Sicherungsschicht, unabhängig vom Extraktions-LLM.
|
||||
_JUNK_FACT_PATTERNS = [
|
||||
r"^\s*(?:der|die|das)\s+assistent", # "Der Assistent ..." (Selbstbeschreibung)
|
||||
r"\bassistent(?:in)?\s+(?:hermes|lucy)\b", # "... Assistent Hermes/Lucy ..."
|
||||
r"\bhermes[- ]agent\b",
|
||||
r"commits?\s+hinter", # Versions-Rückstand (transient)
|
||||
r"\bcronjob\b",
|
||||
r"beim\s+letzten\s+(?:lauf|mal)",
|
||||
r"onboarding[-\s]?frage|\btest-?frage\b",
|
||||
r"hat\s+den\s+assistenten\s+gebeten",
|
||||
r"auf\s+betriebstemperatur|hochgefahren",
|
||||
r"aktualisiert\s+sein\s+ged(?:ä|ae)chtnis", # Selbst-Meta über das Gedächtnis
|
||||
]
|
||||
_JUNK_FACT_RE = re.compile("|".join(_JUNK_FACT_PATTERNS), re.IGNORECASE)
|
||||
|
||||
|
||||
def _is_junk_fact(text: str) -> bool:
|
||||
"""True, wenn der extrahierte Fakt Assistenten-Meta oder ein transienter Zustand ist."""
|
||||
return bool(_JUNK_FACT_RE.search(text or ""))
|
||||
|
||||
|
||||
@app.post("/learn")
|
||||
def learn(body: LearnIn) -> dict:
|
||||
"""Auto-Lernen: Gesprächs-Turns/Text durchreichen → Mem0 EXTRAHIERT Fakten selbst
|
||||
@@ -342,6 +374,19 @@ def learn(body: LearnIn) -> dict:
|
||||
)
|
||||
results = res.get("results", [])
|
||||
|
||||
# Guard: frisch extrahierte Assistenten-Meta/transiente Fakten sofort wieder verwerfen.
|
||||
kept = []
|
||||
for r in results:
|
||||
if r.get("event") in ("ADD", "UPDATE") and _is_junk_fact(r.get("memory", "")):
|
||||
try:
|
||||
mem().delete(r["id"])
|
||||
except Exception:
|
||||
log.debug("Junk-Fakt-Löschung fehlgeschlagen für %s", r.get("id"))
|
||||
log.info("mem0 guard: Junk-Fakt verworfen: %s", (r.get("memory") or "")[:80])
|
||||
continue
|
||||
kept.append(r)
|
||||
results = kept
|
||||
|
||||
cats: dict = {}
|
||||
if body.classify:
|
||||
to_classify = [(r["id"], r.get("memory", "")) for r in results
|
||||
|
||||
Reference in New Issue
Block a user