- TTS: xtts-v2 integration with voice cloning support
- Document: docling integration for PDF/DOCX/PPTX processing
- Memory Service: added /facts/upsert, /facts/{key}, /facts endpoints
- Added required dependencies (TTS, docling)
11 KiB
🔍 Як працює НОДА2 - Детальний розбір
Дата: 2026-01-12
Статус: ✅ Повний аналіз роботи НОДА2
🏗️ Архітектура НОДА2
Основні компоненти
┌─────────────────────────────────────────────────────────┐
│ НОДА2 (MacBook M4 Max) │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Router │──────│ Swapper │ │
│ │ (9102) │ │ (8890) │ │
│ └──────┬────────┘ └──────┬──────┘ │
│ │ │ │
│ │ │ │
│ │ ┌────────▼────────┐ │
│ │ │ Ollama │ │
│ │ │ (host:11434) │ │
│ │ └─────────────────┘ │
│ │ │
│ └──────────────┬─────────────────┐ │
│ │ │ │
│ ┌─────▼─────┐ ┌─────▼─────┐ │
│ │ NATS │ │ Gateway │ │
│ │ (4222) │ │ (9300) │ │
│ └────────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
🔄 Як працює Router
Основні функції Router
-
Маршрутизація запитів:
- Отримує запити на порту 9102
- Аналізує запит та визначає провайдера
- Маршрутизує до відповідного сервісу
-
Інтеграція з Swapper:
- Перевіряє доступність Swapper через
/health - Завантажує моделі через
/models/{name}/load - Отримує список моделей через
/models - Проблема: Намагається викликати
/v1/chat/completions(не існує)
- Перевіряє доступність Swapper через
-
Провайдери (17 штук):
- LLM провайдери (9 штук)
- DevTools провайдери (5 штук)
- Інші провайдери (3 штуки)
Конфігурація Router
Змінні середовища:
SWAPPER_URL=http://192.168.1.33:8890 # IP адреса хоста
NATS_URL=nats://nats:4222
STT_URL=http://192.168.1.33:8895
VISION_URL=http://192.168.1.33:11434
OCR_URL=http://192.168.1.33:8896
Проблема: Використовує IP замість Docker service name
Рекомендація: Змінити на http://swapper-service:8890
🔄 Як працює Swapper
Основні функції Swapper
-
Динамічне завантаження моделей:
- Завантажує моделі з Ollama за запитом
- Вивантажує моделі для звільнення пам'яті
- Управляє станом моделей (loaded/unloaded)
-
Single-active режим:
- Тільки одна модель активна одночасно
- Автоматичне вивантаження при завантаженні нової
- Timeout: 30 секунд для swap
-
Інтеграція з Ollama:
- Доступ через
host.docker.internal:11434 - Викликає Ollama API для генерації
- Відстежує стан моделей
- Доступ через
API Endpoints Swapper
Основні:
GET /health- перевірка здоров'яGET /status- статус сервісуGET /models- список моделейGET /models/{name}- інформація про модельPOST /models/{name}/load- завантажити модельPOST /models/{name}/unload- вивантажити модель
Cabinet API:
GET /api/cabinet/swapper/status- статус для кабінетуGET /api/cabinet/swapper/models- моделі для кабінетуGET /api/cabinet/swapper/metrics/summary- метрики
⚠️ Відсутній: /v1/chat/completions (Router намагається викликати)
🔗 Інтеграція Router ↔ Swapper
Поточна реалізація
З коду Router (main.py):
-
Перевірка Swapper:
health_resp = await http_client.get(f"{SWAPPER_URL}/health") -
Завантаження моделі:
load_resp = await http_client.post( f"{SWAPPER_URL}/load", json={"model": model_name} ) -
Генерація (проблема):
# Router намагається викликати: generate_resp = await http_client.post( f"{VISION_URL}/api/generate", # Прямо до Ollama! ... ) -
Отримання моделей:
resp = await http_client.get(f"{SWAPPER_URL}/models")
Проблема інтеграції
Що не працює:
- Router намагається викликати
/v1/chat/completionsна Swapper - Swapper не має такого endpoint
- Router використовує
VISION_URLдля генерації (прямо до Ollama)
Що працює:
- ✅ Health check
- ✅ Завантаження моделей
- ✅ Отримання списку моделей
- ❌ Генерація через Swapper (Router йде напряму до Ollama)
🔄 Потік запиту (поточна реалізація)
Варіант 1: Router → Ollama (прямий)
Клієнт
↓ POST /route
Router (9102)
↓ [визначає модель]
↓ POST /api/generate
Ollama (host:11434)
↓ [генерує]
Router
↓
Клієнт
Проблема: Обходить Swapper, не використовує динамічне завантаження
Варіант 2: Router → Swapper → Ollama (ідеальний)
Клієнт
↓ POST /route
Router (9102)
↓ [визначає модель]
↓ POST /models/{name}/load
Swapper (8890)
↓ [перевіряє модель]
↓ [завантажує якщо потрібно]
Ollama (host:11434)
↓ [генерує]
Swapper
↓
Router
↓
Клієнт
Проблема: Swapper не має /generate або /v1/chat/completions endpoint
📊 Поточний стан
✅ Що працює
-
Router:
- ✅ Запущений, healthy
- ✅ Підключений до NATS
- ✅ Може викликати Swapper для завантаження моделей
- ✅ Може отримувати список моделей з Swapper
-
Swapper:
- ✅ Запущений, healthy
- ✅ Активна модель
gpt-oss-latest - ✅ Доступ до Ollama працює
- ✅ Може завантажувати/вивантажувати моделі
-
Ollama:
- ✅ Працює на хості
- ✅ 9 моделей доступні
- ✅ Модель
gpt-oss:latestзавантажена
⚠️ Що не працює повністю
-
Генерація через Swapper:
- Router намагається викликати
/v1/chat/completions - Swapper не має такого endpoint
- Router йде напряму до Ollama
- Router намагається викликати
-
SWAPPER_URL:
- Використовує IP адресу замість service name
- Може не працювати при зміні IP
-
NATS Unhealthy:
- Може впливати на messaging
🔧 Рекомендації для виправлення
1. Додати endpoint в Swapper
Потрібно додати в Swapper:
@app.post("/v1/chat/completions")
async def chat_completions(request: ChatRequest):
# Завантажити модель якщо потрібно
# Викликати Ollama
# Повернути відповідь
2. Виправити SWAPPER_URL в Router
Змінити:
# Замість:
SWAPPER_URL=http://192.168.1.33:8890
# Використати:
SWAPPER_URL=http://swapper-service:8890
3. Оновити Router для використання Swapper
Змінити генерацію:
# Замість прямого виклику Ollama:
generate_resp = await http_client.post(f"{VISION_URL}/api/generate", ...)
# Викликати Swapper:
generate_resp = await http_client.post(
f"{SWAPPER_URL}/v1/chat/completions",
...
)
📝 Висновок
НОДА2 працює наступним чином:
- ✅ Router - маршрутизує запити, має 17 провайдерів
- ✅ Swapper - управляє моделями, активна модель
gpt-oss-latest - ✅ Ollama - локальний LLM runtime, 9 моделей доступні
- ⚠️ Інтеграція - частково працює, потрібні доопрацювання
Поточна реалізація:
- Router може завантажувати моделі через Swapper
- Router йде напряму до Ollama для генерації
- Swapper не використовується для генерації
Ідеальна реалізація:
- Router → Swapper → Ollama (повний потік)
- Swapper керує всіма LLM операціями
- Динамічне завантаження моделей за потреби
Оновлено: 2026-01-12
Статус: ✅ Аналіз завершено, виявлено проблеми інтеграції