# Семантичний пошук на сайті на основі ембеддингів

> Як побудувати семантичний пошук на сайті на ембеддингах: вибір моделі, генерація векторів, зберігання в базі і видача релевантних статей.

## Чим семантичний пошук відрізняється від повнотекстового

Звичайний пошук на сайті шукає збіг слів: запит «як повернути кошти» не знайде статтю «політика повернення коштів», якщо в тексті немає точних слів із запиту. Семантичний пошук порівнює зміст, а не літери — він перетворює запит і текст статей на числові вектори (ембеддинги) і знаходить найближчі за змістом збіги, навіть коли слова різні.

Такий пошук корисний для бази знань, каталогу товарів і служби підтримки, де користувачі формулюють питання власними словами. Результат майже завжди точніший за повнотекстовий пошук за ключовими словами, а впровадження займає один робочий день на середньому 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](https://www.zevshost.net/uk/kb/pgvector-postgresql/): один SQL-запит шукає найближчі статті без окремого сервісу.
- Для великих каталогів із мільйонами документів варто порівняти спеціалізовані векторні бази — огляд наведено у статті [порівняння векторних баз даних](https://www.zevshost.net/uk/kb/vektornye-bd-sravnenie/).
- Для готової зв'язки пошуку і відповіді мовної моделі стане в пригоді схема зі статті [RAG на VDS](https://www.zevshost.net/uk/kb/rag-sistema-nastroika/).

## Як вбудувати пошук у сайт

Впровадження семантичного пошуку на наявний сайт зазвичай складається з однакових кроків незалежно від обраної бази:

- Порахувати ембеддинги для всіх поточних статей і зберегти їх разом з id матеріалу.
- Додати фонове завдання, яке перераховує вектор під час публікації або редагування статті.
- На бекенді приймати пошуковий запит, перетворювати його на вектор тією самою моделлю і шукати найближчі записи.
- Віддавати користувачу не лише заголовок, а й оцінку релевантності — це допомагає відкидати слабкі збіги нижче порогу.

Поріг зазвичай підбирають дослідним шляхом: для multilingual-e5-base гарним стартом слугує косинусна подібність вище 0.75.

## Типові помилки під час впровадження

Більшість проблем пов'язані не з самою моделлю, а з організацією пайплайну навколо неї:

- Різні моделі для індексації та для пошуку — вектори з різних моделей непорівнянні, результат завжди безглуздий.
- Відсутність перерахунку ембеддингів після редагування статті — пошук знаходить застарілу версію тексту.
- Надто довгі тексти без розбиття на абзаци — модель усереднює зміст усієї статті і втрачає деталі.
- Ігнорування порогу релевантності — без відсічки пошук завжди повертає щось, навіть коли підходящої відповіді немає.

Після налаштування пайплайну семантичний пошук вдасться розширювати: додати гібридний режим зі звичайним повнотекстовим пошуком або підключити переранжування результатів окремою моделлю.

---

Джерело: https://www.zevshost.net/uk/kb/semanticheskiy-poisk-embeddings/
