Перейти к содержанию

15. Кейсы из Реальной Практики

Зачем это нужно?

В этой главе разберём примеры агентов из разных доменов — с понятным разбором того, как они работают.

Теория полезна, но реальные примеры показывают, как это складывается в рабочую систему. Здесь видно, как все детали (SOP, CoT, Tools, Safety, RAG) работают вместе на практике.

Кейсы используют механику, введённую в ранних главах: Confirm-коллбек и confirmed_by (гл. 05), allowlist инструментов и гарды (гл. 05, гл. 17), Config/Run-паттерн (гл. 04) и бюджеты на tool-результаты (гл. 13). Два кейса разберём подробно, остальные — компактно.

Реальный кейс

Ситуация: Вы хотите создать агента для DevOps, но не знаете, с чего начать.

Проблема: Вы знаете теорию, но не понимаете, как собрать всё вместе: какой System Prompt использовать, какие инструменты нужны, как организовать цикл работы.

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

DevOps Agent

Задача: "У нас проблемы с базой, разберись"

Системный промпт

Ты Senior DevOps Engineer с 10-летним опытом.

Твоя цель — восстановить работоспособность сервисов максимально быстро.

Границы:
- Ты вызываешь только инструменты из allowlist'а хода: команды, которых
  там нет, runtime отклонит с ошибкой — не пытайся их «обойти»
- Перезапуск сервиса — пишущее действие: цикл ставит ход на паузу
  и спрашивает дежурного инженера. Если вызов отклонён — предложи
  альтернативу и объясни риск
- Если данных для решения не хватает — спроси дежурного, а не угадывай:
  неверный регион или лимит создают проблему, которую кто-то будет чинить

SOP для диагностики проблем:
1. Проверь метрики (CPU, Memory, Connections)
2. Прочитай логи (последние 50 строк)
3. Проанализируй ошибки
4. Выдвини гипотезу
5. Примени фикс — write-инструменты выполняются после подтверждения дежурного
6. Верифицируй результат

Обратите внимание: границы объясняют причину, а не запрещают командным тоном. Механику (пауза хода, allowlist) всё равно держит код — промпт лишь помогает модели строить план вокруг реальных границ.

Доступные инструменты

Нейтральный ToolDef из Главы 03, без привязки к SDK:

tools := []ToolDef{
    {
        Name:        "check_db_metrics",
        Description: "Check database metrics: CPU, memory, open connections. The natural starting point for investigating database issues.",
    },
    {
        Name:        "read_db_logs",
        Description: "Read the last N lines of database logs. Use after checking metrics to find the error behind the numbers.",
    },
    {
        Name:        "restart_db_service",
        Description: "Restart the database service: aborts in-flight transactions and drops open connections. Executed only after the on-call engineer approves the call via the Confirm mechanism (chapter 05).",
    },
}

restart_db_service объявляется в реестре хода как пишущий инструмент — с флагом Confirm: true (гл. 04). Description объясняет, что делает инструмент и чем рискован, — а не требует «подтверждения» криком: подтверждение держит код, и строка в описании его не усиливает и не ослабляет.

Подтверждение — механика кода

Никаких «Введите yes» в истории. Цикл перехватывает вызов до выполнения (гл. 05):

// Реестр хода: категория и флаги задаются при объявлении инструмента.
restartTool := Tool{
    Def:     restartDef,
    Confirm: true, // пишущее действие: пауза цикла + решение дежурного
}

// Внутри цикла, до выполнения каждого tool call.
if tool.Confirm {
    d := cfg.Confirm(ctx, call) // вопрос дежурному ВНЕ модели (UI, пейджер)
    if !d.Approved {
        memory.Append(Message{Role: "tool", ToolCallID: call.ID,
            Content: "denied by automatic policy: restart requires on-call confirmation"})
        continue // отказ в истории: модель видит его и меняет план
    }
    out, err = tool.Exec(ctx, call.Arguments, d.ConfirmedBy) // кто подтвердил — подставил runtime
}

confirmed_by — обязательный аргумент инструмента: идентификатор человека из аутентифицированной сессии, который runtime подставляет после явного решения. Пустой confirmed_by или «подтвердил бот» — отказ на уровне кода инструмента. Модель не может подделать это значение: его нет ни в промпте, ни в истории.

Пример выполнения

