Config policies (16 files): alert_routing, architecture_pressure, backlog, cost_weights, data_governance, incident_escalation, incident_intelligence, network_allowlist, nodes_registry, observability_sources, rbac_tools_matrix, release_gate, risk_attribution, risk_policy, slo_policy, tool_limits, tools_rollout Ops (22 files): Caddyfile, calendar compose, grafana voice dashboard, deployments/incidents logs, runbooks for alerts/audit/backlog/incidents/sofiia/voice, cron jobs, scripts (alert_triage, audit_cleanup, migrate_*, governance, schedule), task_registry, voice alerts/ha/latency/policy Docs (30+ files): HUMANIZED_STEPAN v2.7-v3 changelogs and runbooks, NODA1/NODA2 status and setup, audit index and traces, backlog, incident, supervisor, tools, voice, opencode, release, risk, aistalk, spacebot Made-with: Cursor
519 lines
25 KiB
Markdown
519 lines
25 KiB
Markdown
# NODA1 Full Audit — DAARION.city
|
||
**Дата:** 2026-02-27
|
||
**Сервер:** node1-daarion | 144.76.224.179 | NVIDIA RTX 4000 SFF Ada (20GB VRAM)
|
||
**Аудитор:** Sofiia — Chief AI Architect
|
||
|
||
---
|
||
|
||
## EXECUTIVE SUMMARY
|
||
|
||
| Напрям | Стан | Критичність |
|
||
|--------|------|-------------|
|
||
| Фото E2E (Telegram→Vision) | ✅ Працює, але є shortcut (не через NATS) | MEDIUM |
|
||
| PDF/Документи | ⚠️ render-pdf-worker idle, index-doc DNS fail | HIGH |
|
||
| Router/Profiles | ✅ OK — DeepSeek top-level, 27B crew, smollm2 CPU | LOW |
|
||
| STT/TTS | ✅ CPU-only (Whisper), TTS unloaded | LOW |
|
||
| Swapper | ⚠️ Потрібен — єдина точка Vision/STT/OCR/Document | KEEP |
|
||
| GPU policy | ✅ 27B GPU, smollm2 CPU, policy_ok=1 | OK |
|
||
| NODA1↔NODA2 | ⚠️ K3s cluster (flannel), NATS не з'єднані між нодами | HIGH |
|
||
| CTO Sofiia control plane | ⚠️ control-plane сервіс є, але тільки prompts+policy JWT | MEDIUM |
|
||
|
||
---
|
||
|
||
## 1. INVENTORY — Що реально запущено
|
||
|
||
### Контейнери (48 total, ключові):
|
||
|
||
```
|
||
swapper-service-node1 healthy 8890-8891
|
||
dagi-router-node1 healthy 9102→8000
|
||
dagi-nats-node1 up 4222
|
||
dagi-memory-service-node1 healthy 8000
|
||
dagi-qdrant-node1 healthy 6333
|
||
dagi-gateway-node1 healthy 9300
|
||
parser-pipeline up 8101
|
||
ingest-service up 8100
|
||
render-pdf-worker-node1 up (no port)
|
||
render-pptx-worker-node1 up (no port)
|
||
index-doc-worker-node1 up (no port)
|
||
presentation-renderer-node1 healthy 9212
|
||
rag-service-node1 healthy 9500
|
||
dagi-vision-encoder-node1 healthy 8001
|
||
control-plane up 9200
|
||
dagi-crawl4ai-node1 healthy 11235
|
||
oneok-gotenberg-node1 up 3010
|
||
plant-vision-node1 healthy 8085
|
||
crewai-nats-worker up 9011
|
||
dagi-staging-crewai-service up 9010
|
||
artifact-registry-node1 healthy 9220
|
||
dagi-minio-node1 up 9000-9001
|
||
```
|
||
|
||
### Systemd:
|
||
- `ollama.service` — **active** (GPU, port 11434, qwen3.5:27b-q4_K_M, KEEP_ALIVE=10m)
|
||
- `ollama-cpu.service` — **active** (CPU, port 11435, smollm2:135m)
|
||
- `gpu-ollama-exporter.service` — **active** (port 9400)
|
||
- `ollama-warmup-27b.timer` — **active** (кожні 15хв)
|
||
|
||
---
|
||
|
||
## 2. ROUTER — Профілі, моделі, routing
|
||
|
||
### CURRENT STATE
|
||
|
||
**Env у контейнері dagi-router-node1:**
|
||
```
|
||
ENABLE_CREW_MODEL_ROUTING=1
|
||
CREW_SMALL_MODEL=smollm2:135m
|
||
CREWAI_WORKER_LLM_PROFILE=crew_local_27b
|
||
DEEPSEEK_API_KEY=sk-0db94... (production key)
|
||
NATS_URL=nats://nats:4222
|
||
VISION_ENCODER_URL=http://vision-encoder:8001
|
||
```
|
||
|
||
**Профілі (router-config.yml):**
|
||
| Profile | Provider | Model | URL |
|
||
|---------|----------|-------|-----|
|
||
| `cloud_deepseek` | deepseek | deepseek-chat | api.deepseek.com |
|
||
| `cloud_mistral` | mistral | mistral-large-latest | api.mistral.ai |
|
||
| `crew_local_27b` | ollama | qwen3.5:27b-q4_K_M | 172.17.0.1:11434 (GPU) |
|
||
| `crew_vision_27b` | ollama | qwen3.5:27b-q4_K_M | 172.17.0.1:11434 (GPU) |
|
||
| `crew_local_small` | ollama | smollm2:135m | host.docker.internal:11435 (CPU) |
|
||
| `service_local_cpu` | ollama | smollm2:135m | host.docker.internal:11435 (CPU) |
|
||
| `vision_encoder` | — | — | vision-encoder:8001 (ViT-L-14) |
|
||
| `crewai` | — | — | localhost:9010 |
|
||
|
||
**Агенти з vision моделлю:** greenfood, druid, eonarch, helion → `qwen3-vl:8b` (через swapper)
|
||
|
||
**Метрики:** `llm_heavy_share_ratio=0.0` — важкі запити ще не логовані (лічильники нульові, нові після restart).
|
||
|
||
### GAPS
|
||
|
||
- `local_qwen3_8b`, `qwen3_strategist_8b`, ... — **всі вказують на 27B замість 8B** (рядки в config не оновлені після зміни). Назви оманливі.
|
||
- `crew_local_27b` використовує `172.17.0.1:11434` — не `host.docker.internal`. Inconsistency: CPU профілі через host.docker.internal, GPU — через IP.
|
||
|
||
### RECOMMENDED PATCHES
|
||
|
||
**Patch 1:** Уніфікувати GPU профілі на `host.docker.internal:11434`:
|
||
```yaml
|
||
# services/router/router-config.yml
|
||
crew_local_27b:
|
||
base_url: http://host.docker.internal:11434 # було 172.17.0.1
|
||
crew_vision_27b:
|
||
base_url: http://host.docker.internal:11434
|
||
```
|
||
|
||
**Patch 2:** Перейменувати оманливі профілі (або залишити as-is якщо вони deprecated):
|
||
```yaml
|
||
# local_qwen3_8b → local_qwen3_27b (або видалити невикористані)
|
||
```
|
||
|
||
---
|
||
|
||
## 3. ФОТО E2E — Telegram → Vision → Агент
|
||
|
||
### CURRENT STATE (Два шляхи!)
|
||
|
||
#### Шлях A: Прямий (основний для більшості агентів)
|
||
```
|
||
Telegram photo → Gateway (http_api.py:~2085)
|
||
↓ download photo via Telegram Bot API → file_url (https://api.telegram.org/file/...)
|
||
↓ send_to_router({file_url, images: [file_url], prompt})
|
||
↓ Router (main.py:~2445) → SWAPPER_URL/vision
|
||
payload: {model: "qwen3-vl-8b", prompt, images: [file_url]}
|
||
↓ Swapper /vision → завантажує qwen3-vl:8b (ollama pull) → відповідь
|
||
↓ Router повертає text → Gateway → Telegram
|
||
```
|
||
|
||
#### Шлях B: Через NATS ATTACHMENTS (для parser-pipeline)
|
||
```
|
||
Telegram photo → Gateway
|
||
↓ (окремий worker?) → NATS ATTACHMENTS stream
|
||
↓ parser-pipeline consumer
|
||
process_image() → SWAPPER_URL/vision (base64 encode)
|
||
↓ result → ??? (не ясно куди іде результат)
|
||
```
|
||
|
||
**КРИТИЧНО:** `parser-pipeline` логи показують **тисячі** `ServiceUnavailableError` між рестартами — NATS stream `ATTACHMENTS` зникає після рестарту `dagi-nats-node1` (нема persistence). Після рестарту parser підключається знову (`Consumer created: parser-pipeline`).
|
||
|
||
### Vision model flow (Swapper):
|
||
- Gateway надсилає `file_url` (не base64 завантаження)
|
||
- Router передає `images: [file_url]` у Swapper
|
||
- Swapper `/vision` → `qwen3-vl:8b` через Ollama (6.1GB, lazy load)
|
||
- **qwen3-vl:8b зараз `unloaded`** — cold-start ~30-60s при першому виклику
|
||
|
||
### GAPS
|
||
|
||
1. **NATS stream ATTACHMENTS не персистентний** — після `docker restart dagi-nats-node1` stream зникає. Parser спамить `ServiceUnavailableError` поки не перезапустити.
|
||
2. **parser-pipeline `SWAPPER_URL=http://swapper-service:8890`** — але контейнер називається `swapper-service-node1`. DNS може не резолвитись.
|
||
3. **ingest-service** також має `SWAPPER_URL=http://swapper-service-node1:8890` → `socket.gaierror: Temporary failure in name resolution` — сервіс намагається резолвити щось не те.
|
||
4. **Шлях B результат незрозумілий** — куди parser-pipeline відправляє результат обробки зображення після Vision?
|
||
5. **qwen3-vl:8b cold-start** — перший запит до vision займе 30-60s (lazy load).
|
||
|
||
### RECOMMENDED PATCHES
|
||
|
||
**Patch 3:** Виправити `SWAPPER_URL` в parser-pipeline compose:
|
||
```yaml
|
||
# docker-compose.node1.yml, parser-pipeline service
|
||
environment:
|
||
- SWAPPER_URL=http://swapper-service-node1:8890 # було: http://swapper-service:8890
|
||
```
|
||
|
||
**Patch 4:** NATS stream ATTACHMENTS — зробити файловий storage з retention:
|
||
```yaml
|
||
# nats-js-init service (вже є в compose) — перевірити що він запускається після рестарту NATS
|
||
```
|
||
|
||
---
|
||
|
||
## 4. PDF/ДОКУМЕНТИ — Обробка
|
||
|
||
### CURRENT STATE
|
||
|
||
**Сервіси обробки документів:**
|
||
| Сервіс | Статус | Роль |
|
||
|--------|--------|------|
|
||
| `render-pdf-worker-node1` | ✅ up, **idle** | PDF → PNG/зображення (NATS: artifact.job.render_pdf.requested) |
|
||
| `render-pptx-worker-node1` | ⚠️ DNS fail (`nats`) | PPTX → PNG (NATS: нема з'єднання) |
|
||
| `index-doc-worker-node1` | ⚠️ DNS fail (RAG service?) | RAG indexing (NATS: artifact.job.*) |
|
||
| `presentation-renderer-node1` | ✅ healthy (9212) | API сервіс рендерингу |
|
||
| `oneok-gotenberg-node1` | ✅ up (3010) | HTML/PDF generation (Gotenberg) |
|
||
| `rag-service-node1` | ✅ healthy (9500) | RAG retrieval |
|
||
| `artifact-registry-node1` | ✅ healthy (9220) | Артефакт реєстр |
|
||
| `dagi-minio-node1` | ✅ up (9000-9001) | S3 storage |
|
||
| `parser-pipeline` | ✅ up (8101) | NATS consumer → Swapper doc+image |
|
||
|
||
**Docling:** НЕ ВСТАНОВЛЕНИЙ як окремий контейнер. Є як модель у Swapper (`granite-docling`, тип `document`, 2.5GB, `unloaded`).
|
||
|
||
**Шлях обробки документа (PDF):**
|
||
```
|
||
Telegram doc → Gateway → ?
|
||
→ або send_to_router з doc_url
|
||
→ або через NATS → parser-pipeline → Swapper /document
|
||
Swapper /document → granite-docling (lazy load, 2.5GB) → текст
|
||
|
||
Паралельно:
|
||
→ artifact.job.render_pdf.requested → render-pdf-worker → PNG → artifact-registry → MinIO
|
||
→ artifact.job.index_doc.requested → index-doc-worker → rag-service (RAG indexing)
|
||
```
|
||
|
||
### GAPS
|
||
|
||
1. **render-pptx-worker** не може резолвити `nats` DNS — на іншій docker network або compose group.
|
||
2. **index-doc-worker** DNS fail (щось не резолвить) — перевірити network config.
|
||
3. **granite-docling** у swapper `unloaded` — завантажується lazily, займе час при першому запиті документа. GPU увімкнений для docling? (GPU_ENABLED=false зараз!)
|
||
4. **Немає Docling окремим сервісом** — вся обробка документів через Swapper, який зараз CPU-only через наші зміни.
|
||
|
||
### GAPS — КРИТИЧНО
|
||
|
||
> **Swapper GPU_ENABLED=false** — означає, що granite-docling, got-ocr2, qwen3-vl-8b і whisper будуть завантажуватись в CPU/RAM. При 20GB VRAM це субоптимально для Vision і OCR моделей.
|
||
|
||
### RECOMMENDED PATCHES
|
||
|
||
**Patch 5:** Виправити network для render-pptx-worker та index-doc-worker:
|
||
```yaml
|
||
# docker-compose.node1.yml — додати network dagi-network до цих сервісів
|
||
render-pptx-worker:
|
||
networks:
|
||
- dagi-network # щоб резолвити 'nats'
|
||
index-doc-worker:
|
||
networks:
|
||
- dagi-network
|
||
```
|
||
|
||
---
|
||
|
||
## 5. STT/TTS/SWAPPER — Детальний аналіз
|
||
|
||
### CURRENT STATE
|
||
|
||
**Swapper /health:** `{"status":"healthy","active_model":"qwen3-8b","mode":"single-active"}`
|
||
|
||
**Swapper конфіг (фактичний):**
|
||
- `mode: multi-active` в yaml, але ENV `MAX_CONCURRENT_MODELS=1` → single-active режим
|
||
- `GPU_ENABLED=false` (наша зміна) — але config.yaml каже `gpu_enabled: true`
|
||
- `WHISPER_DEVICE=cpu, WHISPER_COMPUTE_TYPE=int8`
|
||
|
||
**Моделі в Swapper:**
|
||
| Модель | Тип | Розмір | Статус |
|
||
|--------|-----|--------|--------|
|
||
| qwen3-8b | llm | 5.2GB | **loaded** (Ollama) |
|
||
| qwen3-vl-8b | vision | 6.1GB | unloaded |
|
||
| got-ocr2 | ocr | 7.0GB | unloaded |
|
||
| donut-base | ocr | 3.0GB | unloaded |
|
||
| donut-cord | ocr | 3.0GB | unloaded |
|
||
| granite-docling | document | 2.5GB | unloaded |
|
||
| faster-whisper-large | stt | 3.0GB | unloaded |
|
||
| whisper-small | stt | 0.5GB | unloaded |
|
||
| xtts-v2 | tts | 2.0GB | unloaded |
|
||
| flux-klein-4b | image_gen | 15.4GB | unloaded |
|
||
|
||
**STT:**
|
||
- STT startup: `[STT-POLICY] WHISPER_DEVICE env='cpu' | actual_device='cpu'` ✅
|
||
- Swapper `/stt` ← parser-pipeline (audio processing)
|
||
- Swapper `/stt` ← router (STT_URL)
|
||
- Swapper `/stt` ← gateway (STT_SERVICE_URL)
|
||
- **Whisper завантажується lazily при першому аудіо-запиті** на CPU (int8)
|
||
|
||
**TTS:** xtts-v2 (2GB) — `unloaded`. Не використовується активно.
|
||
|
||
**Висновок по Swapper: ЗАЛИШИТИ (він критичний)**
|
||
|
||
Swapper є єдиним агрегатором для:
|
||
1. **Vision** (`/vision`) — qwen3-vl:8b для всіх агентів що аналізують фото
|
||
2. **STT** (`/stt`) — Whisper для голосових повідомлень
|
||
3. **OCR** (`/ocr`) — got-ocr2 для документів
|
||
4. **Document** (`/document`) — granite-docling для PDF/DOCX
|
||
5. **TTS** (`/tts`) — xtts-v2 (поки не активований)
|
||
|
||
**Проблема:** `active_model=qwen3-8b` через Ollama — це **дублювання** з основним Ollama GPU. Swapper завантажує qwen3:8b через свій ollama, поки є окремий Ollama на 11434 з 27B. При виклику vision, swapper **swap'ає** qwen3:8b і завантажує qwen3-vl:8b — займає VRAM GPU.
|
||
|
||
> **Але GPU_ENABLED=false!** — Значить qwen3-vl:8b завантажиться в RAM/CPU, що дуже повільно (>30s).
|
||
|
||
### RECOMMENDED PATCHES
|
||
|
||
**Patch 6 (ВАЖЛИВИЙ):** Вирішити GPU конфлікт Swapper vs Ollama:
|
||
|
||
Варіанти:
|
||
- **A (рекомендований):** Swapper Vision через Ollama GPU (11434), STT на CPU:
|
||
```yaml
|
||
# docker-compose.node1.yml, swapper-service
|
||
environment:
|
||
- GPU_ENABLED=true # дозволити GPU для vision/OCR
|
||
- WHISPER_DEVICE=cpu # але STT лишається CPU
|
||
- WHISPER_COMPUTE_TYPE=int8
|
||
# Прибрати CUDA_VISIBLE_DEVICES= (empty block GPU)
|
||
```
|
||
Потрібно додати GPU device back:
|
||
```yaml
|
||
deploy:
|
||
resources:
|
||
reservations:
|
||
devices:
|
||
- driver: nvidia
|
||
count: 1
|
||
capabilities: [gpu]
|
||
```
|
||
Тоді Swapper поверне GPU для vision і OCR.
|
||
|
||
- **B (поточний стан):** GPU_ENABLED=false → all CPU → Vision дуже повільно
|
||
|
||
---
|
||
|
||
## 6. GPU POLICY
|
||
|
||
### CURRENT STATE ✅
|
||
|
||
```
|
||
VRAM: 18783 MiB / 20475 MiB (qwen3.5:27b-q4_K_M завантажений — warmup timer)
|
||
GPU Ollama (11434): 1 model — qwen3.5:27b-q4_K_M (17434 MiB)
|
||
CPU Ollama (11435): 0 models (smollm2:135m unloaded, lazy)
|
||
gpu_single_model_policy_ok = 1 ✅
|
||
ollama_cpu_instance_up = 1 ✅
|
||
```
|
||
|
||
**Проблема:** Swapper показує `active_model=qwen3-8b` — це qwen3:8b через ollama **всередині swapper**, але Swapper зараз CPU-only. Значить qwen3:8b у свопері не займає GPU VRAM поки GPU_ENABLED=false. Але якщо повернути GPU Swapper — треба перевірити що 27B + qwen3-vl-8b не одночасно в VRAM (20GB максимум).
|
||
|
||
**Потенційний конфлікт:** 27B (17.4GB) + qwen3-vl-8b (6.1GB) = **23.5GB > 20GB VRAM** → OOM!
|
||
|
||
Необхідна координація: коли Swapper завантажує vision модель, Ollama GPU має вивантажити 27B або навпаки.
|
||
|
||
---
|
||
|
||
## 7. NODA1 ↔ NODA2 — З'єднання
|
||
|
||
### CURRENT STATE
|
||
|
||
**Інфраструктура:**
|
||
- NODA1 і NODA2 (`llm80-che-1-1`, IP 192.168.1.240) — це **K3s cluster** (flannel CNI)!
|
||
- NODA1: `node1-daarion` — **control-plane, master** (Ready)
|
||
- NODA2 (`llm80-che-1-1`): `worker node` — **NotReady** (проблема!)
|
||
- **Flannel:** `10.42.0.0/24` (NODA1), `10.42.1.0/24` (NODA2) — pod overlay network
|
||
- **WireGuard:** НЕ встановлений
|
||
- **NATS:** cluster config є (`my_cluster`, port 6222), але `routes = []` — **NATS не з'єднаний між нодами**
|
||
|
||
**K3s pods на NODA2 (llm80-che-1-1):** більшість `Terminating` або `Pending` — NODA2 NotReady!
|
||
|
||
**Що це означає:**
|
||
- Фізично NODA1 і NODA2 з'єднані через K3s/flannel (LAN, 192.168.x.x)
|
||
- Але Docker Compose сервіси на NODA2 (memory service, qdrant, neo4j) — **окремі**, не в K3s
|
||
- NATS між нодами не federatederated — жоден cross-node message bus не налаштований
|
||
|
||
### GAPS
|
||
|
||
1. **K3s worker NODA2 NotReady** — pods Terminating/Pending. Не ясно чи це критично для поточного продакшну.
|
||
2. **NATS не кластеризований** — немає leafnode/route між NODA1 і NODA2 NATS.
|
||
3. **Немає cross-node subjects** для агентів.
|
||
4. **NODA2 підключення до NODA1:** NODA2 має свій Docker Compose (окремі memory/qdrant), немає спільного bus.
|
||
|
||
### RECOMMENDED PATCHES
|
||
|
||
**Patch 7 (NATS federation між нодами):**
|
||
```conf
|
||
# /opt/microdao-daarion/nats/nats-server.conf (NODA1)
|
||
leafnodes {
|
||
port: 7422
|
||
}
|
||
|
||
# NATS на NODA2 підключається як leafnode:
|
||
leafnodes {
|
||
remotes = [{ url: "nats://144.76.224.179:7422" }]
|
||
}
|
||
```
|
||
|
||
Це дозволить NODA2 публікувати/підписуватись на `node.control.noda2.*` через NODA1.
|
||
|
||
---
|
||
|
||
## 8. CTO SOFIIA — Control Plane
|
||
|
||
### CURRENT STATE
|
||
|
||
**`control-plane` контейнер (порт 9200):**
|
||
- FastAPI сервіс з JWT auth (`SERVICE_ROLE=controlplane`)
|
||
- Endpoints:
|
||
- `GET /prompts/{agent_id}` — версіоновані system prompts з файлів `*_prompt.txt`
|
||
- `GET /policy/{agent_id}` — RBAC/entitlements (DefaultPolicies)
|
||
- `GET /prompts/{agent_id}/hash` — hash промпту для drift detection
|
||
- **401 Unauthorized** при зверненні без JWT — це правильно
|
||
|
||
**Що є:**
|
||
- ✅ Промпти централізовані та версіоновані
|
||
- ✅ JWT auth для сервіс-до-сервіс
|
||
- ✅ Policy/RBAC per agent
|
||
- ✅ `dagi-vision-encoder-node1` — ViT-L-14 на CPU (embeddings)
|
||
|
||
**Що НЕ реалізовано:**
|
||
- ❌ Node operations (restart/deploy/health через control-plane)
|
||
- ❌ Sofiia не має NATS-control topic для публікації команд
|
||
- ❌ Немає `node-ops-worker` на кожній ноді
|
||
- ❌ Sofiia добавляє нову ноду тільки через SSH root (bRhfV7uNY9m6er — hardcoded!)
|
||
- ❌ Немає механізму "додати нову ноду без root"
|
||
|
||
**Поточний механізм керування нодами:** SSH з паролем root. Небезпечно.
|
||
|
||
### RECOMMENDED PATCHES
|
||
|
||
**Patch 8 (мінімальний control plane extension):**
|
||
|
||
Додати в control-plane endpoints для node ops:
|
||
```python
|
||
# services/control-plane/app/main.py (або новий node_ops.py)
|
||
|
||
# Sofiia публікує на NATS:
|
||
# node.control.noda1.restart_service → {service_name, reason}
|
||
# node.control.noda1.health_check → {}
|
||
# node.control.noda1.get_logs → {service_name, lines}
|
||
|
||
# node-ops-worker (новий мікросервіс) підписується на ці subjects
|
||
# виконує whitelist commands (docker restart, docker logs tail, health curl)
|
||
# відповідає на node.control.noda1.reply.*
|
||
```
|
||
|
||
**Мінімальна реалізація (50 рядків Python):**
|
||
```python
|
||
# services/node-ops-worker/main.py
|
||
ALLOWED_COMMANDS = {
|
||
"restart_service": lambda s: f"docker restart {s}",
|
||
"health_check": lambda s: f"curl -sf http://localhost:{PORT_MAP[s]}/health",
|
||
"logs_tail": lambda s, n: f"docker logs --tail {n} {s}",
|
||
}
|
||
# Subscribe to node.control.noda1.> via NATS
|
||
# Execute only ALLOWED_COMMANDS
|
||
# Reply to reply subject
|
||
```
|
||
|
||
---
|
||
|
||
## VALIDATION CHECKLIST
|
||
|
||
```bash
|
||
# 1. Router CPU profiles (host.docker.internal)
|
||
docker exec dagi-router-node1 curl -s http://host.docker.internal:11435/api/tags | python3 -c 'import sys,json; print("CPU Ollama OK:", len(json.load(sys.stdin).get("models",[])))'
|
||
|
||
# 2. GPU policy
|
||
curl -s http://localhost:9400/metrics | grep gpu_single_model_policy_ok
|
||
|
||
# 3. Swapper Vision (cold start test — без кешу)
|
||
# УВАГА: займе 30-60s якщо GPU_ENABLED=false!
|
||
# curl -s -X POST http://localhost:8890/vision -H 'Content-Type: application/json' \
|
||
# -d '{"model":"qwen3-vl-8b","prompt":"що на фото?","images":["<url>"]}' | jq .
|
||
|
||
# 4. Parser pipeline connected
|
||
docker logs --tail 5 parser-pipeline 2>&1 | grep -E 'Connected|Consumer created'
|
||
|
||
# 5. NATS stream ATTACHMENTS exists
|
||
curl -s 'http://localhost:8222/jsz?streams=true' | python3 -m json.tool | grep -A3 'ATTACHMENTS'
|
||
|
||
# 6. render-pptx-worker DNS fix check
|
||
docker logs --tail 5 render-pptx-worker-node1 2>&1 | grep -v 'getaddrinfo'
|
||
|
||
# 7. index-doc-worker DNS fix check
|
||
docker logs --tail 5 index-doc-worker-node1 2>&1 | grep -v 'getaddrinfo'
|
||
|
||
# 8. Control plane health
|
||
curl -s http://localhost:9200/health
|
||
|
||
# 9. Swapper STT device
|
||
docker logs swapper-service-node1 2>&1 | grep STT-POLICY
|
||
|
||
# 10. K3s NODA2 status
|
||
kubectl get nodes
|
||
```
|
||
|
||
---
|
||
|
||
## PRIORITIZED ACTION PLAN
|
||
|
||
### P0 — Негайно (production impact):
|
||
|
||
| # | Патч | Файл | Вплив |
|
||
|---|------|------|-------|
|
||
| 3 | SWAPPER_URL fix в parser-pipeline | docker-compose.node1.yml | Vision через parser |
|
||
| 5 | Network fix render-pptx + index-doc | docker-compose.node1.yml | Документи |
|
||
| 6 | GPU повернути Swapper (Vision повільний!) | docker-compose.node1.yml | Vision latency |
|
||
|
||
### P1 — Цього тижня:
|
||
|
||
| # | Патч | Файл | Вплив |
|
||
|---|------|------|-------|
|
||
| 1 | host.docker.internal для GPU профілів | router-config.yml | Stability |
|
||
| 4 | NATS ATTACHMENTS persistence | nats config | Parser stability |
|
||
| 7 | NATS leafnode NODA1↔NODA2 | nats-server.conf | Cross-node |
|
||
|
||
### P2 — Наступний спринт:
|
||
|
||
| # | Патч | Файл | Вплив |
|
||
|---|------|------|-------|
|
||
| 8 | node-ops-worker для Sofiia control | нові файли | Security |
|
||
| 2 | Profile rename в router-config | router-config.yml | Clarity |
|
||
|
||
---
|
||
|
||
## ВІДПОВІДІ НА 7 КЛЮЧОВИХ ПИТАНЬ
|
||
|
||
### 1. Фото E2E
|
||
**Telegram photo → Gateway** (скачує файл → file_url) → **`send_to_router({images:[file_url]})`** → **Router** перевіряє агента → якщо vision-агент → **`SWAPPER_URL/vision`** → Swapper → Ollama `qwen3-vl:8b` → text опис → Router → Gateway → Telegram. Parser-pipeline — паралельний worker для асинхронної обробки (не основний шлях). Payload: `{model, prompt, images:[url], max_tokens}`.
|
||
|
||
### 2. Документи/PDF
|
||
**Немає Docling як сервісу.** Docling вбудований в Swapper як `granite-docling` (lazy, unloaded). Шлях: Gateway → Router → `SWAPPER_URL/document` → Swapper → granite-docling. Паралельно через NATS: `artifact.job.render_pdf.requested` → render-pdf-worker → PNG → MinIO/artifact-registry. `index-doc-worker` індексує в RAG але має DNS fail.
|
||
|
||
### 3. Router
|
||
Top-level агенти → **DeepSeek API** (cloud_deepseek). Crew tasks → **qwen3.5:27b-q4_K_M** (crew_local_27b, GPU). Monitoring/small → **smollm2:135m** (crew_local_small, CPU Ollama 11435). `ENABLE_CREW_MODEL_ROUTING=1` активний. Vision агенти отримують `qwen3-vl-8b` через Swapper.
|
||
|
||
### 4. TTS/STT
|
||
STT: **Whisper (CPU, int8)** через Swapper `/stt`. `WHISPER_DEVICE=cpu` підтверджено логами. Lazy load при першому аудіо. Підтримується: faster-whisper-large (3GB), whisper-small (0.5GB). TTS: xtts-v2 (2GB) — **not deployed активно** (unloaded). Немає VRAM конкуренції для STT.
|
||
|
||
### 5. Swapper
|
||
**Залишити.** Є єдиним агрегатором для Vision (qwen3-vl:8b), STT (Whisper), OCR (got-ocr2), Document (granite-docling), TTS (xtts-v2). Без Swapper треба окремі сервіси для кожного. Але: `active_model=qwen3-8b` — потенційно невикористана ролі (є окремий Ollama). **Слід розглянути видалення qwen3-8b зі Swapper** — він дублює GPU Ollama, залишити тільки Vision/OCR/STT/Document функції.
|
||
|
||
### 6. NODA1↔NODA2
|
||
З'єднані через **K3s cluster** (flannel, 10.42.0.0/24). NODA2 (`llm80-che-1-1`, 192.168.1.240) — K3s worker, зараз **NotReady**. NATS між нодами **не з'єднаний** (routes=[]), немає leafnode. Docker Compose сервіси незалежні. Для cross-node messaging потрібен NATS leafnode або Flannel pod networking.
|
||
|
||
### 7. CTO Sofiia Control Plane
|
||
Поточний стан: `control-plane` (9200) — JWT-захищений сервіс з prompts + policy. **Немає node-ops механізму**. Sofiia керує нодами через SSH root (небезпечно). Правильний шлях: NATS-control plane + `node-ops-worker` на кожній ноді з whitelist команд. control-plane вже є основою — треба додати NATS subscription для node operations.
|
||
|
||
---
|
||
|
||
*Звіт згенеровано автоматично аудитом NODA1 | Sofiia v2.7 | 2026-02-27*
|