Конспект 3: Qdrant в N8N

Pavel 09.12.2025 11:46 55 просмотров

Оглавление

  1. Введение в Qdrant
  2. Архитектура Qdrant
  3. Концепции и термины
  4. Подключение Qdrant к N8N
  5. Узел Qdrant в N8N
  6. Операции с коллекциями
  7. Работа с данными (Points)
  8. Поиск (Query)
  9. Фильтрация и метаданные
  10. Оптимизация и индексирование
  11. Практические примеры N8N workflows
  12. Развертывание и конфигурация
  13. Лучшие практики

Введение в Qdrant

Что такое Qdrant?

Определение: Qdrant (от англ. Quadrant) — это высокопроизводительная, открытая векторная база данных, оптимизированная для быстрого поиска семантически похожих данных в многомерном пространстве.

Основные назначения: - Хранение векторных представлений (эмбеддингов) - Поиск по сходству на основе косинусного расстояния или других метрик - Фильтрация результатов по метаданным (payload) - Рекомендации, дедупликация, анализ данных

Ключевые преимущества Qdrant

  • Высокая производительность — быстрый поиск миллионов векторов
  • Гибкая фильтрация — встроенная поддержка комплексных условий
  • Масштабируемость — работает с неограниченным количеством данных
  • Открытый исходный код — можно развернуть локально
  • Облачный вариант — управляемое решение Qdrant Cloud
  • Встроенная интеграция в N8N — официальный узел для автоматизации

Сравнение Qdrant с альтернативами

Характеристика Qdrant Pinecone Milvus ChromaDB Weaviate
Тип Open-source + Cloud Облачный сервис Open-source Open-source Open-source + Cloud
Локальное развертывание ✅ Да ❌ Нет ✅ Да ✅ Да ✅ Да
Фильтрация ✅ Мощная ✅ Есть ✅ Есть ✅ Базовая ✅ Есть
Производительность ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
Масштабируемость ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐
Интеграция с N8N ✅ Встроена ⚠️ Частично ⚠️ HTTP ⚠️ HTTP ✅ Встроена
Бесплатный вариант ✅ Да ✅ Есть ✅ Да ✅ Да ✅ Да

Архитектура Qdrant

Иерархия структур

Qdrant Instance (Инстанс)
    
    ├─ Collection 1 (Коллекция)
       ├─ Point 1 (Точка)
          ├─ Vector (Вектор) [0.23, -0.15, 0.87, ...]
          └─ Payload (Метаданные) {name, date, category...}
       ├─ Point 2
       └─ Point N
    
    ├─ Collection 2
       └─ [Points...]
    
    └─ Collection N
        └─ [Points...]

Основные компоненты

1. Collection (Коллекция)

Определение: Контейнер для хранения векторов и связанных с ними метаданных. Похожа на таблицу в обычной БД.

Параметры при создании: - Vector size — размерность вектора (384, 768, 1536 и т.д.) - Distance metric — метрика расстояния (COSINE, EUCLID, MANHATTAN, DOT_PRODUCT) - Vectors config — конфигурация для одного или нескольких векторов

Пример: Коллекция "documents" с размером вектора 1536 токенов для хранения текстовых эмбеддингов

2. Point (Точка)

Определение: Отдельный элемент в коллекции, состоящий из ID, вектора и опциональных метаданных.

Структура:

{
  "id": "12345",
  "vector": [0.23, -0.15, 0.87, ..., 0.42],
  "payload": {
    "title": "N8N - платформа автоматизации",
    "author": "Иван",
    "date": "2025-11-26",
    "category": "AI",
    "language": "ru",
    "embedding_model": "text-embedding-3-small"
  }
}

3. Vector (Вектор)

Определение: Массив чисел фиксированной длины, представляющий эмбеддинг данных.

Типы: - Dense vector — полный вектор со всеми значениями - Sparse vector — вектор с только ненулевыми значениями (экономит память)

Метрики расстояния:

Метрика Формула Применение Диапазон
COSINE 1 - (A·B)/(‖A‖·‖B‖) Текст, общий случай 0-2
EUCLID √(Σ(ai - bi)²) Геометрические данные 0-∞
MANHATTAN Σ\|ai - bi\| Быстрый поиск, сеть 0-∞
DOT_PRODUCT A·B Нормализованные векторы -∞-∞

