Stefan wollte ne richtige Suche statt nur "klingt aehnlich". Beide
Modi sind jetzt verfuegbar, Default ist Volltext:
- 📝 Wortlich (Substring, case-insensitive ueber Title + Content +
Category + Tags) — neuer Endpoint /memory/search-text. Full-Scan
via Qdrant scroll, k=50. Findet "cessna" exakt im Content. Bei
kleiner DB (<1000 Eintraege) unkritisch performant.
- 🧠 Semantisch (Embedder + score_threshold 0.30) — bestehender
/memory/search Endpoint. Findet konzeptuell verwandte Eintraege.
Diagnostic UI: Dropdown neben dem Suchfeld zum Modus-Wechsel.
Info-Banner zeigt klar welcher Modus aktiv ist.
Warum Wortlich Default: bei kleiner DB liefert Semantic gern False
Positives mit Score 0.30-0.45 fuer komplett unverwandte Begriffe
(z.B. "cessna" matched "Tageslog fuehren" mit 0.43). Wortlich ist
deterministisch und vermeidet das Rauschen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>