Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions wiki-pages/Home.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- **WooCommerce** — синхронизация товаров и заказов в базу знаний для RAG
- **GSM телефония** — SIM7600E-H, голосовые звонки, SMS
- **Fine-tuning** — LoRA для LLM + TTS fine-tuning (Qwen3-TTS)
- **Vector Search** — микросервис семантического поиска (sentence-transformers + ChromaDB)
- **Wiki RAG** — база знаний с BM25 поиском и стеммингом для контекста LLM
- **Ветвление чатов** — OpenWebUI-style: не-деструктивное редактирование, регенерация, дерево веток
- **Закрепление и шаринг чатов** — организация сессий, совместная работа между пользователями
Expand Down Expand Up @@ -80,6 +81,7 @@
| [[Wiki-RAG]] | База знаний: документы, BM25 поиск |
| [[Chat-Sharing]] | Совместный доступ к чат-сессиям между пользователями |
| [[Claude-Code]] | Claude Code CLI терминал в админ-панели (WebSocket) |
| [[Vector-Search]] | Микросервис семантического поиска (embeddings + ChromaDB) |
| [[Backup]] | Экспорт/импорт конфигурации |
| [[Deployment-Profiles]] | Профили развёртывания (full/cloud/local) |
| [[API-Reference]] | Справочник API (REST, OpenAI-совместимый) |
Expand Down
277 changes: 277 additions & 0 deletions wiki-pages/Vector-Search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
# Vector Search (Векторный поиск)

Микросервис семантического поиска по текстовым документам. Работает полностью локально — без внешних API.

## Скриншот

<!-- Вставьте скриншот Swagger UI -->
![Vector Search](images/vector-search.png)

## Концепция

**Vector Search** — отдельный HTTP-микросервис, который:

- **Принимает текст** → разбивает на чанки → превращает в числовые векторы (embeddings)
- **Хранит векторы** в ChromaDB (persistent, на диске)
- **Ищет по смыслу** — cosine similarity между запросом и сохранёнными документами
- **Мультиязычный** — русский, английский, казахский и 50+ языков (модель `paraphrase-multilingual-mpnet-base-v2`)
- **Самодостаточный** — все вычисления локальные, без внешних сервисов

### Зачем нужен

| Задача | Как решает |
|--------|-----------|
| **RAG** | Индексация документации/FAQ, поиск релевантного контекста для LLM |
| **Каталог товаров** | Поиск по описаниям товаров «по смыслу» (а не по ключевым словам) |
| **Дедупликация** | Обнаружение перефразов и дубликатов (similarity > 0.85) |
| **Классификация** | Сравнение нового текста с эталонными категориями |

## Как это работает

### Процесс загрузки (Upsert)

```
Текст документа
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Chunker │────►│ Embedder │────►│ ChromaDB │
│ (разбивка│ │ (векторы │ │ (хранение│
│ на части)│ │ 768-dim) │ │ на диске)│
└──────────┘ └──────────┘ └──────────┘
```

1. Текст нормализуется и разбивается на чанки (~2000 символов)
2. Каждый чанк превращается в вектор из 768 чисел
3. Вектор + метаданные сохраняются в ChromaDB
4. При повторном upsert с тем же `doc_id` — старые чанки заменяются

### Процесс поиска (Search)

```
"поисковый запрос"
┌──────────┐ ┌──────────┐ Результаты
│ Embedder │────►│ ChromaDB │────► (top-N по
│ (вектор │ │ (cosine │ similarity)
│ запроса) │ │ поиск) │
└──────────┘ └──────────┘
```

1. Запрос превращается в вектор
2. ChromaDB находит ближайшие векторы (cosine similarity)
3. Фильтрация по `min_similarity`, `doc_id`, `group`
4. Пагинация и возврат результатов

### Chunking (разбивка текста)

| Шаг | Описание |
|-----|----------|
| **Нормализация** | Убирает лишние пробелы и переносы |
| **Структурная разбивка** | По заголовкам (`#`), абзацам (`\n\n`), предложениям (`.!?`) |
| **Сборка чанков** | Накапливает блоки до `chunk_size` символов (по умолчанию 2000) |
| **Overlap 15%** | Конец предыдущего чанка дублируется в начале следующего |
| **Word-safe** | Никогда не рвёт слово пополам |

## API