Рекомендация: Для текста используйте COSINE, это стандарт в NLP

4. Payload (Полезная нагрузка / Метаданные)

Определение: Дополнительные данные, привязанные к каждому вектору, используемые для фильтрации, поиска и контекста.

Типы данных в Payload:

Тип Описание Пример
Keyword Строки, категории "category": "AI"
Integer Целые числа "priority": 5
Float Дробные числа "relevance": 0.87
Boolean Логические значения "in_stock": true
Geo Географические координаты "location": {"lat": 52.52, "lon": 13.40}
DateTime Дата и время "created": "2025-11-26T15:30:00"
Text Полнотекстовый поиск "content": "N8N помогает автоматизировать..."
UUID Уникальные идентификаторы "doc_id": "550e8400-e29b-41d4-a716-446655440000"
Array Массивы значений "tags": ["automation", "AI", "n8n"]

Хранение данных

Структура диска:

Qdrant Storage
├─ collection_name/
   ├─ vectors.dat (сами векторы)
   ├─ vectors.idx (индекс для быстрого поиска)
   ├─ payload/ (метаданные)
   └─ config.json (параметры коллекции)
└─ [другие коллекции...]

Концепции и термины

HNSW (Hierarchical Navigable Small World Graph)

Определение: Алгоритм индексирования для приблизительного векторного поиска, использует иерархическую структуру графа.

Как работает: 1. Векторы организуются в многоуровневый граф 2. Поиск начинается с верхних уровней 3. Постепенно спускается к более детальным уровням 4. На каждом уровне выбираются ближайшие соседи

Преимущества: - Быстрый поиск даже с миллионами векторов - Логарифмическая сложность O(log n) - Балансирование между скоростью и точностью

Параметры HNSW:

{
  "m": 16,              // Количество соединений на каждом уровне
  "ef_construct": 200,  // Качество построения индекса
  "ef": 150             // Глубина поиска при запросе
}

Определение: Поиск приблизительно ближайших соседей (в отличие от точного поиска).

Преимущества: - Скорость: в 1000+ раз быстрее полного перебора - Приемлемая точность для большинства задач

Точность vs Скорость:

ef параметр увеличиваем → точность ↑, скорость ↓
ef параметр уменьшаем → точность ↓, скорость ↑

Фильтрация с условиями

Определение: Ограничение поиска по значениям в payload перед началом векторного поиска.

Логические операции: - must — ВСЕ условия ДОЛЖНЫ быть истинны (AND) - should — ХОТя бы ОДНО условие должно быть истинно (OR) - must_not — ЭТИ условия НЕ ДОЛЖНЫ быть истинны (NOT)

Payload Indexing

Определение: Создание индекса по полям payload для ускорения фильтрованного поиска.

Когда создавать индекс: - Часто фильтруете по этому полю - Поле содержит много уникальных значений - Нужна быстрая фильтрация

Когда это замедлит: - Редко фильтруете по полю - Поле имеет мало уникальных значений - Нужно экономить память


Подключение Qdrant к N8N

Способ 1: Qdrant Cloud (Облачный вариант)

Шаг 1: Создание аккаунта Qdrant Cloud

  1. Перейти на cloud.qdrant.io
  2. Зарегистрироваться через GitHub, Google или email
  3. Создать новый проект (Cluster)
  4. Выбрать регион и тариф

Шаг 2: Получение учетных данных

  1. В Dashboard выбрать кластер
  2. Нажать "Cluster Details"
  3. Скопировать Endpoint (URL):
  4. Формат: https://xxxxxx-your-cluster.eu-west-1.qdrant.cloud:6333
  5. Перейти на вкладку API Keys
  6. Скопировать API Key

Шаг 3: Подключение в N8N

  1. Открыть N8N → Create New Workflow
  2. Добавить узел Qdrant
  3. Кликнуть на "Create New Credential"
  4. Выбрать QdrantApi
  5. Заполнить поля:
  6. Qdrant URL: https://xxxxxx-your-cluster.eu-west-1.qdrant.cloud:6333
  7. API Key: sk-xxxxxxxxxxxxx
  8. Сохранить

Проверка подключения: - Если подключение успешно, в узле Qdrant появятся доступные коллекции

Способ 2: Локальный Qdrant (Docker)

Запуск контейнера

