Русский
Поиск trip2g против qmd и obsidian-hybrid-search
Что сделали: собрали двуязычный набор из 236 запросов к справке Obsidian, прогнали на нём trip2g, qmd и obsidian-hybrid-search и посчитали всё одним скриптом — цифрам из чужих README не верили. Нашли две причины, по которым trip2g проигрывал на русском. Добавили поиск по алиасам: в своей категории запросов он поднял nDCG@5 с 0,81 до 0,98. Самый большой выигрыш дали поля, которые передаёт агент по MCP: на русском основном наборе плюс 0,10, на остальных около 0,05. Читать, если у вас поиск по заметкам и вы хотите знать, как он выглядит рядом с соседями.
После статьи Как ищут другие остался вопрос, на который разбор кода не отвечает: а какой из этих поисков лучше? В README obsidian-hybrid-search есть сравнение с qmd: 0,733 против 0,659 по nDCG@5. Но это цифры автора, на его машине, и результатов прогона qmd в репозитории нет. Мы решили померить сами.
Набор
Автор obsidian-hybrid-search собрал хороший набор для проверки: 58 запросов к справке Obsidian, написанных вручную, с правильными и частично правильными ответами. Справка — это ровно наш случай: обычные заметки с frontmatter, вики-ссылками и алиасами.
В репозитории справки лежат её переводы на тридцать с лишним языков, в том числе русский: те же 176 страниц. У английской и русской страницы общий permalink, поэтому правильные ответы переносятся на русский без ручной разметки. Запросы мы перевели так, как их набрал бы человек, а не дословно.
Ещё 120 запросов написал отдельный агент: он прошёл по справке и собрал случаи, на которых поиск обычно спотыкается.
- запрос ровно совпадает с алиасом заметки;
- опечатки: «backlnks», «обратные ссылкы»;
- русская морфология: «как синхронизировать» против страницы «Синхронизация»;
- перефразировки без общих слов со страницей;
- вопрос на одном языке, ответ на другом;
- ответ спрятан глубоко в длинной странице;
- синтаксис:
==выделение==,$$,[[заметка#^блок]].
Каждый ответ он сверил с текстом страницы. Итого четыре набора: английский и русский основные по 58 запросов, английский и русский хитрые — 57 и 63.
Как выглядят хитрые запросы
Несколько примеров из прогона. В ячейках — на каком месте каждая система выдала нужную страницу; «—» значит, что в первой двадцатке её нет. Первые три запроса — к английской справке, остальные — к русской. Колонка «trip2g» — уже с поиском по алиасам.
| Запрос | В чём подвох | Нужная страница | obsidian-hybrid-search | qmd + Qwen3 | trip2g | trip2g + поля агента |
|---|---|---|---|---|---|---|
| Insider builds | это алиас страницы, а слово «Insider» есть на соседней странице про лицензию | Early access versions | 1 | 1 | 9 → 1 с алиасами | 2 |
| starred | старое имя плагина, осталось только в алиасе Plugins/Starred |
Bookmarks | 1 | 3 | — | 4 |
{{title}} |
эта переменная есть в трёх разных системах шаблонов | Templates | 15 | 2 | 15 | 2 |
| синхранизация через айклауд | опечатка и iCloud кириллицей | Синхронизация заметок между устройствами | 2 | 5 | 1 | 1 |
| на телефоне и на ноутбуке разные версии одной и той же заметки | ни слова «синхронизация», ни слова «устройства» | Синхронизация заметок между устройствами | 14 | 10 | 3 | 3 |
| how long is version history kept | вопрос по-английски, база русская | Часто задаваемые вопросы (Sync) | 10 | 1 | 1 | 1 |
$$ |
два символа и ни одного слова | Расширенный синтаксис форматирования | — | 12 | 1 | 2 |
| работает ли Obsidian без интернета | отдельной страницы нет, ответ в подразделе | Локальные и удалённые хранилища | — | — | 2 | 5 |
| вернуть старую версию заметки без подписки на Sync | всё решает «без подписки»: рядом есть платная «История версий» | Восстановление файлов | 9 | 10 | — | 3 |
Хорошо видно, где trip2g слаб. «starred» он не находит вовсе: алиас записан как Plugins/Starred, а наш поиск по алиасам требует точного совпадения, тогда как obsidian-hybrid-search прощает разницу нечётким поиском. На вопросе «без подписки на Sync» trip2g уверенно выдаёт платную «Историю версий» — ту самую страницу, которую запрос исключает.
Как мерили
- trip2g — наш гибридный поиск: полнотекстовый поиск bleve с русским и английским стеммингом, векторный поиск на bge-m3, слияние через RRF.
- obsidian-hybrid-search 0.15.2 — SQLite, FTS5, векторы multilingual-e5-small, поиск по алиасам и триграммам.
- qmd 2.8.3 — со своим расширением запроса и реранкером. На нашем сервере без видеокарты один запрос шёл от трёх до семи минут, поэтому qmd гоняли на MacBook с M3 Max и Metal. Два варианта: по умолчанию и с Qwen3-Embedding вместо английской embeddinggemma — это единственная настройка, которая нужна qmd для русского.
Все прогоны посчитаны одним скриптом с формулами из самого obsidian-hybrid-search: nDCG с оценкой 1 за правильный ответ и 0,5 за частично правильный.
Результаты
nDCG@5, чем больше, тем лучше:
| Набор | obsidian-hybrid-search | qmd | qmd + Qwen3-Embedding | trip2g | trip2g + алиасы | trip2g + поля агента |
|---|---|---|---|---|---|---|
| английский основной | 0,726 | 0,717 | 0,731 | 0,742 | 0,742 | 0,798 |
| английский хитрый | 0,722 | 0,733 | 0,764 | 0,767 | 0,785 | 0,815 |
| русский основной | 0,671 | 0,608 | 0,668 | 0,603 | 0,603 | 0,702 |
| русский хитрый | 0,684 | 0,670 | 0,771 | 0,815 | 0,815 | 0,866 |
Что выяснилось
Цифры из README разошлись с нашими. obsidian-hybrid-search воспроизвёл себя почти точно: 0,726 против заявленных 0,733. А qmd оказался заметно лучше, чем в том сравнении: 0,717 вместо 0,659. Разрыв в 0,07 превратился в 0,01. Мы не знаем, отчего так вышло: другая версия qmd, другая машина или другой режим. Поэтому и не стоит сравнивать по чужим таблицам.
На русском основном наборе trip2g проигрывал всем. Причин две, и обе видно по конкретным запросам.
- Полнотекстовый поиск требует, чтобы в тексте встретились все слова запроса. Запрос «свойства заметки во frontmatter» не находит в полнотекстовом поиске ничего: на русской странице этих четырёх слов в таких формах вместе нет. Остаётся один векторный поиск. obsidian-hybrid-search соединяет слова через OR и ищет их по префиксу, поэтому эту проблему не знает.
- Длинные страницы побеждают по лучшему куску. Заметка в векторном поиске получает оценку своего лучшего куска. У страницы про Obsidian CLI 163 куска, и хоть один из них оказывается близок почти к любому запросу. Эта страница и справка по Obsidian URI вылезали наверх в запросах, к которым не имели отношения.
Алиасы помогли точечно. trip2g раньше вообще не читал поле aliases из frontmatter. Мы добавили отдельный поиск по точному совпадению с названием или алиасом заметки, как у obsidian-hybrid-search, с весом 2 в RRF. В категории «запрос совпадает с алиасом» результат вырос с 0,813 до 0,980, в целом по английскому хитрому набору — с 0,767 до 0,785. За этим стоят два запроса, которые без алиасов не находились. На остальных наборах ничего не изменилось: ни плюса, ни минуса. На русском плюса нет, потому что русские алиасы в справке — это английские названия страниц, а такие запросы trip2g находил и так.
qmd переписывает запрос в три варианта своей моделью на 1,7 миллиарда параметров, прямо на сервере, на каждый запрос. Но у MCP-поиска по ту сторону всегда сидит агент — Claude, GPT или другая модель, во много раз больше. Он и так читает вопрос, знает контекст и язык. Если попросить его прислать эти три варианта вместе с запросом, решаются сразу две задачи: trip2g не нужно тащить в себя генеративную модель и считать её на каждый запрос, а варианты пишет модель намного сильнее. На нашем наборе это дало самый большой прирост из всего, что мы пробовали, — при сильном агенте. Со слабым (gpt-5.4-mini) прирост почти пропадает.
Главный выигрыш дали поля агента. Если агент, подключённый по MCP, передаёт вместе с запросом три необязательных поля — короткий запрос из двух-трёх слов, перефразировку и предложение, которое могло бы стоять в ответе, — trip2g выходит на первое место на всех четырёх наборах. На русском основном прирост десять пунктов, и это уверенно выше шума; на остальных наборах прирост около пяти пунктов, и на английском хитром он в пределах шума. Подробности, в том числе как мы подбирали имена полей, — в статье Расширение запроса можно отдать агенту.
qmd на русском без настройки проседает, а с одной настройкой выправляется. По умолчанию у qmd английская модель эмбеддингов, и на русском основном наборе он даёт 0,608. С Qwen3-Embedding — 0,668, на хитром русском — 0,771 вместо 0,670. Это одна переменная окружения, но после неё всю базу нужно перевекторизовать.
Что нашли по дороге
- Баг в trip2g. Если во frontmatter стоит пустое
description:илиdescription: null, сервер не может собрать заметки, и падает вся пачка синхронизации из ста заметок. В справке Obsidian так оформлены по две страницы на язык. Для бенчмарка мы вычистили эти строки; сам баг будет исправлен отдельно. - obsidian-hybrid-search возвращает пути в Unicode-форме NFD:
йиёраскладываются на букву и знак. Если сравнивать пути побайтно, как сделали мы в первом прогоне, его русский результат занижается с 0,671 до 0,447. - obsidian-hybrid-search не видит русские теги в тексте:
#noteнаходится,#заметканет. Теги во frontmatter работают.
Оговорки
- Модели эмбеддингов разные. У trip2g bge-m3 на 568 миллионов параметров, у obsidian-hybrid-search — multilingual-e5-small, у qmd — embeddinggemma на 300 миллионов. Мы сравнивали системы в тех настройках, в которых их ставят, а не модели поиска как таковые.
- Наборы небольшие. По 57–63 запроса на набор — это разница в пару запросов на каждые три пункта nDCG. Разницу в 0,01–0,02 между системами мы бы не считали значимой. Бутстрап подтверждает уверенно только прирост от полей агента на русском основном наборе.
- Хитрые запросы и поля агента писали модели. Хитрые запросы проверены по тексту справки, но независимая перепроверка их разметки ещё не закончена. Поля агента писал отдельный агент, которому дали только вопросы и описания полей; с gpt-5.4-mini в роли агента прирост колеблется от минус пяти до плюс пяти пунктов.
Как повторить
Скрипты, наборы запросов и сырые результаты прогонов лежат в репозитории: scripts/obsidian-help-bench/, testdata/eval/obsidian-help/, docs/superpowers/eval-runs/obsidian-help/. Сама справка Obsidian не лицензирована для распространения, поэтому скрипт скачивает её сам, на том же коммите, по которому размечались ответы.