“Найкраща система retrieval — це та, яку ти насправді виміряв.” — засвоєне на практиці
Одного ранку я відкрив GitHub Trending і побачив дещо незвичне: репозиторій MemPalace, автором якого значилася Міла Йовович — так, та сама актриса з «Обителі зла» — з 32.6k зірок, 4.1k форків і описом:
“Найвища оцінена AI-система пам’яті серед усіх, що коли-небудь проходили бенчмарк. І безкоштовно.”
Репозиторій справжній, бенчмарки опубліковані, числа вражаючі: 96.6% R@5 на LongMemEval — суворому датасеті з 500 питань про conversational memory. Спеціалізована система на ChromaDB, чотирирівневий стек пам’яті, 30-кратна компресія.
Що одразу поставило мені незручне запитання.
У другій частині цієї серії я описав, як ми зібрали гібридний retrieval для Ayona: BM25 + E5-ембединги, об’єднані через Reciprocal Rank Fusion. Тоді я показав код, архітектурні схеми й реальні помилки системи — але без формальних benchmark-чисел. Ми знали, що система достатньо добра для наших операційних потреб. Ми ніколи не питали: наскільки саме?
Тепер у мене був бенчмарк для порівняння. Чи може наш загальний agent pipeline конкурувати з цілеспрямованою бібліотекою пам’яті від зірки Голлівуду?
Ми провели експеримент. Результати нас здивували.
Методологія: однакові дані, однакові питання, однакові метрики
Чесне порівняння вимагає ідентичних умов. Ми обрали LongMemEval — датасет із 500 питань шести категорій, де до кожного питання прив’язано приблизно 53 сесії розмов як «стіг сіна». Задача: за питанням знайти правильну сесію(-ї) з набору.
Три системи в порівнянні:
| Система | Метод | Ембединги |
|---|---|---|
| Ayona BM25 | Okapi BM25 (k1=1.5, b=0.75) | Відсутні |
| MemPalace raw | Семантичний пошук ChromaDB | all-MiniLM-L6-v2 |
| MemPalace hybrid_v4 | ChromaDB + keyword overlap + temporal boosting | all-MiniLM-L6-v2 + евристики |
Адаптер Ayona будує новий BM25-індекс для кожного «стогу», запитує його і перевіряє, чи потрапляє правильна сесія у top-K результатів. Без ембедингів, без GPU, без зовнішніх API. Лише токенізація та IDF-scoring.
MemPalace створює ChromaDB-колекцію на кожне питання, ембедить усі сесії через all-MiniLM-L6-v2 (384-вимірний, ONNX runtime) і виконує семантичний пошук за схожістю. Режим hybrid_v4 додає keyword overlap boosting (30% ваги), temporal date parsing (40% зниження дистанції при збігу дати) та виокремлення цитованих фраз.
Одні й ті ж питання. Одна й та ж ground truth. Одні й ті ж метрики: R@1, R@5, R@10, MRR, NDCG@10.
Весь код — open-source.
Результати
| Метрика | Ayona BM25 | MemPalace raw | MemPalace hybrid_v4 |
|---|---|---|---|
| R@1 | 86.2% | 80.6% | 89.0% |
| R@5 | 96.8% | 96.6% | 98.2% |
| R@10 | 98.2% | 98.2% | 99.8% |
| NDCG@10 | 89.3% | 88.9% | 93.8% |
| MRR | 90.5% | — | — |
| Латентність | 20 мс/п | 1 540 мс/п | ~2 000 мс/п |
Перечитайте ще раз: BM25 без ембедингів досягає 96.8% R@5 — на рівні семантичного пошуку MemPalace (96.6%) і лише на 1.4 в.п. нижче за повний hybrid_v4. І робить це у 77 разів швидше.
Але ми не зупинилися на цьому.
Повний ablation: 7 конфігурацій
Ми протестували кожну комбінацію: BM25 сам по собі, BM25 із temporal date parsing, BM25 із keyword overlap boosting, vector-пошук через all-MiniLM-L6-v2, гібрид BM25+vector через RRF та повний enhanced hybrid. Та сама модель ембедингів, що й у MemPalace (all-MiniLM-L6-v2, 384-dim) — для чесного порівняння.
| Конфігурація | R@1 | R@5 | R@10 | мс/п |
|---|---|---|---|---|
| BM25 baseline | 86.2% | 96.8% | 98.2% | 20 |
| BM25 enhanced | 86.6% | 97.4% | 98.4% | 30 |
| Vector MiniLM-only | 75.2% | 92.8% | 96.8% | 1 427 |
| Hybrid BM25+MiniLM | 85.0% | 97.0% | 98.6% | 1 451 |
| Enhanced hybrid | 85.2% | 97.0% | 98.6% | 1 469 |
| MP raw (ChromaDB) | 80.6% | 96.6% | 98.2% | 1 540 |
| MP hybrid_v4 | 89.0% | 98.2% | 99.8% | ~2 000 |
Несподіванка: додавання ембедингів погіршило результат. BM25 enhanced (97.4%) перевершує кожну гібридну конфігурацію (97.0%). Векторний компонент вносить шум, який розмиває BM25-сигнал через RRF-злиття. На деяких питаннях правильна відповідь стоїть на #2 у BM25, але взагалі не потрапляє до top-30 векторного пошуку — і після fusion вилітає з фінального top-10.
Vector-only retrieval (92.8%) значно гірший за BM25 (96.8%). На питаннях single-session-user вектор падає до 82.9%, тоді як BM25 тримає 98.6%.
Breakdown по категоріях
| Категорія | n | BM25 | Enhanced | Vector | Hybrid | MP hv4 |
|---|---|---|---|---|---|---|
| knowledge-update | 78 | 100.0% | 100.0% | 98.7% | 100.0% | 100.0% |
| single-session-assistant | 56 | 100.0% | 100.0% | 98.2% | 98.2% | 100.0% |
| single-session-user | 70 | 98.6% | 98.6% | 82.9% | 97.1% | 98.6% |
| multi-session | 133 | 96.2% | 97.0% | 95.5% | 98.5% | 98.5% |
| temporal-reasoning | 133 | 95.5% | 97.0% | 91.7% | 95.5% | 97.7% |
| single-session-preference | 30 | 86.7% | 86.7% | 83.3% | 90.0% | 90.0% |
Дві категорії, де ембединги справді допомагають: preference-запити (86.7% → 90.0% з hybrid) і multi-session (97.0% → 98.5%). Дві категорії, де вони шкодять: temporal (97.0% → 95.5%) і single-session-user (98.6% → 97.1%).
Висновок: ембединги не є universally кращими чи гіршими — вони залежать від категорії. Розумна система маршрутизувала б запити до відповідного метода залежно від типу питання, а не зливала б усе підряд.
Що пішло не так і чому
Із 500 питань BM25 baseline пропустив 16. Після додавання temporal date parsing і keyword overlap boosting 3 були виправлені (без регресій), залишилося 13 промахів. Кожна помилка розповідає свою історію.
Temporal-запити (6 → 4 після enhancement). «Який кухонний прилад я купив 10 днів тому?» BM25 бачить токени: кухонний, прилад, купив, 10, днів, тому. Він знаходить сесії про кухонні прилади. Але «10 днів тому» вимагає перетворення відносної дати на абсолютну мітку часу та зіставлення з датами сесій — це BM25 принципово не може.
Ми додали temporal date parsing, який розв’язує відносні дати («минулий вівторок», «два тижні тому», «минулий місяць») відносно мітки часу питання і підвищує рейтинг сесій у цільовому вікні. Це виправило 3 із 6 temporal-промахів — без жодної регресії.
Preference-запити (4 промахи). «Що подати на вечерю цього вихідного з моїми власноруч вирощеними травами?» Відповідь захована в легкій розмові, де користувач згадував, що вирощує базилік. BM25 шукає вечеря, вихідний, власноруч, трави — але релевантна сесія використовує зовсім інші слова. Семантичні ембединги вловлюють концептуальну близькість між «власноруч вирощені трави» і «я вирощую базилік у своєму саду» без лексичного перетину.
Multi-hop aggregation (4 промахи). «Скільки різних лікарів я відвідав?» Для відповіді потрібно переглянути кілька сесій, виокремити згадки лікарів і порахувати унікальні. Жоден retrieval-прохід — незалежно від методу — не може одразу видати всі релевантні сесії. Це фундаментально задача reasoning, замаскована під retrieval.
Один справжній сюрприз (1 промах). «Скільки часу я витрачаю на практику скрипки щодня?» — простий фактичний запит, який BM25 мав би вловити. При перевірці виявилося, що у відповідній сесії було написано «я практикую дві години щодня на своєму інструменті» — без слова «скрипка» поруч із вказівкою часу. Семантичний пошук впіймав би це; лексичний — ні.
Чому BM25 працює (напрочуд добре)
Стандартне уявлення в спільноті RAG таке: ембединги вловлюють семантичний сенс, BM25 лише лексичний збіг, отже ембединги суворо кращі. Наш бенчмарк ставить це під сумнів стосовно задач retrieval у пам’яті розмов.
IDF — потужний дискримінатор. Коли хтось запитує «З якою спеціальністю я закінчив університет?», слово закінчив має помірний IDF (трапляється в багатьох сесіях), але дисертація — високий (трапляється в дуже небагатьох). BM25 ефективно цілиться в правильну сесію через сигнал рідкості. Ембединги ж відображають «закінчив» у семантичне сусідство «завершив освіту», «залишив школу», «академічне досягнення» — усе правдоподібно, але менш дискримінаційно.
Дані розмов насичені ключовими словами. На відміну від наукових статей чи технічної документації, розмови про повсякдення сповнені специфічних унікальних ідентифікаторів: імена, місця, заняття, предмети. «Я купив новий кавомолок у Williams-Sonoma» містить декілька токенів із високим IDF, які практично гарантують BM25-збіг. Ембединги мало що виграють, коли лексичний сигнал уже сильний.
«Прокляття ембедингів» на розмитих запитах. «Що подати на вечерю?» семантично близьке до сотень сесій, що згадують їжу, страви, приготування, рецепти. Простір ембедингів перевантажений саме там, де живе розмитість. BM25 принаймні вимагає певного лексичного перетину, щоб дати документу рейтинг — що діє як неявний фільтр точності.
Перевага hybrid-пошуку — від евристик, а не від ембедингів. MemPalace hybrid_v4 перевершує raw semantic search на 1.6% R@5. Але це перевищення забезпечує keyword overlap boosting і temporal date parsing — доменно-специфічні евристики, накладені поверх ембедингів. Ембединги самі по собі (raw mode) насправді гірші від BM25 за R@1 на 5.6 в.п.
Уроки для production RAG-систем
1. Вимірюй до того, як оптимізуєш
Ми витратили час на побудову E5 embedding pipeline, розгортання Docker-контейнера для локального inference, реалізацію FAISS-індексування — а наш BM25 baseline вже був на рівні 96.8% R@5. Без бенчмарку ми б продовжували оптимізувати embedding pipeline, так і не дізнавшись, що baseline вже конкурентний.
Ціна відсутності бенчмарку — не витрачені обчислення. Це витрачена інженерна увага на хибну проблему.
2. Hybrid не означає автоматично кращий
«Гібридний пошук» став стандартною рекомендацією в спільноті RAG. Поєднай BM25 і ембединги через RRF — і отримаєш найкраще з двох світів. Наші дані свідчать, що це правда лише за умови доменно-специфічних евристик. Чистий BM25+embedding fusion без temporal parsing чи keyword boosting може не виправдати додаткової складності та латентності.
3. Латентність — це фіча
Ayona надає відповіді через Telegram. При 20 мс на retrieval крок пошуку невидимий для користувача. При 1 540 мс — помітний. При 2 000 мс (hybrid_v4) — домінує в часі відповіді. У real-time чат-інтерфейсі перевага у 77 разів — це не оптимізація, це інша категорія продукту.
4. Аналіз помилок важливіший за aggregate-метрики
96.8% R@5 виглядає чудово. Але 16 промахів показують де система розчарує користувачів: temporal-питання та preference-запити. Це саме ті сценарії, де люди очікують, що AI буде «розумним» — і де production-система потребує явного опрацювання (date parsing, preference extraction), а не просто кращих ембедингів.
5. Відкриті бенчмарки тримають тебе чесним
Ми опублікували весь код, всі результати і скрипти для відтворення. Будь-хто може запустити той самий бенчмарк і перевірити наші числа. Це важливо, бо retrieval benchmarks надзвичайно чутливі до деталей реалізації: вибір токенізації, версії моделей ембедингів, параметри індексу. Прозорість — єдиний захист від випадкового самообману.
Що ми зробили далі — і що залишається
Після початкового BM25-бенчмарку ми реалізували і протестували чотири підходи:
Зроблено: Temporal date parsing (+0.6% R@5, 3 виправлення, 0 регресій). Розбирає «минулий вівторок», «два тижні тому», «минулий місяць» і підвищує рейтинг сесій у розрахованому вікні часу. Вартість: +10 мс латентності. Вердикт: інтегрувати у production.
Зроблено: Keyword overlap boosting (+0.2% R@5 у поєднанні з temporal). Формула MemPalace hybrid_v4, адаптована до BM25-балів. Маргінальний самостійний виграш — BM25 IDF вже вловлює більшу частину цього сигналу — але корисний у комбінації.
Зроблено: Hybrid BM25 + all-MiniLM-L6-v2 (та сама модель, що у MemPalace). Вердикт: не покращує загальний R@5 (97.0% < 97.4% enhanced BM25). Ембединги допомагають при preference (86.7% → 90.0%) і multi-session (96.2% → 98.5%), але шкодять temporal (97.0% → 95.5%) і single-session-user (98.6% → 97.1%). Глобальний hybrid — чистий мінус.
Зроблено: QMD query expansion — вердикт: концепція працює, overhead занадто великий. Ми запустили QMD (Qwen3 0.6B GGUF, локально) на 50-питання підвибірці у двох режимах:
- QMD search (FTS5 BM25) — 64% R@5 за 2 561 мс. SQLite FTS5 значно гірший за Okapi BM25 (96.8%), що підтверджує: якість реалізації BM25 має принципове значення.
- QMD query (BM25+Vec+Expand, без reranking) — 88% R@5 за 13 075 мс. LLM query expansion підіймає R@5 з 64% до 88% усередині pipeline QMD — але все одно на 8.8 в.п. нижче за наш BM25 baseline (96.8%) при 650-кратному overhead (13 075 мс проти 20 мс).
Концепція query expansion для preference-запитів залишається перспективною, але вартість інфраструктури вимагає легшої реалізації — точечного мікро-виклику, а не повного GGUF-pipeline, для 6% запитів, яким він справді потрібен.
Зроблено: Тест на українській морфології (50 питань, Google Translate). BM25 без лематизації: 94.0% R@5 (−3% порівняно з англійським baseline). З лематизацією pymorphy3: 96.0% R@5, 100.0% R@10 — повний паритет з англійською. Штраф за морфологію менший, ніж очікувалося; вартість лематизації належить до часу індексації, а не запиту. Повний breakdown — у секції «Бонус» нижче.
Наступне: Selective hybrid routing — класифікувати запити та маршрутизувати на BM25 або hybrid залежно від типу. Preference і multi-session → hybrid. Решта → BM25 enhanced.
Наступне: Бенчмарк LoCoMo (1 986 multi-hop питань) — стрес-тест для виявленої слабкості в multi-session.
Бонус: чи працює BM25 на українській мові?
База знань Ayona — переважно україномовна. Українська має багату морфологію: 7 відмінків іменників, види дієслів, рід — одне слово може мати 10+ поверхневих форм. «Лікар» (називний) стає «лікаря» (родовий), «лікарю» (давальний), «лікарем» (орудний). Ванільний BM25 трактує їх як різні токени.
Ми перекласли підвибірку з 50 питань LongMemEval на українську (Google Translate) і запустили чотири конфігурації:
| Конфігурація | R@1 | R@5 | R@10 | MRR | ms/q |
|---|---|---|---|---|---|
| BM25 baseline (EN, 500Q — референс) | 86.2% | 96.8% | 98.2% | 90.5% | 20 |
| BM25 enhanced (EN, 500Q — референс) | 87.0% | 97.4% | 98.6% | 91.4% | 30 |
| BM25 baseline (UK, 50Q) | 88.0% | 94.0% | 96.0% | 90.9% | 19 |
| BM25 enhanced (UK, 50Q) | 88.0% | 94.0% | 96.0% | 90.9% | 30 |
| BM25 + лематизація pymorphy3 (UK, 50Q) | 86.0% | 96.0% | 100.0% | 91.2% | 1 498 |
| BM25 enhanced + лематизація (UK, 50Q) | 86.0% | 96.0% | 100.0% | 91.2% | 2 642 |
Три висновки:
1. Українська морфологія коштує ~3% R@5. Без лематизації BM25 падає з 96.8% (англійська) до 94.0% (українська) — скромний штраф. Це ефект невідповідності словника: токен запиту «купив» не збігається з «купила» в документі. Штраф менший, ніж очікувалось — частотне зважування BM25 частково компенсує, а ключові власні назви зазвичай не відмінюються.
2. pymorphy3-лематизація закриває розрив. З морфологічною нормалізацією через pymorphy3 R@5 сягає 96.0% — рівень англійського baseline. Усі відмінкові форми слова зводяться до словникової форми перед індексацією і запитом. R@10 досягає 100%: ідеальне покриття в топ-10.
3. Вартість затримки реальна, але уникна. Лематизація на час запиту коштує 1 498 ms/q — збільшення в 79 разів. Виробниче рішення: лематизувати при індексуванні (один раз, коли картки додаються до бази знань). Вартість під час запиту тоді наближається до нуля.
Вердикт: BM25 на українській добре працює «з коробки», а pymorphy3-лематизація виводить його на паритет з англійською. Для мов із багатою морфологією лематизація не є опціональною — але її вартість належить до часу індексації, а не запиту.
# Відтворіть тест на українській
pip install pymorphy3 pymorphy3-dicts-uk deep-translator
python src/translate.py data/longmemeval_s_cleaned.json --limit 50 --out data/longmemeval_uk_50q.json --provider google
python src/lme_adapter.py data/longmemeval_uk_50q.json --mode bm25 --language uk -v
python src/lme_adapter.py data/longmemeval_uk_50q.json --mode bm25 --language uk --lemmatize -v
Відтворіть самостійно
Все open-source: ayona-vs-mempalace-benchmark.
# 1. Завантажте датасет
curl -fsSL -o data/longmemeval_s_cleaned.json \
https://huggingface.co/datasets/xiaowu0162/longmemeval-cleaned/resolve/main/longmemeval_s_cleaned.json
# 2. Запустіть BM25 бенчмарк (10 секунд, без GPU)
pip install numpy requests
python src/lme_adapter.py data/longmemeval_s_cleaned.json --mode bm25 -v
# 3. Запустіть BM25 enhanced (рекомендована конфігурація)
bash benchmarks/run_enhanced.sh
# 4. Запустіть бенчмарк MemPalace (~15 хвилин, CPU embedding)
pip install mempalace
bash benchmarks/run_mempalace.sh
Попередньо обчислені результати для всіх конфігурацій включені до results/.
Висновок
Ми вважали, що ембединги виграють. Ми думали, що спеціалізована бібліотека пам’яті перевершить загальний agent pipeline. Ми припускали, що додавання семантичного пошуку завжди виправдовує складність і затримки.
Жодне з цих припущень не вижило після зіткнення з бенчмарком.
BM25 — алгоритм 1994 року — досяг 96.8% recall на сучасному бенчмарку conversational memory, зрівнявшись зі системою ембедингів 2026 року при 77-кратній перевазі у швидкості. Після додавання temporal date parsing (+0.6%) він виходить на 97.4% — відстаючи від MemPalace hybrid_v4 лише на 0.8%.
Найбільш контрінтуїтивна знахідка: додавання ембедингів (all-MiniLM-L6-v2) до BM25 погіршило загальний retrieval (97.0% < 97.4%). Векторний шум розмиває BM25-сигнал при глобальному RRF-злитті. Ембединги допомагають рівно у двох категоріях — preference і multi-session — і шкодять у двох інших.
Невигідний урок: для retrieval у розмовах вузьке місце — не семантичне розуміння. Це невміння обробляти часові посилання та неявні переваги. Додавати ембединги без усунення цих конкретних помилкових патернів — дорогий спосіб не отримати майже нічого.
І ще один висновок, який часто ігнорують у англоцентричних бенчмарках: BM25 узагальнюється на мови з багатою морфологією. На українській (50 питань) BM25 досягає 94.0% R@5 без жодного мовоспецифічного налаштування — лише −3% від англійського baseline. pymorphy3-лематизація відновлює повний паритет: 96.0% R@5, 100.0% R@10. Алгоритм 1994 року працює у 2026-му між мовними сім’ями.
Практична рекомендація: починай із BM25. Виміряй його. Аналізуй помилки по категоріях. Додавай точкові покращення (temporal parsing, query expansion) для конкретних типів помилок, які ти знайдеш. Використовуй ембединги вибірково, а не глобально. Для мов із багатою морфологією лематизуй при індексуванні. І вимірюй усе — бо інтуїтивна відповідь («ембединги кращі») часто виявляється хибною.
Сергій Заболотній — DSc, дослідник NLP/LLM, професор, архітектор AI-систем. Будую Ayona — AI-native систему для дослідження та операцій.
Це Частина 4 серії «Архітектура Ayona/OpenClaw»:
- Частина 1: Модель вас не врятує — 7 архітектурних рівнів
- Частина 2: Довіра — це pipeline — hybrid retrieval, scoped access, delegation v1.1
- Частина 3: Від одного агента до композиції — мульти-агентне управління, онтологія, AutoResearch
- Частина 4: BM25 переміг ембединги — ця стаття