mirror of
https://gitverse.ru/kpa39l/memory-os.git
synced 2026-09-29 09:35:05 +00:00
Initial commit: Hermes skill memory-os
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# Icarus Threshold Bug — 2026-07-16 (v2)
|
||||
|
||||
## The Problem
|
||||
|
||||
`icarus/hooks.py` calls `_search_qdrant(query, top_k=2, threshold=0.55)` from `pre_llm_call()`.
|
||||
This passes `score_threshold=0.55` to `search_with_fallback()` in `context_enhancer.py`.
|
||||
|
||||
RRF fusion (hybrid dense+sparse) returns scores 0.33–0.50 even for good matches.
|
||||
At 0.55, every query is filtered out. The search cascade falls to `level="none"`,
|
||||
then hits SQLite fallback (`[CE-FALLBACK] SQLite search failed: no such table: lineage`),
|
||||
and finally returns an empty list. Icarus injects nothing.
|
||||
|
||||
This is fundamentally different from dense-only search, which returns COSINE scores
|
||||
0.90+ for the same queries. The threshold bug was invisible because:
|
||||
- `_search_qdrant()` is fail-open (returns `[]` on any error)
|
||||
- The plugin loads and runs without crashing
|
||||
- "Runs without crashing" ≠ "returns useful results"
|
||||
|
||||
## Root Cause: RRF vs Dense Score Regimes
|
||||
|
||||
RRF (Reciprocal Rank Fusion) normalises scores from two independent retrievers
|
||||
(dense and sparse) into a shared 0–1 range via `1/(k + rank)`. This inherently
|
||||
produces clustered scores around 0.33–0.50 regardless of the underlying semantic
|
||||
similarity. This is **not a bug in RRF** — it's how RRF works.
|
||||
|
||||
Dense-only search returns raw COSINE similarity (0.90+ for good matches).
|
||||
|
||||
The same query at different thresholds:
|
||||
|
||||
```
|
||||
Query: "XRay VPS VPN"
|
||||
|
||||
=== Hybrid (RRF), threshold 0.55 ===
|
||||
Level: none, Results: 0
|
||||
Falls through to SQLite → [CE-FALLBACK] All fallback levels exhausted.
|
||||
|
||||
=== Dense-only, threshold 0.35 ===
|
||||
Level: dense-only, Results: 3
|
||||
[0.9938] Пароль Юлии Зозули
|
||||
[0.9078] Nagios
|
||||
[0.9017] Клавиатуры
|
||||
|
||||
=== Hybrid (RRF), threshold 0.35 ===
|
||||
Level: hybrid, Results: 2
|
||||
[0.5000] Инструкция как безопасно расширить кластер Garage до 3+ нод (v2.1)
|
||||
[0.5000] Пароль Юлии Зозули
|
||||
|
||||
=== Hybrid (RRF), threshold 0.30 ===
|
||||
Level: hybrid, Results: 4
|
||||
[0.5000] Garage кластер
|
||||
[0.5000] Пароль Юлии Зозули
|
||||
[0.3333] Двухфакторная VPN
|
||||
[0.3333] Nagios
|
||||
```
|
||||
|
||||
At 0.35, RRF still filters the 0.33 results (2 out of 4 are lost).
|
||||
At 0.30, all 4 are returned.
|
||||
|
||||
## The Fix
|
||||
|
||||
Lower `threshold` in `_search_qdrant()` in `/opt/hermes/.hermes/plugins/icarus/hooks.py`
|
||||
from 0.55 to 0.30.
|
||||
|
||||
```python
|
||||
# Line 722 — NOW:
|
||||
qdrant_results = _search_qdrant(user_message, top_k=2, threshold=0.30)
|
||||
```
|
||||
|
||||
The comment above it was also updated to explain the RRF vs dense score gap.
|
||||
|
||||
## Verification
|
||||
|
||||
After fix, all queries return hybrid results within 6ms Qdrant time:
|
||||
|
||||
```
|
||||
XRay VPS VPN → hybrid, 4 results
|
||||
hermes plugin icarus → hybrid, 3 results
|
||||
telegram → hybrid, 4 results
|
||||
wireguard → hybrid, 4 results
|
||||
```
|
||||
|
||||
No SQLite fallback noise. No `level="none"`.
|
||||
|
||||
## Key Insight
|
||||
|
||||
When debugging an empty `[qdrant]` block in Icarus context injection:
|
||||
1. First check if `_search_qdrant()` even runs (no import error → PYTHONPATH fix)
|
||||
2. Then check if it returns results (threshold too high for RRF)
|
||||
3. These are SEPARATE bugs — the first was fixed 2026-07-14 (PYTHONPATH),
|
||||
the second on 2026-07-16 (threshold 0.55→0.30)
|
||||
Reference in New Issue
Block a user