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.
Общие паттерны¶
Во всех кейсах видны общие паттерны:
- SOP задаёт процесс — четкий алгоритм действий
- CoT помогает следовать процессу — модель думает по шагам
- Tools дают доступ к реальным данным — grounding через инструменты
- Опасные действия держит код — Confirm-коллбек +
confirmed_by(гл. 05), а не просьба в промпте - Границы — allowlist — модель физически вызывает только разрешённое (гл. 05, гл. 17)
- Верификация — проверка результата после действий
- Бюджеты на результаты — большие выводы усекаются и уходят в артефакты (гл. 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-механикой
Связь с другими главами¶
- Промптинг: Как создавать System Prompt, см. Главу 02: Промптинг
- Инструменты: Как определять инструменты, см. Главу 03: Инструменты
- Цикл и лимиты: Config/Run-паттерн и флаги инструментов, см. Главу 04: Автономность и циклы
- Безопасность: Confirm-коллбек и
confirmed_by, см. Главу 05: Безопасность - Границы и governance: allowlist, изоляция процесса, права хоста, см. Главу 17: Security и Governance
Что дальше?¶
После изучения кейсов переходите к:
- 16. Best Practices и Области Применения — лучшие практики создания и поддержки агентов