Перейти к основному содержимому

Архитектура

Обзор системы

AgentCore — мультиканальная AI-платформа, которая связывает messaging-каналы (WhatsApp Cloud API, Telegram) с RAG-базой знаний уровня отдела и автоматизированными approval-процессами.

┌─────────────┐   ┌─────────────┐
│ WhatsApp │ │ Telegram │
│ Cloud API │ │ (Grammy) │
└──────┬──────┘ └──────┬──────┘
│ │
▼ ▼
┌──────────────────────────────────┐
│ Fastify Server │
│ routes, auth, RBAC, dept scope │
└──────────────┬───────────────────┘

┌──────────┼──────────┬──────────────┐
▼ ▼ ▼ ▼
┌────────┐ ┌───────┐ ┌────────────┐ ┌────────────┐
│ Agent │ │ HITL │ │ Memory │ │ WebSocket │
│ Runner │ │Approve│ │ Extraction │ │ Events │
└───┬────┘ └───┬───┘ └─────┬──────┘ └─────┬──────┘
│ │ │ │
▼ ▼ ▼ ▼
┌──────────────────────────────────────────────────┐
│ PostgreSQL 16 + pgvector │
│ Redis 7 (BullMQ queues + rate-limit store) │
└──────────────────────────────────────────────────┘

Конвейер сообщений

ADR-001 делает agent-tasks основной границей выполнения для входящих сообщений. Channel workers становятся транспортными адаптерами: нормализуют входящее сообщение, сохраняют записи пользователя/разговора/сообщения, создают AgentTask и ставят его в очередь. Они больше не владеют решениями по RAG/HITL.

  1. Канал получает сообщение через webhook WhatsApp Cloud API или polling/webhook Telegram.
  2. Inbound-очередь канала (wa-inbound или tg-inbound) нормализует транспортный payload.
  3. Inbound worker находит или создаёт пользователя и разговор, сохраняет сообщение пользователя, создаёт AgentTask и ставит его в очередь agent-tasks.
  4. Agent executor worker обрабатывает задачу:
    • inject_profile — подгружает system prompt namespace и контекст профиля сотрудника;
    • rag_search — запускает OpenAiRagPipeline в проде или fallback-адаптер, выбранный namespace, в тестовом/адаптерном режиме;
    • generate — формирует ответ для канала;
    • confidence_check — управляет маршрутизацией injection guard, триггерами persona escalation, intent-классификацией, fallback по уверенности и обходом матрицы доверия.
  5. Результат маршрутизации сохраняется как строки AgentToolCall и одно из:
    • авто-отправка через wa-outbound или tg-outbound;
    • создание pending Approval и перевод разговора в awaiting_approval;
    • отправка текста persona escalation и перевод разговора в escalated.
  6. При утверждении одобренный или отредактированный ответ ставится в outbound-очередь канала.
  7. Memory extraction запускается после настроенного интервала сообщений.
  8. WebSocket-события стримят жизненный цикл задачи в realtime (agent-task.created, .started, .tool-call, .completed, .failed) с перепроверкой department scope на каждой доставке.

Архитектура компонентов

Fastify-приложение (src/app.ts)

App factory регистрирует компоненты в таком порядке:

  1. OpenAPI — Swagger и Swagger UI (/docs) с префиксом сервера /api/v1.
  2. Security-плагины — Helmet, CORS с точным origin, глобальный rate limit, JWT-аутентификация и departmentScope.
  3. Middleware — audit logger, идемпотентность и структурированный error handler.
  4. Background workers — очереди ingestion, memory extraction и agent executor.
  5. Маршруты — health, auth, knowledge, approvals, traces, namespaces, me, conversations, departments, users, roles, audit, RAG draft, employee profiles, intents, agent tasks, plugins, document templates и notifications в /api/v1.
  6. Каналы — плагины WhatsApp Cloud API и Telegram в /api/v1.
  7. Мониторинг — Bullboard admin UI (/admin/queues) и WebSocket event bridges (/ws/agent-tasks, /ws/notifications).

Система плагинов

Fastify-плагины предоставляют:

  • декоратор authenticate — JWT verify hook (только Bearer header; WebSocket использует first-message auth handshake);
  • декоратор departmentScope — per-request DepartmentScope из forDepartment(request.user);
  • knowledgeIngestionQueue — BullMQ-очередь для обработки документов;
  • memoryExtractionQueue — BullMQ-очередь для extraction профилей;
  • agentTasksQueue — BullMQ-очередь для обработки agent tasks;
  • channelService — абстракция конфигурации каналов, сейчас работает поверх env;
  • broadcastAgentTaskEvent — хелпер WebSocket-бродкаста, перепроверяющий namespace department access перед каждой отправкой;
  • pluginRegistry — реестр integration-плагинов namespace со встроенными OpenDataBot и webhook-плагинами;
  • notification-хелперы — persistent user-уведомления + WebSocket-доставка.