docker run -it --rm \
  -p 6333:6333 \
  -v qdrant_storage:/qdrant/storage \
  qdrant/qdrant

Параметры: - -p 6333:6333 — порт для API - -v qdrant_storage:/qdrant/storage — сохранение данных - Доступ: http://localhost:6333

С API Key (для безопасности)

docker run -it --rm \
  -p 6333:6333 \
  -v qdrant_storage:/qdrant/storage \
  -e QDRANT_API_KEY=test_key_12345 \
  qdrant/qdrant

Подключение в N8N

  1. Добавить узел Qdrant
  2. Создать новый credential
  3. Заполнить:
  4. Qdrant URL: http://localhost:6333 или http://qdrant:6333 (если в Docker Compose)
  5. API Key: test_key_12345 (если установлен)
  6. Сохранить

Способ 3: N8N Self-hosted AI Starter Kit

Docker Compose с предустановкой:

version: '3.8'

services:
  n8n:
    image: n8nio/n8n
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=password123
    networks:
      - demo

  qdrant:
    image: qdrant/qdrant
    hostname: qdrant
    ports:
      - "6333:6333"
    environment:
      - QDRANT_API_KEY=test
    volumes:
      - qdrant_storage:/qdrant/storage
    networks:
      - demo

volumes:
  qdrant_storage:

networks:
  demo:
    driver: bridge

Запуск:

docker-compose up -d

Подключение в N8N: - Qdrant URL: http://qdrant:6333 - API Key: test


Узел Qdrant в N8N

Структура узла Qdrant

Qdrant Node
├─ Credentials (учетные данные)
├─ Resource (тип операции)
├─ Operation (конкретная операция)
└─ Parameters (параметры)

Доступные ресурсы и операции

1. Collections (Коллекции)

Операция Описание
List Collections Получить список всех коллекций
Create Collection Создать новую коллекцию
Update Collection Изменить параметры коллекции
Get Collection Получить информацию о коллекции
Check If Collection Exists Проверить существование коллекции
Delete Collection Удалить коллекцию

2. Points (Точки/Данные)

Операция Описание
Upsert Points Вставить или обновить точки
Retrieve Point Получить одну точку по ID
Retrieve Points Получить несколько точек по ID
Delete Points Удалить точки по ID или фильтру
Count Points Подсчитать точки по условиям
Scroll Points Получить точки постранично
Batch Update Points Пакетное обновление точек

3. Vectors (Векторы)

Операция Описание
Update Vectors Обновить векторы для точек
Delete Vectors Удалить векторы из точек

4. Payload (Метаданные)

Операция Описание
Set Payload Установить/обновить поля payload
Overwrite Payload Полностью заменить payload
Delete Payload Удалить поля из payload
Clear Payload Удалить весь payload
Create Payload Index Создать индекс по полю
Delete Payload Index Удалить индекс
Payload Facets Получить статистику по полю

5. Query (Поиск)

Операция Описание
Query Points Поиск похожих точек
Query Batch Points Пакетный поиск
Query Points Groups Поиск с группировкой результатов

6. Matrix (Матрицы расстояний)

Операция Описание
Matrix Pairs Матрица попарных расстояний
Matrix Offsets Матрица расстояний с смещениями

Операции с коллекциями

Создание коллекции

Параметры:

{
  "collectionName": "documents",
  "vectorSize": 1536,
  "distanceMetric": "Cosine",
  "onVectorSizeMismatch": "error"
}

Описание параметров: - collectionName — уникальное имя коллекции - vectorSize — размер вектора (должен совпадать с эмбеддером) - distanceMetric — метрика расстояния (Cosine, Euclid, Manhattan, DotProduct) - onVectorSizeMismatch — что делать при несовпадении размера (error/warning)

Пример на Python (для понимания):

from qdrant_client import QdrantClient, models

client = QdrantClient(url="http://localhost:6333", api_key="test")

client.create_collection(
    collection_name="documents",
    vectors_config=models.VectorParams(
        size=1536,
        distance=models.Distance.COSINE
    )
)

Получение информации о коллекции

Возвращает:

{
  "name": "documents",
  "vectors": 1000,
  "status": "green",
  "config": {
    "params": {
      "vectors": {
        "size": 1536,
        "distance": "Cosine"
      }
    }
  }
}

Обновление параметров коллекции

Что можно менять: - Параметры оптимизации (ef, m для HNSW) - Timeout для операций

Пример:

{
  "collectionName": "documents",
  "hnsw": {
    "ef": 200,
    "m": 16
  }
}

Удаление коллекции

Внимание: операция необратима!

Параметры:

{
  "collectionName": "documents"
}

Работа с данными (Points)

Вставка и обновление точек (Upsert)

UPSERT = UPDATE + INSERT (обновить, если существует; вставить, если нет)

Структура данных:

{
  "collectionName": "documents",
  "points": [
    {
      "id": 1,
      "vector": [0.23, -0.15, 0.87, ..., 0.42],
      "payload": {
        "title": "N8N - платформа автоматизации",
        "author": "Иван",
        "date": "2025-11-26",
        "category": "AI",
        "embedding_model": "text-embedding-3-small"
      }
    },
    {
      "id": 2,
      "vector": [0.45, 0.12, -0.34, ..., 0.21],
      "payload": {
        "title": "Qdrant для N8N",
        "author": "Мария",
        "date": "2025-11-25",
        "category": "Database"
      }
    }
  ]
}

Типы ID: - Integer — быстрее, занимает меньше памяти - UUID/String — более гибко, если нужны текстовые ID

Получение точки по ID

Один запрос — одна точка:

{
  "collectionName": "documents",
  "pointId": 1
}

Возвращает:

{
  "id": 1,
  "vector": [0.23, -0.15, 0.87, ..., 0.42],
  "payload": {
    "title": "N8N - платформа автоматизации",
    ...
  }
}

Получение нескольких точек

Параметры:

{
  "collectionName": "documents",
  "pointIds": [1, 2, 3, 5]
}

Результат:

{
  "points": [
    { "id": 1, "vector": [...], "payload": {...} },
    { "id": 2, "vector": [...], "payload": {...} },
    { "id": 3, "vector": [...], "payload": {...} },
    { "id": 5, "vector": [...], "payload": {...} }
  ]
}

Удаление точек

По ID:

{
  "collectionName": "documents",
  "pointIds": [1, 2, 3]
}

По фильтру (удалить всё, что соответствует условию):

{
  "collectionName": "documents",
  "filter": {
    "must": [
      {
        "key": "category",
        "match": { "value": "old_content" }
      }
    ]
  }
}

Подсчет точек

Получить количество всех точек:

{
  "collectionName": "documents"
}

С условием (только активные точки):

{
  "collectionName": "documents",
  "filter": {
    "must": [
      {
        "key": "is_active",
        "match": { "value": true }
      }
    ]
  }
}

Пакетное обновление

Одновременное обновление векторов и payload:

{
  "collectionName": "documents",
  "points": [
    {
      "id": 1,
      "vector": [0.23, -0.15, 0.87, ..., 0.42],
      "payload": {
        "status": "updated",
        "updated_at": "2025-11-26"
      }
    }
  ]
}

Поиск (Query)

Поиск похожих точек

Базовый поиск:

{
  "collectionName": "documents",
  "vector": [0.23, -0.15, 0.87, ..., 0.42],
  "limit": 10,
  "scoreThreshold": 0.7
}

Параметры: - vector — вектор запроса (должен быть того же размера, что и коллекция) - limit — количество результатов - scoreThreshold — минимальный порог сходства (0.0-1.0 для COSINE) - withPayload — включить ли метаданные (по умолчанию true) - withVector — включить ли вектор в результат (по умолчанию false, для экономии)

Результат:

{
  "result": [
    {
      "id": 5,
      "score": 0.92,
      "payload": {
        "title": "N8N - платформа автоматизации",
        "category": "AI"
      }
    },
    {
      "id": 3,
      "score": 0.85,
      "payload": {
        "title": "Qdrant для N8N",
        "category": "Database"
      }
    }
  ]
}

Поиск по имени вектора

Если коллекция содержит несколько векторов:

{
  "collectionName": "documents",
  "vector": {
    "name": "description_vector",
    "vector": [0.23, -0.15, 0.87, ..., 0.42]
  },
  "limit": 5
}

Поиск с использованием других точек

Найти похожие на существующую точку:

{
  "collectionName": "documents",
  "pointId": 1,
  "limit": 5
}

Пакетный поиск

Несколько запросов одновременно:

{
  "collectionName": "documents",
  "searches": [
    {
      "vector": [0.23, -0.15, 0.87, ..., 0.42],
      "limit": 5
    },
    {
      "vector": [0.45, 0.12, -0.34, ..., 0.21],
      "limit": 3
    }
  ]
}

Возвращает:

{
  "results": [
    {
      "result": [
        { "id": 5, "score": 0.92, "payload": {...} }
      ]
    },
    {
      "result": [
        { "id": 3, "score": 0.88, "payload": {...} }
      ]
    }
  ]
}

Поиск с группировкой

Группировка результатов по полю payload:

{
  "collectionName": "documents",
  "vector": [0.23, -0.15, 0.87, ..., 0.42],
  "groupBy": "category",
  "groupSize": 2,
  "limit": 10
}

Параметры: - groupBy — поле для группировки - groupSize — максимум результатов в одной группе - limit — общий лимит результатов

Результат:

{
  "groups": [
    {
      "id": "AI",
      "hits": [
        { "id": 5, "score": 0.92, "payload": {...} },
        { "id": 8, "score": 0.87, "payload": {...} }
      ]
    },
    {
      "id": "Database",
      "hits": [
        { "id": 3, "score": 0.88, "payload": {...} }
      ]
    }
  ]
}

Фильтрация и метаданные

Структура фильтра

{
  "must": [
    // Все условия должны быть истинны (AND)
  ],
  "should": [
    // Хотя бы одно условие должно быть истинно (OR)
  ],
  "must_not": [
    // Эти условия НЕ должны быть истинны (NOT)
  ]
}

Типы условий

Точное совпадение (Match)

{
  "key": "category",
  "match": {
    "value": "AI"
  }
}

Диапазон значений (Range)

{
  "key": "price",
  "range": {
    "gte": 100,
    "lte": 1000
  }
}

Параметры: - gt — больше (>) - gte — больше или равно (≥) - lt — меньше (<) - lte — меньше или равно (≤)

Множественное соответствие

{
  "key": "tags",
  "match": {
    "any": ["automation", "AI", "python"]
  }
}

Географическая фильтрация

{
  "key": "location",
  "geo_radius": {
    "center": {
      "lat": 52.52,
      "lon": 13.40
    },
    "radius": 2000  // в метрах
  }
}

Полнотекстовый поиск

{
  "key": "content",
  "text": {
    "query": "N8N автоматизация"
  }
}

Пример комплексной фильтрации

"Найти документы по AI, опубликованные в 2025, от авторов Иван или Мария, и исключить архивные":

{
  "must": [
    {
      "key": "category",
      "match": { "value": "AI" }
    },
    {
      "key": "date",
      "range": {
        "gte": "2025-01-01",
        "lte": "2025-12-31"
      }
    }
  ],
  "should": [
    { "key": "author", "match": { "value": "Иван" } },
    { "key": "author", "match": { "value": "Мария" } }
  ],
  "must_not": [
    { "key": "status", "match": { "value": "archived" } }
  ]
}

Поиск с фильтрацией

В узле Query Points:

{
  "collectionName": "documents",
  "vector": [0.23, -0.15, 0.87, ..., 0.42],
  "filter": {
    "must": [
      { "key": "category", "match": { "value": "AI" } }
    ]
  },
  "limit": 10
}

Процесс: 1. Применить фильтр (отобрать только AI документы) 2. Вычислить расстояние до запроса 3. Вернуть top-10 по сходству

Управление метаданными (Payload)

Set Payload (установить/добавить поля)

{
  "collectionName": "documents",
  "pointIds": [1, 2, 3],
  "payload": {
    "status": "processed",
    "last_updated": "2025-11-26"
  }
}

Результат: добавляет новые поля, оставляет старые

Overwrite Payload (полностью заменить)

{
  "collectionName": "documents",
  "pointIds": [1, 2, 3],
  "payload": {
    "status": "archived",
    "reason": "old content"
  }
}

Результат: удаляет все старые поля, оставляет только новые

Delete Payload (удалить поля)

{
  "collectionName": "documents",
  "pointIds": [1, 2, 3],
  "keys": ["status", "last_updated"]
}

Результат: удаляет только указанные поля

Создание индекса по payload

Для ускорения фильтрации:

{
  "collectionName": "documents",
  "fieldName": "category",
  "fieldSchema": "keyword"
}