Ит. Действие агента Результат Что здесь важно
1 check_db_metrics() CPU 95%, connections 1000/100 read-only — выполняется сразу, без человека
2 read_db_logs(lines=50) "ERROR: Too many connections" гипотеза: утечка соединений
3 restart_db_service() отказ: ход на паузе, дежурный отклонил — «сначала покажи, сколько соединений в дропе» модель вызвала пишущий инструмент без доказательств; Confirm сработал до выполнения, отказ вернулся в историю как tool-результат
4 read_db_logs(lines=200), текст: план рестарта и риск дежурный подтверждает модель изменила план после отказа — не переспрашивает, а обосновывает
5 restart_db_service() → confirmed_by="oncall/i.ivanov" Success подтверждение подставил runtime, не модель
6 check_db_metrics() CPU 30%, connections 50/100 верификация: SOP завершён

Учебный момент — итерация 3: модель попыталась применить фикс, не закончив диагностику. Промпт её не остановил (и не обязан был): отказ пришёл из Confirm-коллбека, как tool-результат в историю, и модель корректно перестроила план. Это и есть разница между «просьбой в промпте» и механикой в коде.

Как это устроено в реальном SDK. read_db_logs(lines=100000) не уронит контекст: у цикла есть бюджет на один tool-результат (~128 KB, гл. 13); что не влезло — усекается с маркером, полный вывод уходит в артефакт вне контекста (гл. 11). Поэтому Description обещает «последние N строк», не оговаривая размер: обрезку держит runtime, а не дисциплина модели.

Security Agent (SOC)

Задача: "Алерт: подозрительная активность на хосте 192.168.1.10"

Системный промпт

Ты Security Analyst в SOC (Security Operations Center).

Твоя цель — быстро и точно триажировать алерты безопасности.

Границы:
- Изоляция хоста — действие с необратимыми последствиями для бизнеса:
  цикл ставит ход на паузу, решение принимает дежурный аналитик.
  Вызывай инструмент, когда доказательств достаточно, — паузу держит код
- Собирай доказательства до действий: изоляция по непроверенному алерту
  останавливает рабочий сервис и портит доверие к автоматике SOC
- Генерируй отчёты для аудита: каждое решение должно быть воспроизводимо

SOP для триажа алерта:
1. Определи severity (Low/Medium/High/Critical)
2. Собери доказательства (логи, метрики, трафик)
3. Проанализируй паттерны атаки
4. Определи scope (затронутые системы)
5. Прими решение (False Positive / True Positive)
6. Если True Positive — containment (подтверждение аналитика через Confirm)
7. Сгенерируй отчёт для SOC

Доступные инструменты

tools := []ToolDef{
    {
        Name:        "query_siem",
        Description: "Query the SIEM for logs and alerts. The starting point of any triage: evidence before conclusions.",
    },
    {
        Name:        "check_ip_reputation",
        Description: "Check if an IP address is known malicious or suspicious. Returns no data for internal IPs — absence of reputation is not evidence of innocence.",
    },
    {
        Name:        "isolate_host",
        Description: "Isolate a host from the network: cuts all its connections, including legitimate ones — a false positive stops a working service. Executed only after the analyst approves via the Confirm mechanism (chapter 05).",
    },
    {
        Name:        "generate_report",
        Description: "Generate a security incident report for SOC and audit, with evidence links and the decision trail.",
    },
}

Изоляция хоста: подтверждение и настоящая граница

В наивной реализации агент писал бы «изолировать?» в чат, а строка «yes» из истории считалась бы согласием. Это дыра: в историю попадает не только человек — текст алерта, вывод SIEM, содержимое логов. Injected-текст с «yes» выполнит изоляцию без аналитика.

Правильная механика — та же, что в DevOps-кейсе: isolate_host объявлен destructive, цикл ставит ход на паузу, аналитик подтверждает через свой канал, и runtime подставляет confirmed_by из аутентифицированной сессии. Отказ (никого на линии) — это «automatic policy»: модель не ждёт человека, а меняет план — собирает больше доказательств и эскалирует текстом.

И вторая опора: реальная граница при изоляции — не строка в промпте, а изоляция процесса и права хоста: процесс агента работает от учётки, у которой физически нет прав трогать чужие хосты; изоляция выполняется через узко ограниченный API. Даже успешная инъекция не выводит за эти границы. Полный разбор — в Главе 17: Security и Governance.

Пример выполнения