Архитектура очередей (BullMQ + Redis)

ОчередьНазначениеПараллелизм
agent-tasksОбработка agent tasks через адаптерынастраивается
knowledge-ingestПарсинг документов, чанкинг, embeddings1
memory-extractionExtraction профилей из чатов1
wa-inboundОбработка входящих WhatsAppнастраивается
wa-outboundОтправка WhatsAppнастраивается
tg-inboundОбработка входящих Telegramнастраивается
tg-outboundОтправка Telegramнастраивается

Очередь agent-tasks использует 3 retry с exponential backoff (base delay 2s). Таймауты на адаптер: api — 30s, claude_local/codex_local — 300s, ollama — 120s. Stalled job detection автоматически ре-тригерит задачи при смерти воркера.

Все очереди используют exponential backoff для retry при обработке. Воркеры завершаются gracefully по SIGTERM/SIGINT.

Agent runner и adapter layer

Agent executor — канонический message-processing pipeline. Он сохраняет каждую задачу в AgentTask, пишет step-level прогресс в AgentToolCall и абстрагирует генерацию через pluggable adapter-интерфейс (AgentAdapter). Каждый namespace выбирает свой адаптер через config.agentRunner.activeAdapter.

Доступные адаптеры:

АдаптерBackendTimeout
apiOpenAI SDK (chat.completions.create)30s
claude_localClaude CLI (claude --print)300s
codex_localCodex CLI (codex exec --json)300s
ollamaOllama HTTP API (OpenAI-совместимый)120s

Модель данных: каждая задача создаёт AgentTask с вложенными AgentToolCall, которые трекают inject_profile, rag_search, generate, confidence_check и любые adapter-level вызовы в fallback-режиме. Использование токенов, стоимость и длительность трекаются per-task.

См. Конфигурацию для настройки адаптера namespace.

Изоляция отдела

ADR-002 централизует department access через src/lib/department-scope.ts:

  • forDepartment(user) возвращает DepartmentScope;
  • scope.directWhere() scope-ит Prisma-модели с прямым departmentId;
  • scope.nestedWhere('namespace') scope-ит модели вроде AgentTask через связанные namespaces;
  • scope.departmentId используется в raw SQL-фильтрах RAG;
  • admin-пользователи получают межотдельский доступ; все остальные роли ограничены departmentId из JWT.

Fastify-плагин в src/plugins/department-scope.ts декорирует аутентифицированные запросы через request.departmentScope. REST-маршруты, RAG retrieval, agent runner и WebSocket-бродкасты используют один и тот же scope-примитив. Регрессионный тест tests/department-isolation.test.ts проверяет изоляцию list, detail, mutation, RAG, analytics и WebSocket.

Data flow: ingestion

Upload → Parse (PDF/DOCX/TXT/Image) → PII Scrub → Chunk → Embed → Synthetic Q&A → Store

Подробнее — в Знания и RAG.

Data flow: RAG-запрос

User Query → Injection Guard → Intent Classify → Embed Query
→ Vector Search (chunks + questions) + Keyword Search
→ Hybrid Score + Rank → Top-K Assembly
→ LLM Generation (with system prompt + history + profile)
→ PII Restore → Confidence Check → Bypass or HITL

Подробнее — в Знания и RAG.

Ключевые решения

Изоляция namespace

Каждый отдел владеет своими namespaces с настраиваемыми system prompts, персонами, правилами эскалации и trust-матрицами. Не-глобальные пользователи видят только данные в рамках namespace своего отдела.

Двухуровневая защита PII

  • Ingest-time — односторонняя очистка до хранения чанков и embeddings.
  • Conversation-time — обратимое AES-256-GCM шифрование с PII_ENCRYPTION_KEY; LLM видит плейсхолдеры, ответы пользователю восстанавливают исходные значения.

Матрица доверия

Per-intent трекинг автономности. После достаточного количества успешных утверждений intent-а система начинает отправлять ответы автоматически (с настраиваемым sampling для continuous-валидации).

Гибридный retrieval

Комбинация vector- и keyword-поиска. По умолчанию: 65% vector + 35% keyword, внутри vector-бюджета — split между chunk-embeddings и synthetic question embeddings.