# Архитектура микросервисов GooSeek Документ описывает план разбиения монолитного приложения GooSeek на микросервисы. --- ## 1. Текущая архитектура (монолит) ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ Next.js Application (monolith) │ ├─────────────────────────────────────────────────────────────────────────────┤ │ API Routes │ Agents/Search │ Models/Providers │ Data │ │ /api/chat │ classifier │ OpenAI, Anthropic │ SQLite│ │ /api/search │ researcher │ Ollama, Groq... │ config│ │ /api/images │ widgets │ registry │ uploads│ │ /api/videos │ writer │ │ │ │ /api/uploads │ media (image/video) │ │ │ │ /api/chats │ │ │ │ │ /api/providers │ │ │ │ │ /api/config │ │ │ │ │ /api/suggestions │ │ │ │ │ /api/weather │ │ │ │ │ /api/discover │ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ External: SearXNG │ Yahoo Finance │ Open-Meteo │ LLM APIs (OpenAI, etc.) │ └─────────────────────────────────────────────────────────────────────────────┘ ``` --- ## 2. Предлагаемые микросервисы ### 2.1 Общая схема ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Frontend │────▶│ Gateway │────▶│ Chat │────▶│ Research │ │ (Next.js) │ │ (BFF/API) │ │ Service │ │ Service │ └──────────────┘ └──────────────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ │ │ ▼ ▼ ▼ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ Config/Chats │ │ LLM Proxy │ │ Search │ └────────────▶│ Service │ │ Service │ │ Service │ └──────────────┘ └──────────────┘ └──────┬───────┘ │ │ │ │ │ │ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Storage │ │ Providers │ │ Uploads │ │ Service │ │ (external) │ │ Service │ └──────────────┘ └──────────────┘ └──────────────┘ ``` --- ## 3. Описание сервисов ### 3.1 Frontend (Next.js UI) **Назначение:** Только UI — страницы, компоненты, клиентский state. **Содержимое:** - `src/app/page.tsx`, `layout.tsx`, маршруты страниц - `src/components/` — все UI компоненты - `src/lib/hooks/` — клиентские хуки - `src/lib/actions.ts` — вызовы к Gateway API **Исключить:** Все API routes (`src/app/api/`), серверная логика агентов, прямые вызовы DB. **API:** Вызывает только Gateway. --- ### 3.2 Gateway (Backend-for-Frontend / API Gateway) **Назначение:** Единая точка входа для клиента, роутинг, валидация, агрегация. **Реализация:** Отдельный Node.js сервис (Fastify/Express) или часть Next.js API routes, которая только проксирует. **Маршруты:** - `POST /api/chat` → Chat Service - `POST /api/search` → Chat Service (API mode) - `GET/POST /api/chats/*` → Storage Service - `POST /api/uploads` → Uploads Service - `GET/POST /api/providers/*` → Config + LLM Proxy - `GET/POST /api/config/*` → Storage Service (config) - `POST /api/suggestions` → Chat Service - `POST /api/images` → Chat/Media Service - `POST /api/videos` → Chat/Media Service - `GET /api/weather` → Widgets Service (или inline) - `POST /api/discover` → Search Service **Зависимости:** Chat, Storage, Uploads, Search. Не содержит бизнес-логики. --- ### 3.3 Chat Service (Оркестратор) **Назначение:** Главный оркестратор диалога: классификация, планирование, вызов research и writer. **Исходники:** - `src/lib/agents/search/index.ts` — SearchAgent - `src/lib/agents/search/api.ts` — APISearchAgent - `src/lib/agents/search/classifier.ts` - `src/lib/agents/search/widgets/` — executor + виджеты (weather, stock, calc) - `src/lib/prompts/search/` — classifier, writer, researcher prompts - `src/lib/session.ts` **API (внутренние):** - `POST /classify` — классификация запроса - `POST /search` — полный пайплайн (classify → research → widgets → write) - `POST /suggestions` — генерация подсказок **Вызывает:** - Research Service — для поиска - LLM Proxy — для LLM вызовов (classify, write, suggestions) - Widgets (внешние API: Yahoo Finance, погода) — можно вынести в отдельный сервис **Поток данных:** 1. Классификация (LLM) 2. Параллельно: Research Service + виджеты 3. Генерация ответа (LLM) 4. Сохранение в Storage (через Gateway или напрямую) --- ### 3.4 Research Service **Назначение:** Выполнение исследовательского цикла — tools (web, academic, social, scrape, uploads). **Исходники:** - `src/lib/agents/search/researcher/` — Researcher, ActionRegistry - `src/lib/agents/search/researcher/actions/` — webSearch, academicSearch, socialSearch, scrapeURL, uploadsSearch, plan, done - `src/lib/prompts/search/researcher.ts` **API:** - `POST /research` — вход: classification, query, chatHistory, config → выход: searchFindings, findings **Вызывает:** - Search Service — SearXNG (web, academic, social) - Uploads Service — семантический поиск по файлам - LLM Proxy — для researcher agent (tool calls) - Внешние URL — scrape **Важно:** Researcher — это LLM-driven agent с tool calls. LLM решает, какой tool вызвать. Либо LLM живёт в Chat Service и вызывает tools по HTTP, либо Research Service сам держит копию researcher LLM — тогда нужно дублировать LLM-вызовы. **Рекомендация:** Оставить researcher внутри Chat Service, а в Research Service вынести только **действия** (web search, scrape, uploads search) как отдельные HTTP endpoints. Chat Service вызывает Research Service по каждому tool call. Это уменьшает связанность, но увеличивает сетевые вызовы. **Альтернатива:** Research как один сервис с LLM — получает query и classification, сам итерирует и возвращает готовые findings. Меньше round-trips, но дублирование LLM-инфраструктуры. --- ### 3.5 Search Service (SearXNG + обёртка) **Назначение:** Обёртка над SearXNG для веб/академического/медиа поиска. **Исходники:** - `src/lib/searxng.ts` - Вызовы: webSearch, academicSearch, socialSearch, image, video — все идут через `searchSearxng` **API:** - `GET /search?q=...&engines=...&categories=...` - `GET /images?q=...` - `GET /videos?q=...` **Внешняя зависимость:** SearXNG (уже отдельный сервис/контейнер). **Реализация:** Минимальный Node.js/Fastify сервис, который проксирует к SearXNG и добавляет логику (rate limiting, fallback, кэш). --- ### 3.6 Uploads Service **Назначение:** Загрузка файлов, парсинг (PDF, DOCX, TXT), эмбеддинги, семантический поиск. **Исходники:** - `src/lib/uploads/manager.ts` — UploadManager - `src/lib/uploads/store.ts` — UploadStore (поиск по эмбеддингам) - `src/lib/utils/splitText.ts`, `computeSimilarity.ts` - Зависимости: pdf-parse, officeparser **API:** - `POST /upload` — multipart, возвращает fileIds - `POST /search` — query, fileIds → chunks (семантический поиск) - `GET /files/:id` — метаданные файла **Вызывает:** LLM Proxy — только для embedding модели (можно вынести в отдельный Embedding Service). **Хранение:** Файлы на диске/volume, `uploaded_files.json`, `.content.json` с chunks. --- ### 3.7 Storage Service **Назначение:** Централизованное хранилище: чаты, сообщения, конфигурация. **Исходники:** - `src/lib/db/` — schema, migrations, drizzle - `src/lib/config/` — ConfigManager, modelProviders **API:** - `GET/POST/PUT/DELETE /chats` - `GET/POST/PUT/DELETE /chats/:id` - `GET/POST/PUT/DELETE /messages` - `GET/POST /config` - `GET/POST /config/providers` **База:** SQLite (или PostgreSQL при масштабировании). config.json можно мигрировать в ту же БД или отдельную таблицу. --- ### 3.8 LLM Proxy Service (опционально) **Назначение:** Единая точка для вызовов LLM и embedding — OpenAI, Anthropic, Ollama, Groq, Gemini и т.д. **Исходники:** - `src/lib/models/` — registry, providers, base LLM/Embedding **API:** - `POST /chat` — text generation (streaming) - `POST /embed` — embedding - `GET /providers` — список провайдеров и моделей **Конфигурация:** Берёт из Storage Service (config/providers) или env. **Альтернатива:** LLM Proxy можно не выделять в отдельный сервис — каждый сервис (Chat, Research, Uploads) сам подключается к провайдерам. Но тогда дублирование кода и конфигурации. Рекомендуется вынести в общую библиотеку или отдельный сервис. --- ## 4. Матрица зависимостей | Сервис | От кого получает вызовы | Кого вызывает | |-------------|----------------------------------|----------------------------------| | Gateway | Frontend | Chat, Storage, Uploads, Search | | Chat | Gateway | Research, LLM Proxy, Storage | | Research | Chat | Search, Uploads, LLM Proxy | | Search | Research, Chat (media) | SearXNG (внешний) | | Uploads | Gateway, Research | LLM Proxy (embedding) | | Storage | Gateway, Chat | — | | LLM Proxy | Chat, Research, Uploads | OpenAI, Anthropic, Ollama... | --- ## 5. Разбиение по репозиториям/папкам ### Вариант A: Монорепо (рекомендуется для старта) ``` gooseek/ ├── apps/ │ ├── frontend/ # Next.js UI │ ├── gateway/ # BFF / API Gateway │ ├── chat-service/ # SearchAgent, classifier, writer, widgets │ ├── research-service/ # Researcher, actions │ ├── search-service/ # SearXNG wrapper │ ├── uploads-service/ # UploadManager, UploadStore │ ├── storage-service/ # DB, config │ └── llm-proxy/ # Models registry, providers ├── packages/ │ ├── shared-types/ # Общие типы, DTO │ └── shared-utils/ # formatHistory, splitText, computeSimilarity ├── docker-compose.yaml └── package.json # Turborepo/nx workspace ``` ### Вариант B: polyrepo Отдельные репозитории для каждого сервиса. Больше гибкости в деплое, но сложнее координация изменений. --- ## 6. Порядок миграции (фазы) ### Фаза 1: Выделение Search Service - Обернуть SearXNG в отдельный сервис - Chat/Research вызывают его по HTTP вместо прямого импорта `searchSearxng` - **Риск:** Низкий. SearXNG уже внешний. ### Фаза 2: Выделение Storage Service - Вынести DB + config в отдельный сервис - Gateway и Chat переходят на HTTP к Storage - **Риск:** Средний. Много точек входа в DB. ### Фаза 3: Выделение Uploads Service - Вынести UploadManager + UploadStore - Research (uploadsSearch action) и Gateway вызывают Uploads по HTTP - **Риск:** Средний. Embedding модель — зависимость. ### Фаза 4: Выделение LLM Proxy - Общая обёртка над провайдерами - Chat, Research, Uploads вызывают LLM Proxy - **Риск:** Высокий. Много мест используют LLM напрямую. ### Фаза 5: Выделение Research Service - Researcher + actions в отдельный сервис - Chat вызывает Research по одному endpoint «проведи исследование» - **Риск:** Высокий. Тесная связь с Session, streaming. ### Фаза 6: Gateway + развязка Frontend - Frontend только UI, все вызовы через Gateway - Gateway — тонкий роутер без бизнес-логики - **Риск:** Средний. Рефакторинг API routes. --- ## 7. Ключевые вызовы и риски 1. **Streaming:** Текущий chat stream идёт от SearchAgent до клиента. При разбиении нужно решить: стримить через Gateway (proxy) или от Chat Service напрямую (WebSocket/SSE через Gateway как туннель). 2. **Session/state:** SessionManager — in-memory. При масштабировании Chat Service нужен Redis или аналог для shared state. 3. **Латентность:** Каждый HTTP hop добавляет ~10–50ms. Research делает много итераций — если Research в отдельном сервисе, round-trips умножаются. 4. **Embedding в Uploads:** Uploads нужна embedding модель. Варианты: вызывать LLM Proxy, или держать тяжёлую модель (transformers) внутри Uploads. 5. **Конфигурация:** Сейчас config.json на диске. При микросервисах — централизованный config (env, vault, или Storage Service). --- ## 8. Минимальный MVP разбиения Если цель — не полный microservices, а **модульность и возможность деплоить части отдельно**: | Сервис | Код | Отдельный процесс | |---------------|-----------------------------|-------------------| | **search-api**| `searxng.ts` + route | Да (отдельный порт) | | **uploads-api**| `uploads/` + route | Да | | **chat** | Всё остальное (agents, LLM, DB) | Один процесс | | **frontend** | Next.js UI | Отдельно (static/SSR) | Так получается 3–4 контейнера вместо 1, но без глубокой декомпозиции логики. --- ## 9. Следующие шаги 1. Определить: полное разбиение или MVP. 2. Выбрать стек для каждого сервиса (Node.js/Fastify, Next.js API routes, Go и т.д.). 3. Описать контракты API (OpenAPI/JSON Schema) для межсервисного взаимодействия. 4. Настроить docker-compose для локальной разработки. 5. Внедрить общие пакеты (shared-types, shared-utils) в монорепо. 6. Начать с Фазы 1 (Search Service) как пилот.