Типы индексов:

Схема Тип данных Операции
keyword String Match, Any
integer Int Match, Range
float Float Match, Range
bool Boolean Match
geo Geo Radius, BoundingBox
datetime DateTime Range
text String FullText
uuid UUID Match

После создания индекса фильтрация работает в 10-100 раз быстрее!

Узнать, сколько документов в каждой категории:

{
  "collectionName": "documents",
  "field": "category"
}

Результат:

{
  "facets": [
    { "value": "AI", "count": 150 },
    { "value": "Database", "count": 87 },
    { "value": "Automation", "count": 203 }
  ]
}

Применение: создание фильтров в UI, статистика


Оптимизация и индексирование

HNSW Параметры

Где настраивать: при создании коллекции

{
  "hnsw": {
    "m": 16,              // Quantity connections per node (8-64)
    "ef_construct": 200,  // Indexing quality (128-2048)
    "ef": 150,            // Search depth (128-4096)
    "full_scan_threshold": 10000,  // Когда перейти на полный поиск
    "max_indexing_threads": 4      // Потоки для индексирования
  }
}

Рекомендации:

Сценарий m ef_construct ef
Быстрый прототип 8 128 100
Сбалансированный 16 200 150
Высокая точность 24 500 250
Огромный объем (млн+) 16 200 150

Оптимизация памяти

Компрессия векторов:

{
  "quantization": {
    "scalar": {
      "type": "int8",
      "quantile": 0.99,
      "always_ram": false
    }
  }
}

Результат: экономия памяти в 4 раза (32-бит → 8-бит)

Стратегия индексирования

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

// Создать индексы
- category (keyword)
- date (datetime)
- author (keyword)
- is_active (bool)

2. Не индексировать: - Редко используемые поля - Поля с очень большим количеством уникальных значений - Очень длинные строки

3. Профилирование: - Мониторить время поиска - Добавлять индексы на медленные фильтры - Удалять неиспользуемые индексы

Масштабирование

Когда переходить на большие объемы:

Размер Рекомендация
< 1M точек Локальный Qdrant достаточно
1M - 100M Один сервер Qdrant, возможна репликация
100M - 1B Qdrant Cloud с высоким тарифом, или собственный кластер
1B+ Мультиузловой кластер, сегментирование

Практические примеры N8N workflows

Пример 1: RAG Workflow (базовый)

Сценарий: Обработка входящего вопроса, поиск релевантных документов в Qdrant, генерация ответа с GPT

[Webhook trigger]
    
[HTTP Request → OpenAI Embedding]
    
[Qdrant Query Points]
    
[Function → Формирование контекста]
    
[HTTP Request → OpenAI Chat]
    
[HTTP Request → Отправка ответа]

N8N Nodes:

1. Webhook Trigger:

Method: POST
Authentication: None

2. OpenAI Embedding:

Используем: Function node или HTTP Request
Input: $json.body.question
Output: vector array

3. Qdrant Query Points:

Resource: Query
Operation: Query Points

collectionName: "kb_documents"
vector: $json.embedding
limit: 5
scoreThreshold: 0.7

filter: {
  "must": [
    { "key": "status", "match": { "value": "active" } }
  ]
}

4. Function Node (JavaScript):

// Формирование контекста из результатов
const items = $input.all()[0].json.result;
const context = items
  .map(item => `${item.payload.title}\n${item.payload.content}`)
  .join('\n\n');

return { context };

5. OpenAI Chat:

System prompt: "Ты помощник. Ответь на вопрос используя контекст"
Context: $json.context
Question: $json.body.question

Пример 2: Document Indexing Workflow

Сценарий: Загрузка новых документов, их чанкирование, генерация эмбеддингов, добавление в Qdrant

[Google Drive New File Trigger]
    
[PDF Parser]
    
[Function → Чанкирование текста]
    
[HTTP Request → OpenAI Embedding]
    
[Qdrant Upsert Points]
    
[Notification → Email]

Nodes:

1. Trigger: Google Drive New File

2. PDF Parser:

Input: file from trigger
Output: raw text

3. Function Node (Text Chunking):

const text = $input.first().json.text;
const chunkSize = 1024; // токены
const chunkOverlap = 100;

const chunks = [];
let start = 0;