Ит. Действие агента Результат Что здесь важно
1 query_siem(query="host=192.168.1.10 AND time>now-1h") "Multiple failed login attempts, unusual network traffic" read-only, выполняется сразу
2 check_ip_reputation(ip="192.168.1.10") "Internal IP, no external reputation data" модель не делает вывод «раз репутации нет — виновен»: описание инструмента предупреждает об этом
3 Вывод: "High severity. Pattern: brute-force. Scope: single host" — решение формулируется до действия
4 isolate_host(host="192.168.1.10") ход на паузе → аналитик подтверждает → confirmed_by="soc/a.petrova" → Success подтверждение вне модели; в историю попало бы что угодно — код проверяет только confirmed_by
5 generate_report(incident_id="INC-12345") отчёт с доказательствами решение воспроизводимо для аудита

Учебный момент — итерация 2: пустой результат репутации — типичная ловушка. Модель, обученная «делать выводы из всего», склонна трактовать отсутствие данных как сигнал. Description инструмента закрывает это явно — пример того, зачем описания пишут с причинами.

Как это устроено в реальном SDK. Вывод SIEM-запроса легко содержит токены и пароли, попавшие в логи. Зрелые рунтаймы прогоняют tool-результат через redaction-фильтр до того, как он попадёт в историю: секреты маскируются и в контексте, и в логах, полный вывод остаётся в артефакте с ограниченным доступом. Маскирование по умолчанию, а не по списку полей: фильтруется всё, что похоже на секрет.

Остальные домены: компактный обзор

Три домена ниже устроены по той же схеме (SOP + инструменты + границы в коде) и не дают новых механик — поэтому компактно:

Кейс Инструменты Специфика Главная ловушка
Customer Support get_ticket, search_kb, draft_reply, escalate_ticket тон и эскалация; draft_reply готовит черновик, отправка пользователю — отдельный Confirm содержимое тикета — недоверенный текст: жалоба пользователя может содержать инъекцию, «подтверждение» из тикета не считается
Data Analytics describe_table, sql_select, check_data_quality только read-only SQL; соединение к БД открывается от учётки с правами SELECT «только SELECT» держит учётка БД, а не строка в промпте; без бюджета на результат большой SELECT раздувает контекст (гл. 13)
Product Operations get_feature_spec, check_dependencies, create_release_plan, send_for_approval документы и согласования; send_for_approval — Confirm: решение за стейкхолдерами агент готовит план, но не «согласовывает» его сам: подделка одобрения в истории — не подтверждение

Общий вывод из таблицы: чем бы ни занимался агент, набор безопасных механик не растёт — allowlist, категории инструментов, Confirm + confirmed_by, бюджеты. Меняется только домен и SOP.

Общие паттерны

Во всех кейсах видны общие паттерны:

  1. SOP задаёт процесс — четкий алгоритм действий
  2. CoT помогает следовать процессу — модель думает по шагам
  3. Tools дают доступ к реальным данным — grounding через инструменты
  4. Опасные действия держит код — Confirm-коллбек + confirmed_by (гл. 05), а не просьба в промпте
  5. Границы — allowlist — модель физически вызывает только разрешённое (гл. 05, гл. 17)
  6. Верификация — проверка результата после действий
  7. Бюджеты на результаты — большие выводы усекаются и уходят в артефакты (гл. 13)

Мини-упражнения

Упражнение 1: Создайте System Prompt для вашего домена

Выберите домен (DevOps, Support, Data, Security, Product) и создайте System Prompt по образцу из кейсов:

systemPrompt := `
// Ваш код здесь
// Включите: Role, Goal, границы (с причинами, не запреты капсом), SOP
`

Ожидаемый результат:

  • System Prompt содержит все необходимые компоненты
  • SOP четко описывает процесс действий
  • Границы объясняют, почему они существуют, и ссылаются на механику кода (Confirm, allowlist), а не дублируют её

Упражнение 2: Определите инструменты для вашего агента

Определите набор инструментов для вашего агента:

tools := []ToolDef{
    // Ваш код здесь
    // Включите: read-only инструменты, пишущие (Confirm), destructive (dry-run + Confirm)
}

Ожидаемый результат:

  • Инструменты покрывают основные задачи домена
  • Описания объясняют, что делает инструмент и чем рискован
  • Опасные инструменты объявлены с флагом Confirm и аргументом confirmed_by

Критерии сдачи / Чек-лист

Сдано:

  • Понимаете общие паттерны создания агентов
  • Можете создать System Prompt для своего домена
  • Можете определить набор инструментов с категориями (read-only / пишущие / destructive)
  • Понимаете, как применять SOP, CoT и подтверждение через механику кода

Не сдано:

  • Не понимаете, как собрать все компоненты вместе
  • System Prompt не содержит всех необходимых компонентов
  • Опасные действия держатся строкой в промпте, а не Confirm-механикой

Связь с другими главами

Что дальше?

После изучения кейсов переходите к: