Image

Домашняя векторная БД + RAG

Пример поиска
Пример поиска

Исходная идея

Часто приходится искать в огромной куче документов какую нибудь частную, специфичную вещь. На данный момент, только лично у меня более 2Gb различных pdf файлов. Зачастую разбросанных не системно. И хотя обычно представляешь где искать, но это отнимает время. Захотелось иметь инструмент ускоряющий поиск.

Для запуска всего этого есть сервер в домашней сетке

  • AMD Ryzen 7, RTX 5060ti 16Gb, 32Gb ОЗУ

  • Ubuntu 24.04, ollama v0.12.3. nvidia v580.95.05. CUDA v13.0, docker qdrant/qdrant:latest

Первая мысль: “a не до обучить ли какую ни будь сетку на данных из документов”.

Но первые же эксперименты показали, то даже просто формирования искусственного набора QA (вопрос+ответ) на 16Gb GPU не реально.

Формирование одной записи QA по одному чанку – это 3..10 сек. на каждый чанк нужно хотя бы 5 вопросов. И все надо вычитывать, поскольку каждые 4-я пара QA это либо бред, либо LLM уходит от темы. Для ~1Gb исходных данных это очень большие затраты.

Остался вариант «векторная БД + RAG»

Казалось все просто. Накидать за пару вечеров код, что бы получить векторный поиск по смыслу и прикрутить генерацию LLM по вопросу и найденному чанку. Обычная «наивная» реализация RAG исходя из ограничения аппаратных ресурсов.

Для кода был выбран python (v3.12.3)

Не очень люблю питон. В первую очередь из за отсутствия реализации полноценной многопоточности. Но, в данном случае, используется как скриптовый язык обработки данных и для «домашних» задач сойдет.

Исходя из объективно/субъективных требований выбрал архитектуру

  1. Ollama с вызовом http+json API (‘/api/embed’ + ‘/api/generate’) напрямую.

  2. Qdrant в виде docker контейнера (быстро и просто). Обращение через http+json api

  3. Хранение документов и картинок страниц на файловой системы и ссылками на них в payload записей Qdrant.

  4. Одностраничный сайт для поиска без идентификации/аутентификации (домашняя сеть же)

Так оно и оказалось. Написать ПО оказалось не долго. Действительно ничего принципиального сложного.

Хотя потратил кучу времени на создание одно страничного сайта.

Под впечатлением статей типа «как я бросил программировать и занялся Вайб-кодингом и заработал за 1 день несколько миллионов», решил принципиально создать одностраничный примитивный сайт вообще не трогая код и только вымаливая у LLM нужный мне вариант.

Я тряпка.

Я сдался после, наверное, всего 7-8 попыток. Когда объем промта стал близок к объему кода, а изначально сгенерированный LLM более менее приличный шаблон кода стал напоминать клубок переваренной спагетти. Наверное, на колени нужно было встать перед клавиатурой и вымаливать у LLM (не локальной) рабочий вариант. Взял в итоге один из сгенеренных вариантов и доделал руками за 15 минут.

А всего-то нужно было перенаправить в режиме stream поток токенов ответа от ollama через серверную часть сайта напрямую в поле html страницы, что бы была иллюзия интерактивности.

Я не знаю как вайб-кодеры, как они (утверждают «не поправляя код») умудряются создавать что-то более менее сложное, а потом это еще запросами к LLM допиливать. LLM это какой-то генератор банальностей и распространенных ошибок из интернета. Что-то простое — без проблем. Шаг вправо/влево от шаблонных решений и получаешь убедительный бред, который не работает и не может работать.

Но, вылезли первые нежданчики. Ответы в топе были, мягко скажем, не адекватны вопросам.

Ошибка выбора модели для эмбединга

Выбрал модель «embeddinggemma:latest».
Зря.
Модель, выложенная месяц/два назад, не обязательно самая хорошая. Что с ней не так – не знаю. Но время выдачи вектора эмбединга в ollama у нее не предсказуемое. От 0.2сек до 30 сек. Обработка чанков для тестового набора документов (300Mb PDF) заняла 4:28:39. В отличие от, например mxbai-embed-large:latest которая выполнила то же самое за 0:04:49. Хотя именно эта ошибка выбора сподвигла на дальнейшие эксперименты.

Внимательно просмотрев код, данные чанков, логи и не найдя явных ошибок ни в логике ни в данных, решил начать с нуля. Т.е. с примеров на «причесанных данных», которые приводятся в Интернете и идеально работают.

Вдруг я что-то упустил, сразу пытавшись загрузить все что мне нужно в векторную БД и не получив ожидаемый результат на реальных данных. Отложил в сторонку реальные документы и сделал песочницу.

Эксперименты в песочнице с разными моделями

В статьях постоянно приводят же примеры прямо в jupyter notebook «вот 10 строк залили в chromadb, а вот сразу нашли нужный текст по запросу». Решил пойти по шагам от этого. Что бы понять почему на реальных данных все так красиво не работает.

