Process Contract

Контракт процесса — это формальное описание того, что процесс делает, какие входы принимает, какие выходы производит, и какие гарантии даёт.

Концепция

Каждый процесс в clowbot — это не просто функция, а контракт. Контракт хранится в БД и определяет:

  • Что процесс делает (jtbd)
  • Какие входы принимает (input_schema)
  • Какие выходы даёт (output_schema)
  • Какие шаги проходит (steps_expected)
  • Какие SLA гарантирует (sla)
  • Что делать при ошибках (fallback_policy)
  • Как измерять качество (kpi)
  • Кто что видит (visibility)
  • Какие ограничения безопасности (safety_policy)

Rule: если нет контракта — это не process template.

Таблица process_templates

Контракты хранятся в таблице clowbot.process_templates. Она связана с таблицей processes через process_id.

-- Из db/init/210_process_rules_v1.sql
CREATE TABLE clowbot.process_templates (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  process_key text NOT NULL,          -- Уникальный ключ процесса
  version text NOT NULL,               -- Версия контракта (semver)
  process_id uuid REFERENCES processes(id),
  name text NOT NULL,                  -- Человекочитаемое название
  jtbd text NOT NULL,                  -- Job To Be Done описание

  -- Схемы данных
  input_schema jsonb NOT NULL DEFAULT '{}',
  output_schema jsonb NOT NULL DEFAULT '{}',

  -- Ожидаемые шаги
  steps_expected jsonb NOT NULL DEFAULT '[]',

  -- SLA и политики
  sla jsonb NOT NULL DEFAULT '{}',
  fallback_policy jsonb NOT NULL DEFAULT '{}',
  kpi jsonb NOT NULL DEFAULT '{}',
  visibility jsonb NOT NULL DEFAULT '{}',
  safety_policy jsonb NOT NULL DEFAULT '{}',

  metadata jsonb NOT NULL DEFAULT '{}',
  status process_status NOT NULL DEFAULT 'active',
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),

  UNIQUE (process_key, version)
);

Поля контракта

process_key

Уникальный идентификатор процесса. Обычно совпадает с code из таблицы processes.

-- Примеры process_key из БД
'copilot_chat'        -- Основной чат с AI
'web_search'          -- Веб-поиск
'daily_checkin'       -- Ежедневный чекин
'swarm_test'          -- Swarm-тестирование
'agent_orchestrator'  -- Оркестрация агентов

version

Версия контракта в формате SemVer. Позволяет иметь несколько версий одного процесса.

-- При seed создаётся версия 1.0.0
INSERT INTO process_templates (..., version, ...)
VALUES (..., '1.0.0', ...);

-- Уникальность по паре (process_key, version)
UNIQUE (process_key, version)

jtbd (Job To Be Done)

Человекочитаемое описание того, какую задачу решает процесс. Используется для документации и выбора процесса.

-- При seed jtbd берётся из description процесса
COALESCE(NULLIF(btrim(p.description), ''),
         'Process contract seeded from active process registry')

input_schema

JSON Schema входных данных процесса. Определяет структуру того, что процесс принимает на вход.

-- Из db/init/211_process_template_seed.sql
jsonb_build_object(
  'type', 'object',
  'properties', jsonb_build_object(
    'task', jsonb_build_object('type', 'string'),
    'run_id', jsonb_build_object('type', 'string', 'format', 'uuid'),
    'chat_id', jsonb_build_object('type', 'integer'),
    'user_id', jsonb_build_object('type', 'integer')
  ),
  'required', jsonb_build_array('task', 'run_id'),
  'additionalProperties', true
)

Обязательные поля: task, run_id
Опциональные: chat_id, user_id

output_schema

JSON Schema выходных данных. Определяет структуру результата выполнения процесса.

-- Берётся из output_schema процесса
COALESCE(p.output_schema, '{}'::jsonb)

steps_expected

Массив ожидаемых шагов процесса. Каждый шаг имеет ключ, описание и лимит retries.

-- Стандартные 3 шага для всех процессов
jsonb_build_array(
  jsonb_build_object(
    'step_key', 'prepare',
    'description', 'Normalize input and enforce policies',
    'max_retries', 1
  ),
  jsonb_build_object(
    'step_key', 'orchestrate',
    'description', 'Run n8n or local fallback logic',
    'max_retries', 2
  ),
  jsonb_build_object(
    'step_key', 'finalize',
    'description', 'Render answer and write audit records',
    'max_retries', 1
  )
)

prepare

Нормализация входа, проверка политик

orchestrate

Выполнение через n8n или локально

finalize

Рендер ответа, запись в audit

sla (Service Level Agreement)

Гарантии производительности и лимиты выполнения.

jsonb_build_object(
  'latency_ms', jsonb_build_object(
    'p50', 4000,   -- Медиана: 4 секунды
    'p95', 15000   -- 95% за 15 секунд
  ),
  'max_steps', 8,           -- Максимум шагов
  'max_retries_total', 5    -- Всего retries на run
)

fallback_policy

Что делать при недоступности компонентов. Fallback — это first-class behavior.

jsonb_build_object(
  'n8n_unavailable', 'local_fallback_or_degraded',
  'ollama_unavailable', 'degraded',
  'web_timeout', 'partial_results'
)
СитуацияДействие
n8n_unavailablelocal_fallback_or_degraded
ollama_unavailabledegraded
web_timeoutpartial_results

kpi (Key Performance Indicators)

Целевые показатели качества процесса.

jsonb_build_object(
  'success_rate_target', 0.95,      -- 95% успешных runs
  'fallback_rate_target', 0.20,     -- До 20% через fallback
  'redo_rate_target', 0.15,         -- До 15% redo от юзера
  'user_score_target', 4.00,        -- Средний балл >= 4
  'latency_p95_ms_target', 15000    -- p95 latency
)

visibility

Кто какие поля видит. Разделение между user-facing и owner-only данными.

jsonb_build_object(
  'user_fields', ['status', 'message', 'sources'],
  'owner_fields', ['error_text', 'raw_payload', 'events']
)

user_fields

  • status — статус выполнения
  • message — текст ответа
  • sources — источники (RAG)

owner_fields

  • error_text — детали ошибок
  • raw_payload — полный payload
  • events — все события

safety_policy

Ограничения безопасности для процесса.

jsonb_build_object(
  'ssrf_guard_enabled', true,               -- Защита от SSRF
  'pii_masking', true,                      -- Маскирование PII
  'financial_actions_require_owner', true   -- Финансы требуют owner
)

Важно: financial_actions_require_owner = true означает, что LLM не может напрямую выполнять финансовые операции — требуется подтверждение owner.

Связь с таблицей processes

Таблица process_templates связана с processes через внешний ключ.

-- Таблица processes (базовая)
CREATE TABLE clowbot.processes (
  id uuid PRIMARY KEY,
  code text NOT NULL UNIQUE,
  name text NOT NULL,
  description text,
  prompt_template text NOT NULL,
  default_model text NOT NULL DEFAULT 'qwen3:8b',
  n8n_workflow_id text,
  n8n_webhook_path text,
  output_schema jsonb NOT NULL DEFAULT '{}',
  auto_run boolean NOT NULL DEFAULT false,
  status process_status NOT NULL DEFAULT 'draft',
  created_by bigint REFERENCES users(id),
  metadata jsonb NOT NULL DEFAULT '{}',
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

-- Таблица process_templates (контракт)
CREATE TABLE clowbot.process_templates (
  ...
  process_id uuid REFERENCES processes(id) ON DELETE SET NULL,
  ...
);

Views для работы с контрактами

-- mart.vw_process_templates — удобный view
CREATE OR REPLACE VIEW mart.vw_process_templates AS
SELECT
  pt.id,
  pt.process_key,
  pt.version,
  pt.process_id,
  p.code AS process_code,
  pt.name,
  pt.jtbd,
  pt.input_schema,
  pt.output_schema,
  pt.steps_expected,
  pt.sla,
  pt.fallback_policy,
  pt.kpi,
  pt.visibility,
  pt.safety_policy,
  pt.metadata,
  pt.status,
  pt.created_at,
  pt.updated_at
FROM clowbot.process_templates pt
LEFT JOIN clowbot.processes p ON p.id = pt.process_id;

Практические запросы

Получить контракт процесса

SELECT *
FROM mart.vw_process_templates
WHERE process_key = 'copilot_chat'
  AND status = 'active'
ORDER BY version DESC
LIMIT 1;

Все активные контракты с их KPI

SELECT
  process_key,
  version,
  name,
  kpi->>'success_rate_target' AS success_target,
  kpi->>'latency_p95_ms_target' AS latency_target
FROM clowbot.process_templates
WHERE status = 'active'
ORDER BY process_key;

SLA по всем процессам

SELECT
  process_key,
  sla->'latency_ms'->>'p50' AS p50_ms,
  sla->'latency_ms'->>'p95' AS p95_ms,
  sla->>'max_steps' AS max_steps,
  sla->>'max_retries_total' AS max_retries
FROM clowbot.process_templates
WHERE status = 'active';

Связанные страницы