Контекст: модерация (AI-агенты)

NOTE

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

Назначение

Принимает все кейсы, которые в классической архитектуре требовали бы решения человека (probable match без второго сигнала, weak match, orphan resolution, inferred SupplierRelationship, AI-предложенные characteristics для critical attribute, overlap Price Rules, candidate для CredentialGroup, ИНН-verification edge cases).

В Tracium по умолчанию эти кейсы автоматически разруливаются AI-агентами с детерминированным pipeline (gather context → LLM → validate → emit). Человек подключается только при escalation: confidence ниже порога, противоречивые сигналы, security/compliance scope (security break-glass — единственное место, где человек обязателен по политике).

Главный смысл

Очередь модерации — не «to-do для оператора», а input для AI-агента. Агент работает в детерминированном sandbox: одинаковый input + одинаковая модель + одинаковый prompt → одинаковое решение. Каждое решение объяснимо (cite of evidence) и отзываемо (replay).

Агрегаты / сущности / value objects

ИмяТипНазначение
ModerationCase🟨 AggregateКейс модерации. Корень: case_id. Lifecycle: queued → analyzing → decided → applied или → escalated.
CaseKindVO enummatch_review / orphan_resolution / inferred_relationship_review / enrichment_critical_attr_review / priority_overlap_review / credential_group_candidate / legal_info_verification_edge / manufacturer_alias_proposal / identity_profile_proposal.
CaseSourceVO(bc, aggregate_ref, event_id) — откуда пришло.
CaseEvidenceVOСтруктурированный input агенту: relevant data из source BC + ссылки.
AgentRunnerEКонфигурация агента per CaseKind: model, prompt template, tools, decision schema, confidence threshold, SLA.
AgentDecisionVO(verdict, confidence, reasoning, citations[], proposed_action).
VerdictVO enumaccept / reject / escalate / defer (нужны доп. данные).
ProposedActionVOЧто должно произойти в source BC (например, MatchUpgrade{from: probable, to: strong}).
EscalationPolicyEКонфигурация: когда escalate (confidence < X / repeat fail / security flag) + куда (Slack channel, ticket system).
AgentRunEAppend-only запись одного выполнения агента: input hash, output, latency, model_ref, tokens.
LlmModelRefVO(model_name, version, prompt_hash). Shared Kernel с Enrichment.
HumanEscalationEЗапись escalation: case_ref, reason, assigned_to, resolved_at.

Поддерживаемые типы кейсов

CaseKindИсточникЧто делает агентDefault action
match_reviewMatching: probable без second signalСравнить offer characteristics с canonical, проверить embedding similarity, classification tag, packaging fingerprint, multi-supplier consensus.acceptMatchUpgrade(probable→strong) или reject → leave probable + log
orphan_resolutionMatching: OrphanItemAssignedПопробовать классифицировать в существующий Identity Profile или предложить новый.acceptResolveOrphan или defer → ждать больше offers
inferred_relationship_reviewSupplier Network: InferredRelationshipProposedПроверить inference: пересечение SKU, источники, бизнес-логика.accept → upgrade source declared или reject
enrichment_critical_attr_reviewEnrichment: EnrichmentReviewRequired для critical attrПерепроверить LLM-извлечение через альтернативный prompt + embedding sanity check.accept → publish для Catalog или reject
priority_overlap_reviewPricing: validator при создании ruleПроверить, какой порядок дат лучший результат на 100 sample-контекстов; предложить explicit priority.accept → суггестировать priority operator’у при create или escalate
credential_group_candidateCredentials: partial fingerprint matchПроверить контекст (одна организация / один customer / разные пароли) → решение объединить / нет.acceptMergeIntoGroup или reject
legal_info_verification_edgeCustomer: ИНН-verify вернул ambiguousСверить с открытыми источниками, проверить consistency reg-данных.acceptLegalInfoVerified или escalate
manufacturer_alias_proposalCatalog/Matching: новое написание manufacturerСверить с существующими aliases, embedding similarity, бренд-каталоги.acceptManufacturerAliasAdded или reject
identity_profile_proposalMatching: повторяющиеся orphans с похожими characteristicsПредложить новый Identity Profile с critical_attribute_keys.defer (всегда) → выписка в admin UI для финального review (структурное решение, не auto).

Доменные события

СобытиеПричина
КейсМодерацииСоздан (ModerationCaseCreated)Source BC опубликовал кейс
КейсАнализируется (ModerationCaseAnalyzing)Агент начал работу
СобраныСвидетельства (EvidenceGathered)Pre-LLM фаза: контекст собран из source BC
АгентВынесРешение (AgentDecisionEmitted)LLM вернул verdict + confidence + reasoning
РешениеПримененоВИсходномBC (DecisionApplied)Source BC получил ProposedAction через PL и выполнил
КейсЭскалирован (CaseEscalated)Confidence < threshold / repeat fail / security flag
КейсРазрешёнЧеловеком (CaseResolvedByHuman)Только после escalation
АгентПровалил (AgentRunFailed)Timeout / model error / validation fail
АгентОтключёнCircuit (AgentDisabledByCircuit)Подряд > N провалов / accuracy упала ниже SLA
КейсПереоткрыт (CaseReopened)Replay по новой версии модели или новому evidence

Команды

КомандаАкторЦелевой агрегатРезультат
СоздатьКейс (CreateCase)Source BC consumerModerationCaseModerationCaseCreated
ЗапуститьАгента (RunAgent)WorkerModerationCaseAgentDecisionEmitted или AgentRunFailed
СобратьEvidence (GatherEvidence)WorkerModerationCaseEvidenceGathered
ПрименитьРешение (ApplyDecision)Worker (publishes Action)DecisionApplied (после ack от source BC)
Эскалировать (Escalate)PolicyModerationCaseCaseEscalated
РазрешитьЧеловеком (ResolveByHuman)OperatorModerationCaseCaseResolvedByHuman
Переоткрыть (Reopen)Schedule / OperatorModerationCaseCaseReopened

Pipeline AI-агента

flowchart TD
    A["🟧 ModerationCaseCreated<br/>(из любого source BC)"] --> B["🟦 GatherEvidence"]
    B --> C["🟧 EvidenceGathered<br/>(структурированный input)"]
    C --> D["🟦 RunAgent (LLM call в sandbox)"]
    D --> E{"Output schema валиден?"}
    E -->|нет| F["🟧 AgentRunFailed<br/>(retry с альтернативным prompt)"]
    F -->|повтор N раз| G["🟪 Policy: escalate"]
    E -->|да| H{"confidence ≥ threshold?"}
    H -->|нет| G
    H -->|да| I{"verdict?"}
    I -->|accept/reject| J["🟧 AgentDecisionEmitted"]
    I -->|escalate| G
    I -->|defer| K["🟪 Policy: дождаться доп. evidence"]
    J --> L["🟦 ApplyDecision<br/>(publish ProposedAction в source BC)"]
    L --> M["🟧 DecisionApplied"]
    G --> N["🟧 CaseEscalated → human queue"]

Шаги

  1. GatherEvidence — детерминированный код (не LLM) собирает structured input:
    • Read-only запросы в source BC (Catalog, Offers, etc.) через query API.
    • Embeddings, classification tags, manufacturer aliases.
    • Исторические похожие кейсы (RAG: top-K cases с outcome).
    • Метаданные: case.kind, case.source.event_id, timestamps.
  2. RunAgent (LLM call):
    • Sandbox: timeout 30 сек, no network outside whitelisted RAG store, no creds.
    • Prompt = AgentRunner.prompt_template + EvidenceGathered payload.
    • Function calling: enforce JSON schema на output (verdict + confidence + reasoning + citations + proposed_action).
  3. Validation:
    • JSON schema валиден?
    • confidence ∈ [0, 1].
    • proposed_action соответствует ожидаемому для case.kind.
    • citations[] ссылаются на existing IDs из source BC.
    • Если что-то не так → retry с альтернативным prompt (max 2 retry); потом AgentRunFailed.
  4. Decision routing:
    • accept / reject + confidence ≥ threshold → emit AgentDecisionEmitted.
    • confidence < threshold или verdict = escalateCaseEscalated (даже если verdict = accept — низкая уверенность важнее).
    • defer → ставим waiting; reopen триггер на новые события из source BC.
  5. ApplyDecision — publishes ProposedAction event с case_id correlation:
    • Source BC consumer применяет (например, Matching: MatchUpgrade(probable→strong)).
    • Source BC отвечает DecisionApplied{case_id, ack} через kafka — Moderation marks complete.