while (start < text.length) {
  let end = start + chunkSize;
  if (end < text.length && text[end] !== ' ') {
    end = text.lastIndexOf(' ', end);
  }
  chunks.push(text.substring(start, end));
  start = end - chunkOverlap;
}

return chunks.map((chunk, i) => ({
  "chunk_id": i,
  "content": chunk,
  "source": $input.first().json.fileName
}));

4. HTTP Request (Embedding):

Method: POST
URL: https://api.openai.com/v1/embeddings
Headers: Authorization: Bearer sk-...

Body: {
  "input": $json.content,
  "model": "text-embedding-3-small"
}

5. Qdrant Upsert Points:

Resource: Points
Operation: Upsert Points

collectionName: "documents"

points: [
  {
    "id": $json.chunk_id,
    "vector": $input.previous().json.data[0].embedding,
    "payload": {
      "content": $json.content,
      "source": $json.source,
      "indexed_at": new Date().toISOString(),
      "document_id": $input.first().json.fileId
    }
  }
]

Пример 3: Фильтрованный поиск с метаданными

Сценарий: Поиск документов по категориям и датам

[Webhook trigger с параметрами]
    
[Qdrant Query Points + Filter]
    
[Presentation форматирования]
    
[HTTP Response]

Qdrant Query Node:

collectionName: "documents"
vector: $json.embedding

filter: {
  "must": [
    {
      "key": "category",
      "match": { "value": $json.category }
    },
    {
      "key": "date",
      "range": {
        "gte": $json.startDate,
        "lte": $json.endDate
      }
    }
  ]
}

limit: 10
scoreThreshold: 0.75

Пример 4: Мониторинг и обновление метаданных

Сценарий: Проверка актуальности документов каждый день, обновление метаданных

[Schedule trigger (ежедневно)]
    
[Qdrant Scroll Points]
    
[Function → Проверка актуальности]
    
[Qdrant Set Payload (обновить метаданные)]
    
[Logging]

Nodes:

1. Schedule: Cron 0 0 * * * (каждый день в полночь)

2. Qdrant Scroll Points:

collectionName: "documents"
limit: 100

3. Function Node:

const today = new Date();
const oneMonthAgo = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000);

const oldItems = $input.all()
  .filter(item => {
    const docDate = new Date(item.json.payload.indexed_at);
    return docDate < oneMonthAgo;
  });

return oldItems.map(item => ({
  pointId: item.json.id,
  status: "stale",
  needs_review: true
}));

4. Qdrant Set Payload:

collectionName: "documents"

pointIds: $json.pointIds

payload: {
  "status": "stale",
  "needs_review": true,
  "last_checked": new Date().toISOString()
}

Пример 5: Рекомендации на основе Qdrant

Сценарий: Если пользователь просмотрел документ X, показать похожие

[User view event webhook]
    
[Qdrant Retrieve Point (получить вектор просмотренного документа)]
    
[Qdrant Query Points (найти похожие)]
    
[Filter excluding similar (исключить само себя)]
    
[HTTP Response → Recommendations]

Nodes:

1. Webhook:

{
  "user_id": "123",
  "document_id": 5
}

2. Qdrant Retrieve Point:

collectionName: "documents"
pointId: $json.document_id

3. Qdrant Query Points:

collectionName: "documents"
vector: $input.previous().json.vector

filter: {
  "must_not": [
    { "key": "id", "match": { "value": $json.document_id } }
  ]
}

limit: 5

Развертывание и конфигурация

Локальное развертывание (Docker)

Базовый docker-compose.yml:

version: '3.8'

services:
  qdrant:
    image: qdrant/qdrant:latest
    container_name: qdrant
    ports:
      - "6333:6333"
    volumes:
      - ./qdrant_storage:/qdrant/storage
    environment:
      QDRANT_HTTP_API_KEY: "test_api_key_12345"
    restart: unless-stopped

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=password123
      - N8N_HOST=localhost
      - N8N_PORT=5678
    volumes:
      - ./n8n_data:/home/node/.n8n
    depends_on:
      - qdrant
    restart: unless-stopped

volumes:
  qdrant_storage:
  n8n_data:

Запуск:

docker-compose up -d

# Проверка
docker ps
docker logs qdrant
docker logs n8n

Доступ: - N8N: http://localhost:5678 (admin/password123) - Qdrant API: http://localhost:6333

Qdrant Cloud (Облачное развертывание)

Процесс: 1. Регистрация на cloud.qdrant.io 2. Создание кластера 3. Получение endpoint и API key 4. Подключение в N8N

Преимущества облака: - Автоматические резервные копии - Масштабируемость - Мониторинг - Поддержка Qdrant

Стоимость: - Free: до 1 млн точек - Professional: от $29/месяц - Enterprise: договорная цена

Мониторинг и логирование

Qdrant Web UI:

http://localhost:6333/dashboard

Доступные статистики: - Количество коллекций - Размер данных - Состояние индексов - Производительность поиска

Логи N8N:

docker logs -f n8n

Логи Qdrant:

docker logs -f qdrant

Лучшие практики

Проектирование коллекции

Правила: 1. Размер вектора должен соответствовать модели эмбеддинга 2. Метрика расстояния: - Текст → COSINE - Изображения → EUCLID или COSINE - Специализированные → попробовать DOT_PRODUCT 3. Payload: только нужные метаданные (экономит память) 4. Индексы: создавать только для часто используемых фильтров

Подготовка данных

  1. Качество эмбеддингов:
  2. Использовать консистентный эмбеддер
  3. Нормализовать входные данные
  4. Проверять размер вектора

  5. Чанкирование:

  6. Размер 256-1024 токена
  7. Overlap 10-20%
  8. Граница по логическим разделам

  9. Метаданные:

  10. Включать источник (для контекста)
  11. Дату и версию
  12. Статус актуальности

Оптимизация производительности

Проблема Решение
Медленный поиск Увеличить ef, создать индексы
Высокое потребление памяти Квантизация, удалить старые данные
Неточные результаты Увеличить чанк overlap, проверить эмбеддер
Медленное индексирование Батчинг, увеличить потоки

Обработка ошибок в N8N

1. Проверка подключения:

Qdrant node → "List Collections"
Если пусто → проверить credentials

2. Размер вектора:

// Проверка перед Upsert
if (embedding.length !== 1536) {
  throw new Error("Vector size mismatch");
}

3. Обработка исключений:

Qdrant Query → Try/Catch → Fallback action

Резервные копии

Qdrant:

# Снятие снимка
curl -X POST http://localhost:6333/collections/documents/snapshots

# Восстановление
curl -X PUT http://localhost:6333/collections/documents/snapshots/restore \
  -F snapshot=@snapshot.tar

Стратегия: - Еженедельные снимки - Хранить в S3 или облаке - Регулярно проверять восстановление

Масштабирование

Когда нужна оптимизация: - 100M+ точек → рассмотреть кластер - 1B+ точек → многоузловая архитектура - 10B+ точек → горизонтальное масштабирование

Стратегии: 1. Сегментирование по категориям 2. Мультиузловой кластер Qdrant 3. Фильтрование на уровне приложения

Безопасность

Обязательно: - Установить API key в production - Использовать HTTPS - Ограничить доступ по IP - Мониторить логи доступа

API Key в N8N:

Не сохранять в коде
Использовать N8N credentials
Ротировать ежемесячно

Шпаргалка: Быстрая справка

Создание и управление

List Collections → Получить все коллекции
Create Collection → Создать новую (указать имя, размер вектора, метрику)
Get Collection → Информация о коллекции
Delete Collection → Удалить (необратимо!)

Добавление данных

Upsert Points  Вставить или обновить точки
Structure: {id, vector, payload}

Поиск

Query Points → Поиск похожих
+ Filter → ограничение по условиям

Работа с метаданными

Set Payload  добавить/обновить поля
Create Payload Index  ускорить фильтрацию
Faceted Search  статистика по полям

Оптимизация

Индексы на часто фильтруемые поля
Квантизация для экономии памяти
Батчинг для массовых операций

Дополнительные ресурсы

Официальная документация

Python Клиент

pip install qdrant-client

Обучающие материалы

  • YouTube: "Qdrant Tutorial"
  • GitHub: qdrant/qdrant-examples
  • Habr: статьи про Qdrant и RAG

Дата создания: November 2025
Версия: 1.0
Язык: Русский
Для кого: Разработчики, автоматизаторы, Data scientists

Комментарии (0)

Для добавления комментария необходимо войти в аккаунт

Войти / Зарегистрироваться