fix(brain): Memory-Suche filtert jetzt Rauschen — score_threshold + kleineres k

Bug: bei kleiner DB (31 Eintraege) lieferte die Suche fuer JEDES Wort
fast alles als Treffer zurueck — k=20 Top-N ohne Threshold sorgte
dafuer dass auch "banane" zehn vermeintliche Treffer mit Scores
0.09-0.22 (= Rauschen) zurueckgab.

Fix:
- vector_store.search() bekommt optional score_threshold (an Qdrant
  durchgereicht, das nimmt's nativ)
- /memory/search endpoint hat score_threshold-Query-Param (default 0.30)
- Diagnostic schickt k=10 + score_threshold=0.30 statt k=20 ohne Threshold
- "Keine Treffer"-Info-Box wenn alle Treffer < Threshold

MiniLM-multilingual liefert typischerweise:
  >0.50 → starker Treffer
  0.30-0.50 → relevant
  0.20-0.30 → grenzwertig
  <0.20 → Rauschen

Mit score_threshold=0 (oder None) bleibt die alte Top-N-Semantik
fuer Aufrufer die Rauschen explizit wollen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 15:59:05 +02:00
parent 051d629cb3
commit daf0d44dd7
3 changed files with 34 additions and 7 deletions
+7 -1
View File
@@ -184,9 +184,14 @@ class VectorStore:
k: int = 5,
type_filter: Optional[str] = None,
exclude_pinned: bool = True,
score_threshold: Optional[float] = None,
) -> List[MemoryPoint]:
"""Semantische Search. Standard: pinned-Punkte ausgeschlossen
(die kommen separat via list_pinned in den Prompt)."""
(die kommen separat via list_pinned in den Prompt).
score_threshold: nur Treffer mit Cosine-Similarity >= Schwelle
zurueckgeben. None = keine Filterung. MiniLM-multilingual liefert
typischerweise 0.3-0.6 fuer relevante Treffer; <0.25 ist Rauschen."""
must = []
must_not = []
if type_filter:
@@ -202,6 +207,7 @@ class VectorStore:
query_filter=flt if (must or must_not) else None,
limit=k,
with_payload=True,
score_threshold=score_threshold,
)
return [MemoryPoint.from_qdrant(p) for p in results]