Idempotency

  • Каждый AgentRun хешируется по (case_id, evidence_hash, model_ref). Повторный запуск с тем же — идентичный output (model_ref включает temperature=0 для агентов).
  • ApplyDecision идемпотентен: source BC проверяет case_id correlation, не применяет дважды.

Политики

ТриггерРеакция
ModerationItemAdded (Matching / Catalog / Pricing / Credentials / Supplier Network / Enrichment / Customer)CreateCase
ModerationCaseCreatedGatherEvidence
EvidenceGatheredRunAgent
AgentDecisionEmitted + threshold okApplyDecision
AgentDecisionEmitted + confidence < thresholdEscalate
AgentRunFailed подряд N раз для агентаAgentDisabledByCircuit + escalate в #tracium-ai-ops
Daily scheduled (для defer)→ reopen + повторить gather
Новая версия модели (RolesUpdatedAt-аналог для модели)→ schedule replay открытых deferred кейсов
CaseEscalated + case.kind ∈ security_critical→ mandatory human (см. invariants)

Read-модели

  • 🟩 moderation_queue (PG) — текущие кейсы по статусам.
  • 🟩 moderation_decisions_log (CH) — append-only история всех решений: case, evidence, verdict, confidence, model_ref, latency, applied_outcome.
  • 🟩 agent_accuracy_dashboard (CH) — per-agent metrics: accuracy vs human escalation outcomes, drift detection.
  • 🟩 agent_runs_audit (CH) — full input/output для каждого AgentRun.
  • 🟩 human_escalation_queue (PG) — для UI операторов (только escalated кейсы).

Инварианты

  1. Каждое AgentDecisionEmitted имеет (model_ref, prompt_hash, evidence_hash, confidence, reasoning, citations[]). Без них — AgentRunFailed.
  2. Detalism: при тех же (evidence, model_ref, prompt) + temperature=0 — идентичный output. Replay воспроизводим.
  3. Verdict ≠ accept если confidence < threshold агента (configurable per CaseKind, default 0.85).
  4. Security-critical кейсы НЕ автоматизируются: credential_break_glass_decrypt, security_incident_review, legal_compliance_block — здесь только человек (4-eyes), AI выступает только как анализатор/предупредитель. Эти кейсы имеют case.kind ∈ security_critical и EscalationPolicy.always_human=true.
  5. ApplyDecision идемпотентен — source BC дедуплицирует по case_id.
  6. AI-агент не имеет прямого write-доступа к source BC. Только через published ProposedAction event → source BC consumer → policy → команда.
  7. Каждый AgentRunner имеет SLA p95 latency < 30 сек. При нарушении — circuit breaker.
  8. Drift detection: если accuracy агента (vs последующих human override / customer complaints) падает ниже X% за окно — auto-disable + alert.
  9. AgentRun append-only. Старые runs архивируются после 90 дней; aggregate accuracy сохраняется.

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

AgentRunner
├── case_kind                       — для какого CaseKind
├── model_ref                       — (model_name, version)
├── prompt_template_ref             — версионируется
├── temperature                     — фиксировано 0 для детерминизма
├── max_tokens
├── confidence_threshold            — 0.85 default, configurable per kind
├── max_retries                     — 2 default
├── tools[]                         — function calling: lookup_canonical, lookup_supplier, search_similar_cases, embedding_similarity
├── rag_collection_ref              — какая база похожих кейсов
├── evidence_query                  — какие данные собирать в GatherEvidence
├── output_schema                   — JSON schema для verdict
├── escalation_policy_ref
├── enabled
└── version

