Чем семантический поиск отличается от полнотекстового
Обычный поиск по сайту ищет совпадение слов: запрос «как вернуть деньги» не найдёт статью «политика возврата средств», если в тексте нет точных слов из запроса. Семантический поиск сравнивает смысл, а не буквы — он превращает запрос и текст статей в числовые векторы (эмбеддинги) и находит ближайшие по смыслу совпадения, даже если слова разные.
Такой поиск полезен для базы знаний, каталога товаров и службы поддержки, где пользователи формулируют вопросы своими словами. Результат почти всегда точнее полнотекстового поиска по ключевым словам, а внедрение занимает один рабочий день на среднем VDS.
Как работают эмбеддинги и какую модель выбрать
Модель эмбеддингов превращает текст в вектор фиксированной длины — обычно от 384 до 1536 чисел. Тексты с похожим смыслом получают близкие векторы, а расстояние между векторами (косинусное сходство) показывает степень похожести.
| Модель | Размерность | Языки | Где запускать |
|---|---|---|---|
| all-MiniLM-L6-v2 | 384 | в основном английский | CPU, легко |
| multilingual-e5-base | 768 | множество, включая русский | CPU или GPU |
| text-embedding-3-small | 1536 | множество | только через API |
Для сайта с русским и украинским контентом подходит multilingual-e5-base — она запускается локально на VDS без API-ключей и обходится без затрат на внешний сервис.
Установка окружения и генерация эмбеддингов
Установите библиотеку sentence-transformers и посчитайте векторы для всех статей базы знаний.
python3.11 -m venv /opt/search-env
source /opt/search-env/bin/activate
pip install sentence-transformers
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("intfloat/multilingual-e5-base")
texts = ["Как настроить резервное копирование", "Что делать при ошибке 500"]
vectors = model.encode(texts, normalize_embeddings=True)
print(vectors.shape)
Каждый вызов encode возвращает массив чисел для каждого текста. Нормализация векторов упрощает дальнейшее сравнение через скалярное произведение вместо полного косинусного расчёта.
Где хранить векторы и искать ближайшие совпадения
Готовые векторы нужно где-то хранить и быстро искать среди них ближайшие к запросу пользователя. Есть два основных пути: добавить векторный тип прямо в существующую реляционную базу или поднять отдельную специализированную базу.
- Для проекта, который уже работает на PostgreSQL, проще всего подключить расширение — см. pgvector в PostgreSQL: один SQL-запрос ищет ближайшие статьи без отдельного сервиса.
- Для крупных каталогов с миллионами документов стоит сравнить специализированные векторные базы — обзор дан в статье сравнение векторных баз данных.
- Для готовой связки поиска и ответа языковой модели пригодится схема из статьи RAG на VDS.
Как встроить поиск в сайт
Внедрение семантического поиска на существующий сайт обычно состоит из одинаковых шагов независимо от выбранной базы:
- Посчитать эмбеддинги для всех текущих статей и сохранить их вместе с id материала.
- Добавить фоновую задачу, которая пересчитывает вектор при публикации или редактировании статьи.
- На бэкенде принимать поисковый запрос, превращать его в вектор той же моделью и искать ближайшие записи.
- Отдавать пользователю не только заголовок, но и оценку релевантности — это помогает откидывать слабые совпадения ниже порога.
Порог обычно подбирают опытным путём: для multilingual-e5-base хорошим стартом служит косинусное сходство выше 0.75.
Типичные ошибки при внедрении
Большинство проблем связаны не с самой моделью, а с организацией пайплайна вокруг неё:
- Разные модели для индексации и для поиска — векторы из разных моделей несравнимы, результат всегда бессмысленный.
- Отсутствие пересчёта эмбеддингов после редактирования статьи — поиск находит устаревшую версию текста.
- Слишком длинные тексты без разбивки на абзацы — модель усредняет смысл всей статьи и теряет детали.
- Игнорирование порога релевантности — без отсечки поиск всегда возвращает что-то, даже когда подходящего ответа нет.
После настройки пайплайна семантический поиск можно расширять: добавить гибридный режим с обычным полнотекстовым поиском или подключить переранжирование результатов отдельной моделью.