# Human-in-the-Loop для AI-продуктов: когда решает модель, а когда человек

> Фреймворк принятия решений для HITL в AI-продуктах: confidence threshold, risk matrix, паттерны эскалации. Примеры реализации с кодом для production.
> Author: Roman Belov · Published: 2026-04-06 · Source: https://futurecraft.pro/ru/blog/human-in-the-loop/

Полностью автономные AI-системы в production допускают критические ошибки. Добавление human-in-the-loop снижает их число в разы, но увеличивает latency и стоимость обработки.

Вопрос не в том, нужен ли человек в контуре. Вопрос в том, где именно его поставить, чтобы ловить опасные решения и не превращать AI-систему в дорогой интерфейс для ручной работы.

## Когда автономность работает, а когда убивает продукт

Две крайности. Полная автономность: модель решает всё сама, человек видит результат постфактум. Полный контроль: каждый ответ модели проходит ручную проверку до отправки пользователю. Первое масштабируется, но ломает доверие при ошибках. Второе надёжно, но убивает экономику.

Реальные AI-продукты живут между этими полюсами. Задача архитектора: определить, какие решения модель принимает автономно, а какие требуют подтверждения человека.

Три фактора определяют границу:

**Цена ошибки.** Чат-бот рекомендует ресторан с неправильным рейтингом — неприятно. AI-система одобряет кредит на $50 000 по галлюцинирующему анализу — судебный иск. Чем выше стоимость ошибки, тем ниже порог эскалации к человеку.

**Обратимость.** Отправленное push-уведомление не вернуть. Сгенерированный черновик email легко исправить до отправки. Необратимые действия требуют подтверждения.

**Уверенность модели.** Модель с confidence 0.95 ошибается реже, чем с 0.6. Но даже 0.95 означает одну ошибку на двадцать решений. Порог зависит от задачи.

## Confidence Threshold: фреймворк принятия решений

Confidence threshold — числовой порог, ниже которого решение модели уходит на ревью человеку. Звучит просто. На практике требует калибровки под каждый тип задачи.

### Базовая формула

```
ЕСЛИ confidence >= threshold И risk_level == "low"
  → автономное решение
ЕСЛИ confidence >= threshold И risk_level == "high"
  → автономное решение + асинхронный аудит
ЕСЛИ confidence < threshold
  → эскалация к человеку
```

Threshold не фиксированный. Для классификации тикетов поддержки достаточно 0.7. Для медицинской триажной системы нужен 0.95+. Для финансовых решений — 0.99.

### Калибровка порога

Неоткалиброванный порог хуже его отсутствия. Модель, которая выдаёт confidence 0.9 на каждом ответе (включая неправильные), бесполезна для HITL.

Процесс калибровки:

1. Собрать набор из 500–1000 решений модели с confidence scores
2. Разметить каждое решение как правильное/неправильное (ручная разметка или [LLM-as-Judge](/ru/blog/llm-as-judge-automated-quality-gate/))
3. Построить кривую: при каждом пороге — какой процент решений уходит на ревью, какой процент ошибок проходит мимо
4. Выбрать порог по бизнес-требованиям: допустимый процент пропущенных ошибок vs. нагрузка на ревьюеров

```python
from sklearn.metrics import precision_recall_curve
import numpy as np

def find_optimal_threshold(
    confidences: list[float],
    is_correct: list[bool],
    max_error_rate: float = 0.02,  # макс 2% ошибок в автономных решениях
) -> dict:
    """Находит порог, при котором ошибки в автономной зоне <= max_error_rate."""
    confidences = np.array(confidences)
    is_correct = np.array(is_correct)

    thresholds = np.arange(0.5, 1.0, 0.01)
    results = []

    for t in thresholds:
        autonomous = confidences >= t
        escalated = confidences < t

        if autonomous.sum() == 0:
            continue

        error_rate = 1 - is_correct[autonomous].mean()
        escalation_rate = escalated.sum() / len(confidences)

        results.append({
            "threshold": round(t, 2),
            "error_rate": round(error_rate, 4),
            "escalation_rate": round(escalation_rate, 4),
            "autonomous_volume": int(autonomous.sum()),
        })

    # Выбрать наименьший порог, при котором error_rate <= max_error_rate
    valid = [r for r in results if r["error_rate"] <= max_error_rate]
    if not valid:
        return results[-1]  # самый строгий порог

    return min(valid, key=lambda r: r["threshold"])
```

Как может выглядеть результат калибровки (модельные данные для иллюстрации, не замер конкретной системы):

| Порог | Ошибки в автономных | Эскалация | Автономный объём |
|-------|---------------------|-----------|------------------|
| 0.60 | 8.2% | 12% | 8800 из 10000 |
| 0.75 | 3.1% | 28% | 7200 из 10000 |
| 0.85 | 1.4% | 41% | 5900 из 10000 |
| 0.92 | 0.3% | 58% | 4200 из 10000 |

В этом примере порог 0.85 даёт 59% автономной обработки с ошибкой 1.4%. Оставшиеся 41% уходят на ревью. Для большинства B2B-продуктов такой баланс приемлемый — но конкретные цифры зависят от модели и задачи, поэтому кривую строят на своих данных.

## Risk Matrix: второе измерение фильтрации

Confidence threshold работает по одной оси. Risk matrix добавляет вторую: тип и последствия решения. Высокий confidence при высоком риске всё равно требует контроля.

```
                    Low Risk          High Risk
                ┌─────────────────┬─────────────────┐
High Confidence │  AUTO           │  AUTO + AUDIT   │
                │  Полная         │  Автономно, но  │
                │  автономность   │  логируем для   │
                │                 │  выборочной     │
                │                 │  проверки       │
                ├─────────────────┼─────────────────┤
Low Confidence  │  QUEUE          │  ESCALATE       │
                │  В очередь на   │  Немедленная    │
                │  пакетный       │  эскалация к    │
                │  ревью          │  человеку       │
                │                 │                 │
                └─────────────────┴─────────────────┘
```

Четыре зоны — четыре поведения:

**AUTO.** Низкий риск, высокая уверенность. Модель решает, результат отправляется сразу. Примеры: классификация тикетов поддержки, генерация тегов для контента, автодополнение поискового запроса.

**AUTO + AUDIT.** Высокий риск, высокая уверенность. Модель решает автономно, но каждое решение записывается в аудит-лог. Ревьюер проверяет выборку (10–20%) постфактум. Примеры: модерация контента, автоматическое ценообразование, персонализация рекомендаций.

**QUEUE.** Низкий риск, низкая уверенность. Решение уходит в пакетную очередь для ревью. Не срочно, но модель не справляется сама. Примеры: категоризация нестандартных запросов, генерация описаний для edge-case товаров.

**ESCALATE.** Высокий риск, низкая уверенность. Немедленная эскалация к человеку. Блокирует процесс до получения решения. Примеры: подозрение на мошенничество, медицинские рекомендации при неоднозначных симптомах, решения об удалении аккаунта.

### Определение уровня риска

Риск определяется статически (по типу задачи) или динамически (по содержанию запроса).

Статическая классификация:

```python
RISK_LEVELS = {
    "ticket_classification": "low",
    "content_moderation": "high",
    "price_adjustment": "high",
    "search_autocomplete": "low",
    "fraud_detection": "high",
    "tag_generation": "low",
    "medical_triage": "critical",
    "account_deletion": "critical",
}
```

Динамическая классификация — через вторую модель или набор правил. Запрос о возврате товара за $5 — low risk. Запрос о возврате $50 000 — high risk. Та же задача, разный уровень контроля.

```python
def assess_risk(task_type: str, context: dict) -> str:
    base_risk = RISK_LEVELS.get(task_type, "medium")

    # Динамические модификаторы
    if context.get("amount", 0) > 10_000:
        return "critical"
    if context.get("is_new_user", False):
        return max_risk(base_risk, "high")
    if context.get("affects_multiple_users", False):
        return "critical"

    return base_risk
```

## Паттерны HITL в production

Пять паттернов. Каждый решает конкретную архитектурную задачу.

### Паттерн 1: Pre-action Gate

Модель генерирует решение, но не выполняет действие. Человек подтверждает или отклоняет.

```
Запрос → LLM генерирует решение → Gate → [Человек подтверждает] → Действие
                                    ↓
                            [Человек отклоняет] → Feedback → Модель пробует снова
```

Применение: любые необратимые действия. Отправка email от имени пользователя, публикация контента, финансовые транзакции.

Реализация: модель возвращает structured JSON с предлагаемым действием. Система записывает его в очередь ревью. Ревьюер нажимает Approve/Reject. При Approve система выполняет действие. При Reject — feedback возвращается модели для повторной генерации.

```python
class PreActionGate:
    def __init__(self, queue: ReviewQueue, executor: ActionExecutor):
        self.queue = queue
        self.executor = executor

    async def process(self, llm_decision: dict, context: dict) -> str:
        risk = assess_risk(llm_decision["action_type"], context)
        confidence = llm_decision["confidence"]

        if confidence >= THRESHOLDS[risk] and risk != "critical":
            # Автономное выполнение
            return await self.executor.execute(llm_decision)

        # Эскалация
        review_id = await self.queue.enqueue(
            decision=llm_decision,
            context=context,
            priority="urgent" if risk == "critical" else "normal",
        )
        return f"Awaiting review: {review_id}"
```

### Паттерн 2: Post-action Audit

Модель действует автономно. Человек проверяет выборку решений постфактум. Ошибочные решения откатываются или компенсируются.

```
Запрос → LLM → Действие → Лог в аудит
                              ↓
                    Ревьюер проверяет выборку
                              ↓
                    Ошибка → Откат + корректировка модели
```

Применение: высокообъёмные решения с низкой ценой отдельной ошибки. Модерация комментариев, классификация тикетов, генерация метаданных.

Размер выборки зависит от зрелости модели. На старте — 20–30% решений. После стабилизации — 5–10%. При обнаружении деградации — возврат к 20–30%.

### Паттерн 3: Confidence-based Routing

Запросы распределяются между моделью и человеком на основе confidence score. Модель обрабатывает простые кейсы, человек — сложные.

```
Запрос → LLM оценивает → confidence >= 0.85 → Автономный ответ
                        → confidence 0.6-0.85 → LLM отвечает + флаг для ревью
                        → confidence < 0.6    → Человек отвечает
```

Три зоны вместо двух. Средняя зона — модель отвечает сразу (latency не страдает), но ответ попадает в очередь на проверку. Если ревьюер находит ошибку, пользователь получает исправленный ответ.

Этот паттерн эффективен для support-ботов. 60–70% запросов типовые — модель справляется с confidence 0.9+. 20–25% запросов средней сложности — модель отвечает, ревьюер проверяет. 5–15% сложных кейсов — сразу к человеку.

### Паттерн 4: Cascading Validation

Несколько уровней проверки. Каждый следующий дороже, но точнее. Запрос проходит столько уровней, сколько нужно для достижения требуемой уверенности.

```
LLM Generator → Автоматические правила (regex, schema validation)
                  ↓ (прошёл)
              → LLM-as-Judge (вторая модель оценивает)
                  ↓ (прошёл)
              → Автономный ответ

              ↓ (не прошёл на любом уровне)
              → Эскалация к человеку
```

Подробнее о втором уровне — в статье [LLM-as-Judge: автоматический quality gate](/ru/blog/llm-as-judge-automated-quality-gate/).

Каждый уровень отсекает часть ошибок. Автоматические правила ловят очевидные нарушения формата (отсутствие обязательных полей, SQL-injection в ответе, запрещённый контент по стоп-словам). LLM-as-Judge ловит смысловые ошибки: галлюцинации, нерелевантность, нарушение тона. Человек ловит то, что пропустили оба автоматических уровня.

Экономика: автоматические правила обрабатывают 100% запросов за $0. LLM-as-Judge обрабатывает 85% (15% отсеяны правилами) за $0.002–$0.01 на запрос. Человек обрабатывает 5–10% (остальное прошло оба уровня) за $0.50–$2.00 на запрос.

### Паттерн 5: Feedback Loop с обучением

Решения ревьюеров возвращаются в систему для улучшения модели. Со временем модель учится на правках и требует меньше ревью.

```
LLM → Решение → Ревью → [Correct] → +1 к обучающей выборке
                       → [Incorrect] → Корректировка + обучающий пример
                                              ↓
                                    Fine-tuning / prompt update
                                              ↓
                                    Threshold recalibration
```

Feedback loop работает только при структурированном сборе данных. Ревьюер не просто нажимает Reject — указывает причину отказа, правильный ответ, категорию ошибки. Эти данные формируют evaluation dataset для [автоматического мониторинга качества](/ru/blog/llm-as-judge-automated-quality-gate/).

## Реализация HITL-системы: архитектура

Минимальная production-архитектура включает пять компонентов.

```
┌──────────┐     ┌──────────────┐     ┌──────────────┐
│  Client   │────→│  AI Service  │────→│  Review Queue │
└──────────┘     │              │     │  (Redis/SQS)  │
                 │  - LLM call  │     └──────┬───────┘
                 │  - Confidence│            │
                 │  - Risk      │     ┌──────▼───────┐
                 │  - Routing   │     │  Review UI    │
                 └──────────────┘     │  (Dashboard)  │
                        │             └──────┬───────┘
                        │                    │
                 ┌──────▼───────┐     ┌──────▼───────┐
                 │  Action      │     │  Feedback     │
                 │  Executor    │     │  Store        │
                 └──────────────┘     └──────────────┘
```

**AI Service** вызывает модель, получает confidence, определяет risk level, маршрутизирует решение.

**Review Queue** хранит решения, ожидающие ревью. Redis для простых случаев, SQS/RabbitMQ для распределённых систем. Каждое решение в очереди содержит: оригинальный запрос, ответ модели, confidence, risk level, контекст, timestamp, приоритет.

**Review UI** показывает ревьюеру решение модели с контекстом. Ревьюер подтверждает, корректирует или отклоняет. Хороший UI показывает confidence модели, подсвечивает зоны неуверенности, предлагает альтернативы.

**Action Executor** выполняет подтверждённое действие. Идемпотентный — повторный вызов с тем же ID не дублирует действие.

**Feedback Store** собирает решения ревьюеров для обучения. Структурированные данные: решение модели, решение человека, delta, причина корректировки.

## Метрики HITL-системы

Шесть метрик для мониторинга.

| Метрика | Формула | Целевое значение |
|---------|---------|------------------|
| Escalation Rate | эскалации / все запросы | 15-30% (зависит от домена) |
| Auto-resolve Rate | автономные / все запросы | 70-85% |
| Error Escape Rate | ошибки в автономных / автономные | < 2% |
| Review Latency | среднее время ревью | < 5 мин (P95) |
| Reviewer Agreement | согласие с решением модели | > 85% |
| Feedback Utilization | feedback → улучшение модели | месячный цикл |

**Escalation Rate** растёт — модель деградирует или порог слишком строгий. Падает — модель улучшается или порог слишком мягкий.

**Error Escape Rate** — главная метрика безопасности. Если растёт, нужна рекалибровка порога или переобучение модели.

**Reviewer Agreement** ниже 85% означает одно из двух: модель плохо справляется (ревьюеры часто корректируют) или ревьюеры несогласованы между собой (нужна калибровка ревьюеров).

## Антипаттерны

**Threshold без калибровки.** Порог 0.8, установленный «потому что кажется разумным». Без данных о реальных ошибках невозможно определить правильный порог. Начните с ручного ревью 100% решений, накопите данные, откалибруйте.

**Ревью как bottleneck.** Очередь на ревью растёт быстрее, чем ревьюеры обрабатывают. Решения ждут часами. Пользователи не получают ответов. Решение: автоматический fallback — если решение ждёт ревью дольше SLA, отправить ответ модели с пометкой «может быть скорректирован».

**Слепое доверие confidence.** Модели [галлюцинируют с высоким confidence](/ru/blog/truthguard-ai-agents-lie/). Модель уровня GPT-5.6 может выдать 0.95 на фактически неправильном ответе. Confidence из logprobs и confidence из самооценки модели — разные вещи. Logprobs показывают уверенность в выборе токена, а не в правильности ответа. Нужна внешняя калибровка.

**HITL на каждом шаге.** Человек подтверждает каждое решение модели. AI-система превращается в UI для ручной работы. Если 90% решений ревьюер подтверждает без правок — порог слишком строгий.

**Feedback без действий.** Ревьюеры корректируют решения, данные собираются, но модель не улучшается. Каждый месяц: анализ типичных ошибок, обновление промптов, рекалибровка порогов.

## Чеклист: выбор паттерна HITL

Алгоритм для выбора правильного паттерна.

```
1. Действие необратимо?
   ДА → Pre-action Gate (паттерн 1)
   НЕТ → далее

2. Объём > 1000 решений/день?
   ДА → Confidence-based Routing (паттерн 3)
   НЕТ → далее

3. Цена единичной ошибки > $100?
   ДА → Cascading Validation (паттерн 4)
   НЕТ → далее

4. Есть ресурсы на ревью 20-30% решений?
   ДА → Post-action Audit (паттерн 2)
   НЕТ → Confidence-based Routing с высоким порогом (паттерн 3)

Всегда: добавить Feedback Loop (паттерн 5) поверх любого выбранного паттерна.
```

## Итого

Human-in-the-loop — не fallback для плохой модели. Это архитектурный паттерн, который определяет, где AI работает автономно, где под наблюдением, а где уступает место человеку.

Три инструмента: confidence threshold (откалиброванный на реальных данных), risk matrix (статический + динамический уровень риска), паттерн маршрутизации (выбранный по чеклисту). Метрики мониторинга показывают, работает ли система и когда пора рекалибровать.

Начните с Post-action Audit на 100% решений. Через 1–2 недели накопится достаточно данных для калибровки порога. После этого переходите на Confidence-based Routing. Через месяц добавляйте Cascading Validation для высокорисковых решений. Каждый шаг уменьшает нагрузку на ревьюеров и увеличивает автономность модели.

---

*Нужна помощь с проектированием HITL-систем и AI-автоматизацией? Я помогаю стартапам внедрять AI-решения и строить продукты — [belov.works](https://belov.works).*