Данные для тестов нагенерил конечно не сам (LLM), но вычитал и явного бреда там нет. (https://github.com/mmMikeKn/local-vector-db/tree/main/py_tests/tests_local)
Как оказалось, выбор модели эмбеддинга имеет решающее значение. И не нужно никому доверять в оценках модели. Нужно проводить тесты самому. Графическое отображение результатов тестов по моделям показался более наглядным чем просто обобщенные цифры.

  • Точка на диаграмме – это чанк в списке ответа на поиск. Оси: X — номер вопроса, Y — дистанция между вектором вопроса и вектором найденного чанков в топе выдачи.

    • Зеленый цвет – найденный чанк прямо соответствует вопросу (в тестовых данных). Остальные точки серые – это другие чанки в списке найденных. Просто для наглядности что бы оценить их «дистанцию» до вопроса.

    • Красный цвет – ни один найденный чанк не соответствует вопросу.

Признаки наилучшего поиска на диаграмме

  • Зеленая точка лежит ниже всех и максимально близко к 0 (ось Y). Т.е. «дистанция» между вектором эмбеддинга вопроса и ответа минимальная.

  • Серые точки лежат заметно выше зеленой – хорошая дифференциация ответов в списке найденных ответов.

  • Красный точек нет (ну или очень мало)

Результаты всем моделям можно посмотреть в https://github.com/mmMikeKn/local-vector-db/tree/main/py_tests/tests_local/plt

Все тесты сделаны на одном и том же наборе данных

Модель embeddinggemma:latest

Несмотря на то, что модель свежая, но она отвратительная по качеству. Размер 621 MB (размер привожу в том, сколько фактически займет GPU памяти. Для меня это важней, чем количество параметров), контекст 2048, вектор 768. Время расчета эмбеддинга не предсказуемо в широких пределах. От 300ms до 30 сек (!). Почему? Не знаю. Не вникал и не интересно. Есть из чего выбирать.

Диаграммы тестов

embeddinggemma EN
embeddinggemma EN
embeddinggemma RU
embeddinggemma RU

Модель (русскоязычная) evilfreelancer/FRIDA:latest

Просто не грузится в ollama с ошибкой INFO source=sched.go:438 msg=»Load failed» model=/usr/share/ollama/.ollama/models/blobs/sha256-b94dd828625ffee6bd86723e18c5bf8b7a452d71d8d981dde45a974134c8bb03 error=»llama runner process has terminated: exit status 2″. Хотя находится в списке доступных для ollama и версия ollama, судя по описанию, подходящая. Не стал разбираться. Тем более, что у нее окно контекста всего 512

Модель evilfreelancer/enbeddrus:latest

Позиционируется как до обученная на русском. Размер 336MB, контекст 512.
Да простят меня авторы модели, но, по моим тестам, оказалась хуже мультиязычных схожего размера.

Диаграммы тестов

enbeddrus EN
enbeddrus EN
enbeddrus RU
enbeddrus RU

На этом закончил эксперименты с «русскими» моделями и занялся мультиязычными. Все они, кроме ‘qwen3-embedding’ оказались приблизительно похожи +/- по результатам.
Но явно видна корреляция между общим размером модели в памяти GPU (оцениваю по ресурсам GPU) и результатами. Чем больше, тем лучше результат. Что ожидаемо.

После всех экспериментов остановился на

Модель qwen3-embedding:latest

Довольно «тяжелая» модель 4.7 GB с огромным контекстным окном и размерностью вектора в 4096. Основной недостаток – высокое потребление ресурсов GPU. Слышно, как включается вентилятор на карте при обработке всех документов. На остальных моделях такого нет. Но время расчета вектора стабильное в рамках одного и того же размера чанка. Для чанка в 2-3Kb байт (условно) это где-то 1000-1200ms. Но полностью использовать огромное контекстное окно данной модели для данной цели не стоит.

  1. Сильно увеличивается потребление ресурсов GPU на больших данных контекста.

  2. Крупные чанки документа приводят к не релевантным результатам поиска по коротким вопросам.

Диаграммы тестов

qwen3-embedding EN
qwen3-embedding EN
qwen3-embedding RU
qwen3-embedding RU
Нагрузка на GPU
Нагрузка на GPU

В результате модель «qwen3-embedding:latest» и была выбрана мной как рабочая для получения эмбеддинга по всем моим документам.
За ночь (удалил лог не посмотрев время) все обработалось и загрузилось в qdrant.

Мои впечатление и выводы от поиска по векторной БД и RAG

Восторженные статьи замалчивают недостатки как векторного поиска, так и RAG. В области AI вообще тренд «щенячьего восторга». Мне это всегда казалось сомнительным («..и вы то же говорите, что 10 раз за ночь») и собственный опыт это подтверждает. Да <сараказм>AI</сараказм> инструменты. Да удобные. Но вот не прям «ого..ого» с решением вопроса «42».

Контекстный поиск, совсем не заменяет поиск по подстроке

Если вам нужно найти что-либо очень конкретное, например, документ (страницу документа) со строкой вида «Требование 492», то вероятность, того, что страница с этим текстом попадет в топ результатов поиска по вектору контекста близка к 0.

Потому, что поиск по контексту и поиск по подстроке (конкретной) это принципиально разные вещи.

Следующее, что я буду прикручивать – это поиск по подстроке в чанках. К сожалению, qdrant на это плохо ориентирован. Но на 1-2Гб данных в конце концов можно и “grep” поискать. А задача типичная.

Малейшее изменение формулировки вопроса и получите другой набор результатов в топе выдачи. Все красиво на тестовых данных. А когда у вас есть ~100 очень похожих по стилю документов, на близкую тему, в которых полно таблиц, диаграмм, бюрократически/технически жаргонных оборотов и т.п., то нужно как минимум знать, что должно найтись.

Нужно постараться, что бы за несколько попыток поиска с разными формулировками найти нужный документ (хотя бы документ, не говоря уж о нужной странице). И никогда точно не знаешь: не нашлось потому что просто нет, или потому что далеко по контексту для данной модели эмбеддинга.

Все что работает «как бы хорошо» в контекстном поиске по товарам Озона (хотя лично меня он бесит. А вас? Недоделка какая-то, а не поиск), очень плохо работает для задачи поиска в технической документации.

Теперь о RAG

Лично мне, он был не особо нужен. Достаточно было png страниц документов на экране для быстрой оценки и ссылок на документы для скачивания. Но прикрутить было не долго и прикрутил (отдельной кнопкой на странице сайта). Но:

  • Скармливать весь документ в контекст запроса – не тянет GPU 16Gb. А для облачных LLM быстро токены кончатся, если в контекст передавать весь документ.

  • Чанк, по реальному документу, это, зачастую, обрывки мыслей и с этим LLM не справляется. Что локальная типа Qwen3-Coder-REAP-25B-A3B-MXFP4_MOE-GGUF:latest, что чатботы «больших» LLM.

    • Несут банальности на которых обучались, игнорируя содержимое чанка.

    • Впадают в откровенный бред.

  • Результаты (ну если не фиксировать параметр options.seed в запросе к LLM) будут каждый раз разные. И никогда не будешь знать: каких то данных в ответе LLM нет потому что их вообще нет, или потому что механизм генерации очередного токена в LLM обошел нужное тебе ветвление предсказаний очередного токена.

В общем то, что «говорит» LLM по вопросу + текст чанка меня сильно разочаровало. Хотя возится и подбирать системные промты и прочее не стал.

Даже большие LLM иногда такой убедительный бред несут, когда их спрашиваешь про узкие/частные случаи, которых не было или было мало в исходных данных обучения. А искать приходится не «почему небо голубое?», а информацию которой просто нет в Интернете (служебные документы и т.п.).

Ссылка на проект [GitHub](https://github.com/mmMikeKn/local-vector-db)

Источник: habr.com

✅ Найденные теги: Домашняя, новости

ОСТАВЬТЕ СВОЙ КОММЕНТАРИЙ

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

Фото сгенерированных лиц: исследование показывает, что люди не могут отличить настоящие лица от сгенерированных
Нейросети построили капитализм за трое суток: 100 агентов Claude заперли…
Скетч: цифровой осьминог и виртуальный мир внутри компьютера с человечком.
Сцена с жестами пальцами, где один жест символизирует "VPN", а другой "KHP".
‼️Paramount купила Warner Bros. Discovery — сумма сделки составила безумные…
Скриншот репозитория GitHub "Claude Scientific Skills" AI для научных исследований.
Структура эффективного запроса Claude с элементами задачи, контекста и референса.
Эскиз и готовая веб-страница платформы для AI-дизайна в современном темном режиме.
ideipro logotyp
Image Not Found
Звёздное небо с галактиками и туманностями, космос, Вселенная, астрофотография.

Система оповещения обсерватории Рубина отправила 800 000 сигналов в первую ночь наблюдений.

Астрономы будут получать оповещения о небесных явлениях в течение нескольких минут после их обнаружения. Теренс О'Брайен, редактор раздела «Выходные». Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной…

Мар 2, 2026
Женщина с длинными тёмными волосами в синем свете, нейтральный фон.

Расследование в отношении 61-фунтовой машины, которая «пожирает» пластик и выплевывает кирпичи.

Обзор компактного пресса для мягкого пластика Clear Drop — и что будет дальше. Шон Холлистер, старший редактор Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной странице вашего…

Мар 2, 2026
Черный углеродное волокно с текстурой плетения, отражающий свет.

Материал будущего: как работает «бессмертный» композит

Учёные из Университета штата Северная Каролина представили композит нового поколения, способный самостоятельно восстанавливаться после серьёзных повреждений.  Речь идёт о модифицированном армированном волокном полимере (FRP), который не просто сохраняет прочность при малом весе, но и способен «залечивать» внутренние…

Мар 2, 2026
Круглый экран с изображением замка и горы, рядом электронная плата.

Круглый дисплей Waveshare для креативных проектов

Круглый 7-дюймовый сенсорный дисплей от Waveshare создан для разработчиков и дизайнеров, которым нужен нестандартный экран.  Это IPS-панель с разрешением 1 080×1 080 пикселей, поддержкой 10-точечного ёмкостного сенсора, оптической склейкой и защитным закалённым стеклом, выполненная в круглом форм-факторе.…

Мар 2, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых