Сценарий: AI-модерация (автоматическая обработка очереди)

NOTE

Статус: Target design. Документ описывает целевую доменную модель. Соответствующий код реализован частично (см. backend/internal/core/) или пока не начат. Правила маркировки — в 50-processes/documentation-standard.md.

Триггер

Любое событие из source BC, которое раньше требовало человека:

  • Matching: ModerationItemAdded(match_review), OrphanItemAssigned.
  • Catalog: ManufacturerAliasProposalCreated, IdentityProfileProposalCreated.
  • Enrichment: EnrichmentReviewRequired (для critical attribute).
  • Supplier Network: InferredRelationshipProposed.
  • Pricing: PriceRuleConflictDetected.
  • Credentials: CredentialGroupCandidateOpened.
  • Customer: LegalInfoVerificationEdge (ИНН ambiguous).

Участники

BC / компонентРоль
Source BCПубликует ModerationItemAdded или специализированное событие через PL.
ModerationOwner. Создаёт ModerationCase, собирает evidence, запускает агента, валидирует, публикует ProposedAction.
AgentRunnerКонфигурация агента per CaseKind: model, prompt, tools, threshold.
External LLMFoundation model в sandbox (no network outside whitelisted RAG, no creds, timeout 30 сек).
RAG storeИндекс похожих кейсов с outcomes (для in-context learning).
Source BC consumerПрименяет ProposedAction через свою команду; публикует DecisionApplied{case_id}.
OperatorТолько при escalation — security-critical или low-confidence fallback.

Sequence diagram

sequenceDiagram
    autonumber
    participant SRC as Source BC
    participant MOD as Moderation
    participant Q as moderation_queue
    participant GE as GatherEvidence
    participant RAG as RAG store
    participant LLM as Sandboxed LLM
    participant V as Validator
    participant K as Kafka (moderation.actions.*)
    participant SC as Source BC consumer
    participant HQ as human_escalation_queue

    SRC->>MOD: ModerationItemAdded
    MOD->>Q: 🟦 CreateCase
    Q-->>MOD: ModerationCaseCreated
    MOD->>GE: 🟦 GatherEvidence(case_id)
    GE->>SRC: read-only queries (canonical, offer, supplier, etc.)
    GE->>RAG: search top-K похожих кейсов
    GE-->>MOD: EvidenceGathered (structured payload)
    MOD->>LLM: 🟦 RunAgent (prompt + evidence + tools)
    LLM-->>MOD: JSON output (verdict, confidence, reasoning, citations, proposed_action)
    MOD->>V: validate schema + citations + ranges
    alt валидно + confidence ≥ threshold + verdict ∈ {accept, reject}
        V-->>MOD: ok
        MOD-->>MOD: AgentDecisionEmitted
        alt verdict = accept
            MOD->>K: publish ProposedAction (case_id correlation)
            K->>SC: consume
            SC->>SC: применить через свою команду
            SC->>K: DecisionApplied{case_id, ack}
            K->>MOD: consume ack
            MOD-->>MOD: case = applied
        else verdict = reject
            MOD-->>MOD: case = closed (no action)
        end
    else невалидно или confidence < threshold или verdict = escalate
        V-->>MOD: fail/low
        MOD-->>MOD: AgentRunFailed (если schema fail)
        Note over MOD: retry до N раз с альтернативным prompt
        alt все retries исчерпаны или verdict = escalate
            MOD->>HQ: 🟧 CaseEscalated
            HQ-->>HQ: notify #tracium-ai-ops
        end
    else verdict = defer
        MOD-->>MOD: waiting (reopen триггер на новые данные)
    end

Шаги (детально)

1. CreateCase

Source BC публикует событие модерации (типизированное per kind). Moderation consumer создаёт ModerationCase со статусом queued. Дедупликация по (source.bc, source.aggregate_ref, kind) — повторное событие на тот же агрегат не создаёт duplicate, обновляет existing case.

2. GatherEvidence (детерминированный код, не LLM)

Запросы по evidence_query из AgentRunner конфига. Per CaseKind — свой набор:

CaseKindEvidence
match_reviewoffer characteristics, candidate canonical, embedding similarity score, classification tags, packaging fingerprint, multi-supplier consensus check, last 30d похожие resolved match decisions
orphan_resolutionoffer characteristics, ближайшие Identity Profiles (matcher partial fit), other orphans с похожими attrs, бренды/категории
inferred_relationship_reviewfrom/to suppliers full info, overlap метрики, observed evidence (raw payloads sample), declared relationships обоих
enrichment_critical_attr_revieworiginal offer description, AI-extracted value, alternative LLM extractions (другая модель / prompt), embedding sanity vs canonical-в-том-же-profile
priority_overlap_reviewobe Price Rules, sample 100 pricing_contexts, результат для каждого order
credential_group_candidateдве credentials (без секретов!), customer info, supplier info, normalized identity field
legal_info_verification_edgeИНН-verify response, открытые источники (FNS API mock), customer registration data
manufacturer_alias_proposalproposed alias, existing aliases для всех manufacturers, embedding сравнение, бренд-каталоги
identity_profile_proposalcluster orphans, common characteristics, потенциальные critical_attribute_keys

Evidence — JSON payload. Hashed для idempotency (evidence_hash).

Безопасность: evidence query ограничен read-only API source BC. Нет прямого PG-доступа. Секреты (auth_payload, password_hash, ПД) — НИКОГДА не в evidence (filter на репозиторном уровне).

3. RunAgent (LLM в sandbox)

prompt = AgentRunner.prompt_template
       + system_instructions("ты модератор Tracium для CaseKind=X, отвечай строго JSON по schema Y")
       + EvidenceGathered (JSON)
       + (опционально) RAG: top-3 похожих resolved кейсов

config:
  temperature: 0
  max_tokens: per kind
  timeout: 30 сек
  function_calling: enforce JSON schema на output
  network: whitelist (RAG store only)
  no_creds: gateway гарантирует
  no_pii_in_logs: redact middleware

Output schema (для всех kinds):

{
  "verdict": "accept | reject | escalate | defer",
  "confidence": 0.0-1.0,
  "reasoning": "короткое объяснение, до 500 символов",
  "citations": ["ссылки на IDs из evidence"],
  "proposed_action": { /* per CaseKind, см. ниже */ }
}

Примеры proposed_action per kind:

// match_review
{ "kind": "MatchUpgrade", "from": "probable", "to": "strong", "second_signal": "embedding_similarity:0.91" }
 
// orphan_resolution
{ "kind": "ResolveOrphan", "assign_to_canonical_id": "uuid", "match_confidence": "probable", "reason": "..." }
// или
{ "kind": "ResolveOrphan", "create_new_canonical": true, "identity_profile_id": "uuid" }
// или
{ "kind": "ResolveOrphan", "mark_unclassifiable": true }
 
// inferred_relationship_review
{ "kind": "ConfirmInferredRelationship", "relationship_id": "uuid", "upgrade_source_to": "declared" }
 
// enrichment_critical_attr_review
{ "kind": "AcceptEnrichment", "characteristic_key": "voltage", "value": "220V", "confidence": 0.92 }
 
// priority_overlap_review
{ "kind": "SuggestPriority", "rule_id": "uuid", "priority": 80, "rationale": "..." }
 
// credential_group_candidate
{ "kind": "MergeCredentialGroup", "primary_credential_id": "uuid", "members": ["uuid", "uuid"] }

4. Validate

  • JSON schema валиден.
  • confidence ∈ [0, 1].
  • citations[] — все IDs существуют (lookup в source BC).
  • proposed_action.kind соответствует ожидаемому per CaseKind.
  • confidence ≥ confidence_threshold агента (default 0.85, configurable).
  • Бизнес-санити: например, для MatchUpgrade(probable→strong) должен быть указан second_signal из 5 разрешённых типов.

Невалидный output → retry с альтернативным prompt. Max 2 retries → AgentRunFailed → escalate.

5. ApplyDecision

Moderation публикует ProposedAction в типизированный topic (например, moderation.actions.matching.v1):

{
  "case_id": "uuid",
  "case_kind": "match_review",
  "action": { "kind": "MatchUpgrade", ... },
  "evidence_hash": "...",
  "model_ref": { "model_name": "...", "version": "..." },
  "confidence": 0.91,
  "emitted_at": "..."
}

Source BC consumer (например, Matching):

  1. Дедупликация по case_id.
  2. Внутренняя команда (например, ApplySecondSignal + MatchUpgrade).
  3. Публикует DecisionApplied{case_id, ack: true}.

Moderation marks case applied. Запись в moderation_decisions_log.

6. Если escalation

Кейс в human_escalation_queue (PG) + push в #tracium-ai-ops. Operator открывает admin UI:

  • Вся evidence как у агента.
  • Reasoning агента (что предлагал и почему confidence низкая).
  • Alternative LLM extractions / похожие кейсы.
  • Кнопки: accept proposed_action / reject / overwrite (свой выбор).

Решение оператора → CaseResolvedByHumanApplyDecision (как обычно). Запись source=human в moderation_decisions_log — основа для drift detection и переобучения.

Edge cases

СлучайПоведение
LLM provider недоступенCircuit breaker. Кейсы copyются в awaiting_llm queue, retry exponential backoff. SLA-alert если > 100 кейсов в queue 30 мин.
Output schema fail после max retriesAgentRunFailed → escalate с reason schema_validation_failed.
proposed_action ссылается на несуществующий IDValidation fail → retry с подсказкой «эти IDs не существуют». Если повтор — escalate.
Source BC не подтвердил DecisionApplied за SLA (например, 60 сек)Moderation marks case apply_pending; alert через 5 мин. Возможный rollback через operator.
Drift: accuracy агента упала ниже X%AgentDisabledByCircuit для этого CaseKind → все кейсы → escalate (временный режим human-only). Trigger переобучения / prompt review.
Новая версия модели deployedSchedule replay deferred + sample 100 ранее resolved (canary): сравнить outputs, если accuracy ≥ — switch full traffic. Иначе rollback.
Race: source BC изменил агрегат пока case в очередиValidate citations при apply: если evidence stale — retry с fresh evidence.
Кейс security-critical (credential_break_glass_decrypt)НЕ вводится в Moderation BC. Это отдельный flow в Credentials с обязательным human 4-eyes. AI может только подсветить аномалию, не принимать решение.
LLM пытается вернуть creds или ПД в reasoningPII-redact middleware в response chain + alert security. Agent run помечается failed.

Инварианты сценария

  1. AI-агент не имеет прямого write-доступа к source BC. Только через published ProposedAction + DecisionApplied ack loop.
  2. Никогда не передаём в LLM: секреты, password, auth_payload, recovery codes, MFA secrets, full ПД (минимизация).
  3. temperature = 0 для всех модерационных агентов → детерминизм.
  4. Replay одного и того же (case_id, evidence_hash, model_ref) даёт идентичный output (verifiable).
  5. Решение агента не финальное в смысле audit: customer / operator может оспорить → CaseReopened с пометкой disputed.
  6. Каждое applied решение можно откатить через source BC compensating команду (например, MatchDowngrade) — Moderation не блокирует rollback.
  7. confidence_threshold per CaseKind фиксирован конфигом; изменение = breaking → pre-prod evaluation.
  8. Security-critical кейсы НЕ автоматизируются (см. Moderation BC invariant #4).

Метрики и observability

  • moderation_cases_total{kind, source} — input rate.
  • moderation_decisions_total{kind, verdict, applied} — outcome distribution.
  • agent_latency_seconds{kind, model_ref} — p95 < 30 сек.
  • agent_confidence_distribution{kind} — histogram.
  • agent_escalation_rate{kind, reason} — alert если spike.
  • agent_accuracy{kind} — vs последующих human override / rollback / customer dispute, окно 7 дней.
  • agent_drift_score{kind} — embedding similarity outputs vs baseline.
  • decision_apply_lag_seconds{kind} — от AgentDecisionEmitted до DecisionApplied.
  • human_escalation_queue_size{kind}, human_resolution_time{kind}.
  • llm_token_cost_total{kind, model_ref} — для FinOps.

Связанные файлы