Изменение prompt / модели / threshold = breaking для accuracy → требует pre-prod evaluation на референсном наборе из 200 ранее resolved кейсов; deploy через blue-green (старый агент не отключается, пока новый не показал ≥ accuracy).

Эскалация на человека (минимизация)

Default — escalation отключена для большинства CaseKind. Включается только если:

  • EscalationPolicy.always_human = true (для security-critical).
  • Confidence ниже floor (0.5 default, ниже даже не пытаемся применить).
  • Circuit breaker сработал (агент disabled).
  • Repeat retries исчерпаны.

Эскалация выписывает в human_escalation_queue + push в #tracium-ai-ops (Slack/Telegram) с full context. Человек разрешает через admin UI; решение записывается в moderation_decisions_log как source=human для последующего обучения / дрифт-метрики.

Интеграционные события (публикуем)

Топик: moderation.events.v1. Partition key: case_id.

ИмяКогда
ModerationCaseCreatedСоздание кейса (для аналитики)
AgentDecisionEmittedКаждое решение
DecisionAppliedПодтверждение применения
CaseEscalatedЭскалация
CaseResolvedByHumanФинал escalation
AgentDisabledByCircuitДля алертов

И — главное: ProposedAction events в типизированных топиках (например, moderation.actions.matching.v1, moderation.actions.catalog.v1) — на них подписаны source BC consumer’ы.

Подписанные интеграционные события

ИсточникСобытиеРеакция
MatchingModerationItemAdded(match_review) / OrphanItemAssignedCreateCase
CatalogModerationItemAdded(manufacturer_alias_proposal/identity_profile_proposal)CreateCase
EnrichmentEnrichmentReviewRequiredCreateCase(enrichment_critical_attr_review)
Supplier NetworkInferredRelationshipProposedCreateCase(inferred_relationship_review)
PricingPriceRuleConflictDetectedCreateCase(priority_overlap_review)
CredentialsCredentialGroupCandidateOpenedCreateCase(credential_group_candidate)
CustomerLegalInfoVerificationEdgeCreateCase(legal_info_verification_edge)
Source BCDecisionApplied{case_id}Mark case applied

Связи в context map

BCПаттернНазначение
Matching / Catalog / Enrichment / Supplier Network / Pricing / Credentials / CustomerCustomer/Supplier (источники → Moderation)Источники публикуют кейсы; не зависят от деталей агентов
Source BC (downstream)PL (Moderation → source)ProposedAction events с case_id correlation
EnrichmentSK (LlmModelRef)Общий kernel для model versioning
External LLM providerACLSandbox-обёртка; смена провайдера не задевает Moderation domain

Мини event storming

flowchart LR
    SRC["🟧 ModerationItemAdded<br/>(из source BC)"]
    subgraph MOD["Moderation"]
        CMD1["🟦 CreateCase"]
        MC["🟨 ModerationCase"]
        E1["🟧 ModerationCaseCreated"]
        CMD2["🟦 GatherEvidence"]
        E2["🟧 EvidenceGathered"]
        CMD3["🟦 RunAgent"]
        AR["🟨 AgentRun"]
        E3["🟧 AgentDecisionEmitted"]
        DEC{"🟪 confidence + verdict?"}
        CMD4["🟦 ApplyDecision"]
        E4["🟧 DecisionApplied"]
        ESC["🟧 CaseEscalated"]
        HQ["🟩 human_escalation_queue"]
    end
    subgraph EXT["External LLM"]
        LLM["⚙️ Sandboxed LLM call"]
    end
    SRCBC["🟧 ProposedAction → Source BC"]

    SRC --> CMD1 --> MC --> E1 --> CMD2 --> E2 --> CMD3
    CMD3 --> LLM
    LLM --> AR --> E3 --> DEC
    DEC -->|accept ≥ threshold| CMD4 --> SRCBC --> E4
    DEC -->|low confidence / security| ESC --> HQ

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