Справочник

Триаж и риск-движок

Двухуровневая фильтрация рисков, маршрутизация агентов и финальное решение: автоответ или остановка на одобрении оператора.

Каждое входящее сообщение проходит один и тот же триаж-пайплайн. Цель — классифицировать риск, выбрать подходящего агента, обосновать ответ в базах знаний и отправлять автоматически только при зелёном вердикте.

Компоненты

  • TriageOrchestrator.processIncoming(ticket) — управляет всем потоком.
  • Router.pick(category, requiredSkills) — выбирает лучшего включённого агента.
  • AgentService.executeAgent(agent, turns, { sources }) — собирает промпт и стримит черновик.
  • RiskAssessor — Layer 1 детерминированные правила и Layer 2 LLM-классификатор.

Поток сообщения

IncomingMessage
  → сохранить сообщение + upsert тикета
  → TriageOrchestrator.processIncoming
      ├── RiskAssessor.layer1(text)    → rules + level
      ├── RiskAssessor.layer2(text)    → { category, risk, confidence,
      │                                  reasoning, requiredSkills }
      │     skipped если layer1 = red
      ├── Router.pick(category, requiredSkills) → Agent
      ├── если agent.knowledgeBaseIds.length > 0:
      │     RAG.search(...) → SourceSnippet[]
      ├── AgentService.executeAgent(agent, turns, { sources })
      │     → собрать промпт (system + language + sources + turn)
      │     → runner.generate(stream) → draft
      ├── сохранить draft агента + risk_assessment
      └── решение по finalLevel:
          ├── green  → отправить в канал, status = auto_replied
          └── yellow | red → status = waiting_operator
                               → operator Inbox → approve / edit / reject

Layer 1 — детерминированные правила

Layer 1 — быстрый rule engine, работает менее 10 мс. Каждое правило — чистая функция (text: string) => { triggered, level, reason }. Правила загружаются из таблицы risk_rules при старте и на riskRules:update.

Встроенные категории:

КатегорияУровеньПримеры
piiyellowemail, международный телефон
credentialsredsk-…, xoxb-…, JWT, PEM, кредитная карта (Luhn)
destructivereddrop table, rm -rf, "удалить всё"
destructiveyellowdisable, "отключить", "забанить"
financialredrefund, lawsuit, "возврат денег"
financialyellowprice, billing, "цена"
accessredgrant access, make admin, "выдать права"
volumeyellowсообщение более 5000 символов, более 10 URL
profanityyellowлёгкий tone screen

Типы правил:

  • regex — строка RegExp.
  • keywords — comma-separated список, case-insensitive, word-boundary.
  • builtin — идентификатор встроенного checker (luhn_credit_card, oversize_message, excess_urls, profanity_lite).

Результат Layer 1:

{ level: 'green' | 'yellow' | 'red', triggeredRules: [...] }

Уровень — максимум из сработавших правил. Нет правил → green, и Layer 2 вызывается.

Layer 2 — LLM-классификатор

Если Layer 1 не red, маленькая classifier-модель (по умолчанию qwen3-0.6b-q4) через grammar выдаёт структурированный JSON-вердикт:

type LLMRiskVerdict = {
  category: 'coding' | 'business' | 'marketing' | 'seo' | 'general' | 'other'
  risk: 'green' | 'yellow' | 'red'
  confidence: number        // 0..1
  reasoning: string         // одна строка для аудита
}

Промпт классификатора хранится в risk_rules_config.llm_prompt и редактируется в Settings → Risk & Triage.

Маршрутизация

Router.pick оценивает включённых агентов:

  1. agent.enabled === true.
  2. Точное совпадение роли (agent.role === category) или agent.role === 'general' как fallback.
  3. Наибольшее пересечение agent.skills с requiredSkills.
  4. Тай-брейк по last_used_at ASC (round-robin).

Финальный вердикт и решение

finalLevel = max(L1.level, L2.risk)
finalCategory = L2.category ?? 'general'
  • green — ответ уходит автоматически.
  • yellow или red — ответ становится тикетом в Inbox оператора. Человек одобряет, редактирует или отклоняет перед отправкой в канал.

Аудит

Каждый вердикт сохраняется в risk_assessments:

  • layer1_result — полный JSON Layer 1.
  • layer2_result — полный JSON Layer 2, или null, если пропущен.
  • final_level, final_category.
  • created_at.

В desktop-приложении откройте тикет в Inbox и раскройте секцию Assessment, чтобы увидеть raw-вердикт.

Конфигурация

Операторы управляют рисками в Settings → Risk & Triage:

  • Добавляйте, редактируйте, включайте и отключайте правила с live preview.
  • Редактируйте промпт Layer 2 классификатора.
  • Встроенные правила помечены is_builtin=true — можно отключить, но нельзя удалить.