16. Best Practices и Области Применения¶
Зачем это нужно?¶
В этой главе разберём лучшие практики создания и поддержки агентов, а также области, где они обычно работают лучше всего.
Знание теории и примеров — это хорошо, но без понимания best practices вы можете совершить типичные ошибки и создать неэффективного или небезопасного агента.
Реальный кейс¶
Ситуация: Вы создали агента для DevOps и запустили его в продакшен. Через неделю агент удалил production базу данных без подтверждения.
Проблема: Вы не реализовали валидацию входных данных и проверку безопасности. Агент выполнил опасное действие без подтверждения.
Решение: Удаление должно было быть destructive-инструментом: dry-run (план: «удалю базу prod, таблиц: 42») + Confirm-коллбек с confirmed_by (гл. 05). Тогда даже кривой промпт не приводит к потере базы — механику держит код. Валидация, safety checks и evals — ниже, по порядку.
Best Practices: Создание агентов¶
1. Начинайте с простого¶
Плохо: Сразу пытаться создать сложного агента со множеством инструментов и многошаговым планированием.
Хорошо: Начните с простого агента с 2-3 инструментами, затем постепенно добавляйте функциональность.
Пример эволюции (нейтральный ToolDef из гл. 03):
// Этап 1: Простой агент (1 инструмент)
tools := []ToolDef{
{Name: "check_status", Description: "Check if a service is running."},
}
// Этап 2: Добавляем инструменты
tools = append(tools,
ToolDef{Name: "read_logs", Description: "Read the last N lines of service logs."},
ToolDef{Name: "restart_service", Description: "Restart a service: drops open connections. Confirmed via the Confirm mechanism (chapter 05)."},
)
// restart_service объявлен в реестре с Confirm: true
// Этап 3: Добавляем сложную логику (SOP, планирование)
systemPrompt = addSOP(systemPrompt, incidentSOP)
2. Чётко определяйте границы ответственности¶
Проблема: Агент пытается делать всё подряд и путается.
Решение: Опишите зону ответственности с причинами. Саму границу держит allowlist инструментов (гл. 05, гл. 17): чего нет в allowlist'е — того модель вызвать не может.
Ты DevOps инженер.
Твоя зона ответственности:
- Проверка статуса сервисов
- Чтение логов
- Перезапуск сервисов (дежурный подтверждает вызов через Confirm)
- Базовая диагностика проблем
Вне зоны ответственности:
- Изменение конфигурации и удаление данных: таких инструментов у тебя нет,
runtime отклонит вызов с ошибкой «unknown tool»
- Операции на production без разрешения дежурного
Модель соблюдает правила, которые понимает, заметно лучше, чем правила капсом. Но помните: промпт объясняет границы — allowlist их держит.
3. Используйте детальные описания инструментов¶
Плохо:
Хорошо:
ToolDef{
Name: "check_service_status",
Description: "Check if a systemd service is running. Use when the user asks about service status, availability, or whether a service is up/down. Returns 'active', 'inactive', or 'failed'.",
}
Почему важно: Модель выбирает инструменты на основе Description. Чем точнее описание (что делает, когда применять, что возвращает, чем рискован), тем лучше выбор. Для опасных инструментов описание объясняет риск — а механику подтверждения держит флаг Confirm в коде, не текст (гл. 05).
4. Всегда валидируйте входные данные¶
Критично для безопасности:
func executeTool(name string, args json.RawMessage, confirmedBy string) (string, error) {
// 1. Инструмент существует и разрешён в этом ходу (allowlist)
tool, ok := toolsByName[name]
if !ok {
return "", fmt.Errorf("unknown tool: %s", name)
}
// 2. Парсим и валидируем аргументы
var params ToolParams
if err := json.Unmarshal(args, ¶ms); err != nil {
return "", fmt.Errorf("invalid JSON: %v", err)
}
// 3. Проверяем обязательные поля
if params.ServiceName == "" {
return "", fmt.Errorf("service_name is required")
}
// 4. Санитизация входных данных
params.ServiceName = sanitize(params.ServiceName)
// 5. Подтверждение — свойство инструмента, а не текст в промпте (гл. 05)
if tool.Confirm && confirmedBy == "" {
return "refused: this tool requires confirmed_by — a human id from an authenticated session", nil
}
return execute(tool, params)
}
Ключевое отличие от наивной версии: проверка опасности опирается на флаг tool.Confirm и аргумент confirmed_by, который runtime подставляет после решения человека (гл. 05). Поиск «yes» в истории (hasConfirmationInHistory) не защищает: в историю попадает недоверенный текст.
5. Реализуйте защиту от зацикливания¶
Проблема: Агент может повторять одно и то же действие бесконечно.
Решение: Границы хода задаются в конфиге цикла, а не константой в теле функции (Config/Run-паттерн, гл. 04):
cfg := AgentConfig{
Limits: Limits{
MaxIterations: 10,
Deadline: time.Hour, // дедлайн хода — терминальная граница
TokenBudget: 100_000,
},
Loop: newLoopDetector(), // N одинаковых вызовов подряд → блокировка, 2N → терминал
}
res := Run(ctx, cfg) // RunResult возвращается и при терминальной ошибке
Детекция повторяющихся действий — задача цикла, а не вашей бизнес-логики. Полный разбор лимитов и recovery — в гл. 04 и гл. 09.
6. Логируйте всё¶
Важно для отладки и аудита:
type AgentLog struct {
Timestamp time.Time
UserInput string
ToolCalls []ToolCall
ToolResults []ToolResult
FinalAnswer string
TokensUsed int
Latency time.Duration
}
func logAgentRun(log AgentLog) {
// Логируем в файл, БД, или систему мониторинга
logger.Info("Agent run", "log", log)
}
Что логировать и как хранить историю, чтобы её можно было восстановить и проиграть заново, — гл. 11: State Management; трейсинг и метрики — гл. 19: Observability.
7. Используйте evals с самого начала¶
Не откладывайте тестирование:
// Создайте базовый набор evals сразу
tests := []EvalTest{
{Name: "Basic tool call", Input: "...", Expected: "..."},
{Name: "Safety check", Input: "...", Expected: "..."},
}
// Запускайте после каждого изменения
func afterPromptChange(ctx context.Context) {
metrics := collectMetrics(ctx, tests) // гл. 08: метрики прогонов
if metrics.PassRate < 90 { // проценты (×100), согласовано с гл. 08
panic("Regression detected!")
}
}
Safety-чек в наборе — это не «модель вежливо просит подтверждение», а «цикл поставил ход на паузу и передал confirmed_by» — тестируйте механику, а не формулировки (гл. 08).
Best Practices: Поддержка агентов¶
1. Версионируйте промпты¶
Проблема: После изменения промпта агент стал работать хуже, но вы не знаете, что именно изменилось.
Решение:
type PromptVersion struct {
Version string
Prompt string
CreatedAt time.Time
Author string
Notes string
}
// Храните версии промптов
promptVersions := []PromptVersion{
{Version: "1.0", Prompt: systemPromptV1, CreatedAt: ..., Notes: "Initial version"},
{Version: "1.1", Prompt: systemPromptV2, CreatedAt: ..., Notes: "Added SOP for incidents"},
}
// Можете откатиться к предыдущей версии
func rollbackPrompt(version string) {
prompt := findPromptVersion(version)
systemPrompt = prompt.Prompt
}
2. Мониторинг метрик¶
Отслеживайте ключевые метрики:
type AgentMetrics struct {
RequestsPerDay int
AvgLatency time.Duration
AvgTokensPerRequest int
PassRate float64
ErrorRate float64
MostUsedTools map[string]int
}
func collectProductionMetrics() AgentMetrics {
// Собирайте метрики из логов
return AgentMetrics{
RequestsPerDay: countRequests(today),
AvgLatency: calculateAvgLatency(),
// ...
}
}
Алерты:
- Pass Rate упал ниже 80%
- Latency вырос более чем на 50%
- Ошибки участились
- Агент зацикливается чаще обычного
3. Регулярно обновляйте evals¶
Добавляйте новые тесты по мере обнаружения проблем:
// Обнаружили проблему: агент вызывает рестарт без достаточной диагностики
newTest := EvalTest{
Name: "Restart requires completed diagnosis",
Input: "Проблемы с базой, разберись",
// Ожидание в контракте чекера гл. 08: Confirm ставит ход на паузу,
// модель добирает доказательства и только потом повторяет запись
Expected: "ask_confirmation",
}
tests = append(tests, newTest)
4. Документируйте решения¶
Ведите документацию. Типовая ошибка в таких записях — фиксировать проблему «в промпте». Правильный фикс — в коде, промпт лишь объясняет причину:
## Известные проблемы
### Проблема: Агент выполнял рестарты без подтверждения
**Дата:** 2026-01-06
**Симптомы:** Агент перезапускал сервисы по первому упоминанию слова «перезапуск» в тикете
**Решение:** Рестарт объявлен пишущим инструментом с флагом Confirm: цикл ставит
ход на паузу и спрашивает дежурного вне модели, решение передаётся в вызов как
confirmed_by (гл. 05). В промпте добавлено объяснение, зачем нужна пауза, —
чтобы модель строила план вокруг неё, а не пыталась её «обойти».
**Статус:** Исправлено в версии 1.2
Почему «добавили просьбу в промпт» — не фикс: инструкция модели не инвариант системы. Ей не следуют при инъекции, её «забывают» в исключительном случае, и ничто не мешает модели сгенерировать «yes» за пользователя. Разбор — в гл. 05.
5. A/B тестирование промптов¶
Сравнивайте разные версии:
func abTestPrompt(ctx context.Context, promptA, promptB string, tests []EvalTest) string {
// Контракт evals гл. 08: подмена system prompt + два прогона collectMetrics
systemPrompt = promptA
metricsA := collectMetrics(ctx, tests)
systemPrompt = promptB
metricsB := collectMetrics(ctx, tests)
fmt.Printf("Prompt A: Pass Rate %.1f%%, Avg Latency %v\n",
metricsA.PassRate, metricsA.AvgLatency)
fmt.Printf("Prompt B: Pass Rate %.1f%%, Avg Latency %v\n",
metricsB.PassRate, metricsB.AvgLatency)
// Выбираем лучший вариант
if metricsB.PassRate > metricsA.PassRate {
return promptB
}
return promptA
}
Практики прод-эксплуатации¶
Когда агент пережил первые релизы, на первый план выходят четыре практики.
Бюджеты на контекст (гл. 13):
- ~128 KB на один tool-результат: что не влезло — усекается с маркером, полный вывод уходит в артефакт (гл. 11);
- лимит картинок в сессии: изображения дороги в токенах и не сжимаются condense'ом;
- параллелизм инструментов ограничивайте памятью потомков:
go testили браузер в tool'е едят RAM вне рантайма — лимитируйте их число, иначе OOM на хосте, а не в цикле.
Секреты:
- секреты приходят из vault'а при сборке/старте, а не из env, прокинутого целиком; если env неизбежен — allowlist переменных, которые попадают в процесс;
- вывод инструментов проходит redaction по умолчанию: маскируется всё, что похоже на секрет, полный вывод — в артефакт с ограниченным доступом.
Ревью субагентом с чистой памятью: финальный ответ (PR, отчёт, план) проверяет отдельный агент с read-only-подмножеством инструментов (запись делает родитель, получив вывод субагента — инвариант гл. 09), чистой историей и инструкцией «найди ошибку» — он не унаследовал уверенность автора в собственном плане.
Гард-тесты и дашборды: инварианты («destructive без confirmed_by невозможен», «allowlist не расширился») фиксируются guard-тестами в CI (гл. 23), поведение — дашбордами метрик и трейсов (гл. 19). Регрессию должна ловить система, а не пользователи.
Как это устроено в реальном SDK. Redaction и бюджет на tool-результат — свойства рантайма, а не договорённости с моделью: фильтр и усечение применяются к результату до записи в историю, а полная версия хранится в артефакте с отдельным доступом. Секретов в env процесса просто нет — они подтягиваются резолвером при старте и в контекст не попадают.
Как это устроено в реальном SDK. Субагент-ревьюер — это тот же цикл, запущенный вторым Run с минимальным Config и пустой историей; корреляция с родительским ходом — общий
run_idв телеметрии (гл. 07). Параллельные инструменты ограничены семафором в рантайме, а не «просьбой не торопиться» в промпте.
Области применения агентов¶
Где агенты наиболее эффективны¶
1. DevOps и Infrastructure¶
Хорошо: диагностика по метрикам и логам, инцидент-менеджмент (триаж, сбор информации), рутинные операции через allowlist.
Примеры: "Проверь статус всех сервисов", "Найди причину падения сервиса X", "Очисти логи старше 7 дней".
Границы: архитектурные решения, любые write-операции без подтверждения дежурного — Confirm-механика, не промпт.
Кейс: управление виртуальными машинами
Парк VM на десятках хостов: инвентаризация, capacity planning, создание и изменение. Инженер — узкое место: недоступен, вручную собирает информацию из разных источников, ошибается в рутине.
Агент решает типовые задачи: инвентаризация ("На каких хостах VM проекта X?"), capacity ("Хватит ли ресурсов на 5 новых VM?"), изменение ("Увеличь память app-01 до 16GB").
tools := []ToolDef{
{Name: "list_vms", Description: "Получить список виртуальных машин. Используй для инвентаризации и поиска VM по имени или проекту."},
{Name: "get_vm_placement", Description: "Получить размещение VM: хост и кластер. Используй для проверки распределения нагрузки."},
{Name: "get_cluster_capacity", Description: "Получить доступные ресурсы кластера (CPU, память, диск). Используй для capacity planning перед созданием новых VM."},
{Name: "create_vm", Description: "Создать VM (имя, CPU, память, диск, хост). Занимает ресурсы кластера и попадает в биллинг — выполняется после подтверждения инженером через Confirm (гл. 05)."},
{Name: "resize_vm", Description: "Изменить ресурсы работающей VM: требует перезагрузки и прерывает сервисы на ней. Выполняется после подтверждения через Confirm."},
{Name: "expand_disk", Description: "Расширить диск VM: необратимо и занимает ёмкость хранилища. Выполняется после подтверждения через Confirm."},
}
SOP для изменения VM: capacity → валидация параметров (runtime проверяет корректность CPU/RAM/disk до выполнения) → Confirm-пауза и решение инженера → выполнение → верификация → отчёт. Все операции логируются для аудита; evals проверяют, что создание и изменение не выполняются без confirmed_by.
Результат: рутина уходит агенту, инженёр остаётся для сложных решений; критичные операции проходят через runtime-валидацию и подтверждение.
2. Customer Support¶
Хорошо: типовые запросы по базе знаний, сбор контекста (версия ПО, ОС, браузер), эскалация.
Примеры: "Пользователь не может войти", "Найди решение проблемы с оплатой".
Границы: эмоциональная поддержка, юридические вопросы, сложные технические проблемы — эскалация на человека.
3. Data Analytics¶
Хорошо: SQL из естественного языка, проверка качества данных, отчёты, тренды.
Примеры: "Покажи продажи за месяц по регионам", "Почему упали продажи в регионе X?".
Границы: только read-only — соединение от учётки с правами SELECT, а не запрет в промпте; интерпретация в бизнес-контексте — человек.
4. Security (SOC)¶
Хорошо: триаж алертов, сбор доказательств, анализ паттернов атак, отчёты об инцидентах.
Примеры: "Триажируй алерт о подозрительной активности", "Проверь репутацию IP".
Границы: изоляция хостов и блокировки — dry-run + Confirm + confirmed_by; реальная граница — изоляция процесса и права хоста (гл. 17).
5. Product Operations¶
Хорошо: планы релизов, проверка зависимостей, документация.
Примеры: "Подготовь план релиза фичи X", "Создай release notes для версии 2.0".
Границы: стратегические решения и согласования — за стейкхолдерами; агент готовит, не решает.
Когда НЕ стоит использовать агентов¶
1. Критичные операции без механики подтверждения¶
Плохо: destructive-инструмент без категории — агент сам удаляет production базу, потому что «в промпте просили быть осторожным».
Хорошо: удаление объявлено destructive: сначала dry-run (план: «удалю базу prod, таблиц: 42»), затем Confirm-пауза и confirmed_by от человека из аутентифицированной сессии (гл. 05).
2. Задачи, требующие творчества¶
Агенты плохо справляются с дизайном интерфейсов, маркетинговыми текстами и архитектурными решениями — там, где нужны креативность, вкус и глубокая экспертиза.
3. Задачи с высокой неопределённостью¶
Лучше всего — когда есть чёткие критерии успеха, SOP и инструменты для получения информации. Хуже всего — когда критериев нет, нужна интуиция или нет доступа к данным.
4. Задачи, требующие эмпатии¶
Агенты не понимают эмоции пользователей и не оказывают эмоциональную поддержку — это остаётся человеком.
Типовые ошибки¶
Большинство типовых ошибок уже разобрано в профильных главах — здесь сводка и место, куда идти:
| Ошибка | Где разобрано |
|---|---|
| Нет валидации входных данных | Гл. 03, Гл. 09 |
| Нет защиты от зацикливания | Гл. 04 |
| Нет логирования и восстановления истории | Гл. 11 |
| Нет мониторинга и трейсинга | Гл. 19 |
| Нет evals | Гл. 08 |
Три ошибки, которые заслуживают разбора именно здесь — потому что встречаются у команд, уже прочитавших всё остальное:
Разбор 1: подтверждение починили «в промпте»¶
Симптом: Инцидент с удалением без подтверждения; в changelog пишут «добавили явную просьбу подтверждать опасные действия в системный промпт»; через месяц инцидент повторяется.
Причина: Инструкция модели — не инвариант системы. Ей не следуют при инъекции (гл. 05), и «yes» в истории мог написать не человек.
Решение: Confirm-флаг на инструменте + confirmed_by как обязательный аргумент. Промпт объясняет причину паузы, чтобы модель строила план вокруг неё. Тест на это — guard-тест: destructive-вызов с пустым confirmed_by должен возвращать отказ.
Разбор 2: секреты утекают через вывод инструментов¶
Симптом: В трейсах и истории видны токены: kubectl get secret вернул базу64-строку, а через неделю она оказалась в экспортированном логе.
Причина: Результат инструмента попал в историю как есть, а env процесса содержал все секреты сразу.
Решение: Redaction по умолчанию для всех tool-результатов (маскируется всё, что похоже на секрет), полный вывод — в артефакт с ограниченным доступом; секреты из vault'а при старте, env — по allowlist'у. Детали — гл. 17.
Разбор 3: регрессию находят пользователи, а не CI¶
Симптом: Незначительное изменение промпта («переформулировал границы») уронило Pass Rate с 92% до 61%, но узнали об этом через две недели по жалобам.
Причина: Evals запускались вручную перед релизом, guard-тестов на инварианты не было.
Решение: Evals в CI на каждый PR (гл. 23) + дашборд метрик с алертами (гл. 19). Правило простое: если регрессию видно на дашборде — вы узнали первым.
Критерии сдачи / Чек-лист¶
Сдано (готовность к продакшену):
- Системный промпт объясняет границы с причинами
- Все инструменты имеют детальные описания
- Реализована валидация входных данных (allowlist + схема + санитизация)
- Лимиты заданы в конфиге цикла (итерации, дедлайн, бюджет)
- Критичные операции — Confirm-флаг +
confirmed_by, не строка в промпте - Логирование всех действий и мониторинг метрик
- Бюджеты: ~128 KB на tool-результат, лимит картинок, ограничение параллелизма
- Секреты: vault при сборке, redaction вывода инструментов по умолчанию
- Создан базовый набор evals; guard-тесты инвариантов в CI
- A/B тестирование промпта и документированные решения
Не сдано:
- Опасные действия держатся просьбой в промпте
- Нет лимитов цикла или они зашиты константой в тело функции
- Нет бюджетов на tool-результаты и redaction
- Нет evals и мониторинга — регрессию находят пользователи
Связь с другими главами¶
- Цикл и лимиты: Config/Run-паттерн, см. Главу 04: Автономность и циклы
- Безопасность: Confirm-коллбек и
confirmed_by, см. Главу 05: Безопасность - Evals: Как тестировать агентов, см. Главу 08: Evals
- Контекст: Бюджеты и усечение, см. Главу 13: Context Engineering
- Observability и CI: см. Главу 19: Observability и Главу 23: Evals в CI/CD
Что дальше?¶
После изучения best practices переходите к:
- 17. Security и Governance — безопасность и управление агентами
- Приложение: Справочники — глоссарий, чек-листы, шаблоны