**Base URL:** `https://ai-sekretar24.ru/vector-search`
**Swagger UI:** [/vector-search/docs](https://ai-sekretar24.ru/vector-search/docs)
**Auth:** заголовок `Authorization: Bearer <AUTH_KEY>` (кроме `/health`)

### Загрузка данных

| Метод | Путь | Описание |
|-------|------|----------|
| `POST` | `/upsert` | Загрузить текст (авто-chunking + embedding) |

**Тело запроса:**
```json
{
"text": "Текст документа...",
"doc_id": "catalog-v2",
"group": "products",
"chunk_size": 2000
}
```

- `doc_id` (опционально) — при повторном upsert с тем же ID старые чанки заменяются
- `group` (опционально) — группировка для фильтрации при поиске
- `chunk_size` (опционально) — размер чанка в символах (по умолчанию 2000)

**Ответ:** `{"ids": ["uuid1", "uuid2", ...]}`

### Поиск

| Метод | Путь | Описание |
|-------|------|----------|
| `POST` | `/search` | Семантический поиск по смыслу |
| `POST` | `/compare` | Сравнить текст с конкретной записью |

**Тело `/search`:**
```json
{
"text": "поисковый запрос",
"doc_id": "optional",
"group": "optional",
"min_similarity": 0.5,
"limit": 10,
"page": 1
}
```

**Ответ:**
```json
{
"items": [
{
"id": "uuid",
"text": "найденный чанк...",
"doc_id": "catalog-v2",
"group": "products",
"chunk_index": 0,
"similarity": 0.87
}
],
"total": 5,
"page": 1,
"limit": 10
}
```

**Тело `/compare`:**
```json
{
"text": "текст для сравнения",
"record_id": "uuid конкретной записи"
}
```

**Ответ:** `{"similarity": 0.87}`

### Получение данных

| Метод | Путь | Описание |
|-------|------|----------|
| `GET` | `/count` | Количество записей (query params: `text?`, `doc_id?`, `group?`, `min_similarity?`) |
| `GET` | `/ids` | Список ID записей (query params: `doc_id?`, `group?`) |
| `GET` | `/records` | Пагинированный список (query params: `doc_id?`, `group?`, `limit?`, `page?`) |

### Удаление

| Метод | Путь | Описание |
|-------|------|----------|
| `DELETE` | `/record/{id}` | Удалить одну запись |
| `DELETE` | `/document/{doc_id}` | Удалить все чанки документа |
| `DELETE` | `/group/{group}` | Удалить все записи группы |
| `DELETE` | `/clear` | Очистить всё |

### Здоровье

| Метод | Путь | Auth | Описание |
|-------|------|------|----------|
| `GET` | `/health` | Нет | `{"status": "ok", "model": "paraphrase-multilingual-mpnet-base-v2"}` |

## Деплой

**Сервер:** `155.212.231.7` (тот же VPS что AI Secretary)
**Порт:** 8003 (проксируется nginx как `/vector-search/`)
**Systemd:** `vector-search.service`
**Данные:** `/opt/vector-search/data/chroma/`
**Модель:** `/opt/vector-search/.cache/huggingface/` (~420MB)

### Управление сервисом

```bash
systemctl status vector-search # Статус
systemctl restart vector-search # Перезапуск
journalctl -u vector-search -f # Логи
```

### Структура на сервере

```
/opt/vector-search/
├── app/ # Исходный код
│ ├── main.py # FastAPI + роуты
│ ├── auth.py # Bearer token
│ ├── chunker.py # Разбивка текста
│ ├── embedder.py # sentence-transformers
│ ├── storage.py # ChromaDB обёртка
│ └── config.py # Настройки (.env)
├── tests/ # Тесты (pytest)
├── data/chroma/ # Данные ChromaDB
├── .cache/huggingface/ # Кеш модели
├── venv/ # Python виртуальное окружение
└── .env # Конфигурация (AUTH_KEY)
```

## Стек

| Компонент | Технология |
|-----------|-----------|
| **Язык** | Python 3.12 |
| **Фреймворк** | FastAPI + Uvicorn |
| **Embeddings** | sentence-transformers (paraphrase-multilingual-mpnet-base-v2, 768d) |
| **Векторная БД** | ChromaDB 0.6.x (persistent, cosine similarity) |
| **Конфигурация** | pydantic-settings + .env |
| **Потребление RAM** | ~1.1GB (модель + ChromaDB) |

## Примеры использования

### Из curl

```bash
AUTH="Authorization: Bearer YOUR_KEY"
URL="https://ai-sekretar24.ru/vector-search"

# Загрузить документ
curl -X POST $URL/upsert \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"text": "Текст документа...", "doc_id": "doc-1", "group": "knowledge"}'

# Поиск по смыслу
curl -X POST $URL/search \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"text": "запрос", "min_similarity": 0.4}'

# Количество записей
curl "$URL/count" -H "$AUTH"

# Удалить документ
curl -X DELETE "$URL/document/doc-1" -H "$AUTH"
```

### Интеграция с AI Secretary (RAG)

```python
import httpx

VECTOR_URL = "http://localhost:8003"
AUTH = {"Authorization": "Bearer YOUR_KEY"}

# 1. Индексация wiki-страниц
for page in wiki_pages:
httpx.post(f"{VECTOR_URL}/upsert", headers=AUTH, json={
"text": page.content,
"doc_id": page.filename,
"group": "wiki",
})

# 2. Поиск контекста для вопроса пользователя
results = httpx.post(f"{VECTOR_URL}/search", headers=AUTH, json={
"text": user_question,
"group": "wiki",
"min_similarity": 0.4,
"limit": 5,
}).json()

# 3. Подставить в промпт LLM
context = "\n\n".join(r["text"] for r in results["items"])
prompt = f"Контекст:\n{context}\n\nВопрос: {user_question}"
```

---

**См. также:** [[Wiki-RAG]], [[Cloud-LLM-Providers]], [[Architecture]]
1 change: 1 addition & 0 deletions wiki-pages/_Sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
### Интеграции
* [[Cloud-LLM-Providers]]
* [[Claude-Code]]
* [[Vector-Search]]
* [[VLESS-Proxy]]

### Безопасность
Expand Down
Loading