Практическое руководство
Как правильно сообщать о сбоях AI-агента
Введение
Сообщение «Internal error» почти бесполезно для владельца AI-агента. Оно подтверждает сбой, но не отвечает на три главных вопроса: что произошло, затронут ли результат и что делать дальше. В итоге владелец либо повторяет операцию вслепую, либо отправляет разработчику скриншот без контекста.
Хорошее уведомление разделяет техническую причину и пользовательское объяснение. Оно содержит безопасный корреляционный идентификатор, по которому можно связать уведомление с журналом выполнения, а также предлагает действие, допустимое именно для этого класса ошибки.
Ниже используется условный агент обработки заявок. Это пример структуры, а не описание реальной системы, клиента или инцидента.
Каким должно быть уведомление
Минимально полезное сообщение состоит из шести частей:
- Понятный заголовок: какой этап не завершён.
- Причина: что известно без догадок.
- Последствие: создан ли результат и можно ли ему доверять.
- Следующее действие: повторить, исправить входные данные или обратиться к оператору.
- Идентификатор: ссылка между интерфейсом, журналом и повторной диагностикой.
- Время события: в однозначном формате с часовым поясом.
Фраза «сервис не ответил за отведённое время» допустима только тогда, когда система действительно зафиксировала тайм-аут. Если причина неизвестна, следует честно написать: «Причину не удалось определить автоматически», а не подменять факт предположением.
Шаг 1. Введите стабильные классы ошибок
Не показывайте владельцу необработанный текст исключения. Сначала сопоставьте техническое событие со стабильным кодом. Код должен описывать класс проблемы, а не конкретную формулировку библиотеки.
{
"AGENT_INPUT_INVALID": {
"retryable": false,
"owner_action": "Исправьте отмеченные входные данные и запустите задачу снова."
},
"DEPENDENCY_TIMEOUT": {
"retryable": true,
"owner_action": "Повторите операцию позже."
},
"AUTHORIZATION_REQUIRED": {
"retryable": false,
"owner_action": "Проверьте подключение и необходимые разрешения."
},
"AGENT_INTERNAL_FAILURE": {
"retryable": "unknown",
"owner_action": "Передайте оператору код события для диагностики."
}
}
Это пример конфигурации. Названия кодов можно изменить, но их смысл не должен неожиданно меняться между выпусками: на них могут опираться интерфейс, оповещения и инструкции поддержки.
Шаг 2. Создавайте идентификатор в начале запуска
Один идентификатор должен сопровождать задачу от входного запроса до вызовов инструментов и итогового уведомления. Не создавайте новый код в каждом обработчике ошибки: иначе цепочка распадётся на несвязанные события.
function startRun(input) {
const runId = generateOpaqueId();
return executeAgent({
runId,
input
});
}
Идентификатор должен быть непрозрачным: не включайте в него email, имя пользователя, текст запроса, токены доступа или другие чувствительные данные. Последовательный номер вроде 4821 тоже нежелателен во внешнем интерфейсе, поскольку позволяет угадывать соседние значения.
Шаг 3. Записывайте структурированное событие
Журнал нужен для диагностики, а не для дублирования пользовательского уведомления. Записывайте код ошибки, этап, попытку, длительность и безопасные признаки состояния. Секреты и полное содержимое пользовательских данных в журнал не помещайте.
{
"timestamp": "2026-07-28T12:40:15Z",
"level": "error",
"event": "agent_step_failed",
"run_id": "run_01JEXAMPLE",
"step": "deliver_result",
"error_code": "DEPENDENCY_TIMEOUT",
"retryable": true,
"attempt": 1,
"duration_ms": 10000,
"result_state": "draft_saved"
}
Значения здесь условные. Поле result_state особенно важно: оно помогает отличить «ничего не создано» от «результат создан, но доставка не подтверждена».
Шаг 4. Формируйте сообщение из фактов
Пользовательский текст удобно строить по шаблону, но значения должны поступать из состояния выполнения:
Заголовок: {failed_operation}
Причина: {verified_reason}
Последствие: {result_state_explanation}
Действие: {safe_next_action}
Код события: {run_id}
Время: {timestamp}
Не передавайте наружу трассировку стека, имена внутренних хостов, пути файлов, SQL-запросы, ключи или исходный ответ внешнего сервиса. Подробности остаются в защищённом журнале с подходящим сроком хранения и контролем доступа.
Шаг 5. Разрешайте повтор только там, где он безопасен
Кнопка «Повторить» подходит не для каждой ошибки. Перед её показом ответьте на два вопроса:
- может ли первый вызов уже быть выполнен, хотя подтверждение не пришло;
- защищена ли операция от создания дублей.
Для изменяющих состояние операций используйте отдельный ключ идемпотентности. Повторная попытка должна отправлять тот же ключ, а не создавать новый:
{
"run_id": "run_01JEXAMPLE",
"operation": "deliver_result",
"idempotency_key": "op_01JEXAMPLE",
"retry_attempt": 2
}
Это пример схемы. Реальная поддержка идемпотентности зависит от вызываемого сервиса. Если гарантии нет, уведомление должно предлагать сначала проверить состояние операции, а не немедленно повторять её.
Повторная диагностика
Владельцу полезна отдельная команда или действие «Проверить состояние». Такая проверка не должна повторно выполнять исходную операцию. Она только собирает текущие сведения по идентификатору запуска.
agentctl diagnose --run-id run_01JEXAMPLE --redact
Команда условная и иллюстрирует безопасный интерфейс: явный идентификатор и обязательное скрытие чувствительных полей. Диагностический результат может включать:
- последний завершённый этап;
- код и время последней ошибки;
- число попыток;
- состояние результата;
- допустимость автоматического повтора;
- проверку доступности зависимости без вывода учётных данных.
Если журнал уже удалён по правилам хранения, диагностика должна сообщить именно об отсутствии данных, а не утверждать, что сбоя не было.
Как проверить результат
Воспроизведите контролируемый сбой на тестовом окружении: например, настройте заглушку зависимости так, чтобы она отвечала медленнее заданного тайм-аута. Не отключайте реальную сеть и не меняйте рабочие учётные данные.
- Запустите задачу с заранее известным тестовым вводом.
- Зафиксируйте идентификатор запуска из уведомления.
- Найдите по нему ровно одну связанную цепочку событий в журнале.
- Убедитесь, что уведомление называет этап, подтверждённую причину и состояние результата.
- Проверьте, что предложенное действие соответствует полю
retryable. - Запустите диагностику и сравните её вывод со структурированным событием.
- Убедитесь, что интерфейс и журнал не раскрывают секреты или содержимое тестового запроса сверх необходимого.
Успешный результат проверки: владелец понимает последствие сбоя и следующее действие, а оператор по тому же коду восстанавливает ход выполнения без запроса дополнительных скриншотов.
Типовые ошибки
- Один текст для всех сбоев
- Сообщение «Что-то пошло не так» безопасно, но не помогает действовать. Добавьте этап, состояние результата и проверенное следующее действие.
- Кнопка повтора по умолчанию
- Повтор после неопределённого результата может создать дубликат. Сначала определите идемпотентность и возможность проверить состояние.
- Новый идентификатор при каждом повторе
- Так теряется связь между исходным запуском и попытками. Сохраняйте идентификатор запуска и отдельно учитывайте номер попытки.
- Техническая причина как инструкция
- Фраза «HTTP 504» не объясняет последствие. Код можно оставить для оператора, но владельцу нужно сообщить, завершена ли операция.
- Секреты в диагностическом пакете
- Автоматически удаляйте токены, cookie, заголовки авторизации и чувствительные поля. Не полагайтесь только на ручную проверку.
- Ложная уверенность
- Если агент не знает, был ли результат доставлен, пишите «доставка не подтверждена», а не «результат не отправлен».
Ограничения
Корреляция не заменяет распределённую трассировку, если задача проходит через несколько независимых систем. Единый идентификатор поможет с поиском, но для точной временной картины могут потребоваться идентификаторы отдельных операций и согласованный формат событий.
Автоматическая классификация также не гарантирует правильную причину. Неизвестные исключения следует относить к общему безопасному классу и уточнять после диагностики. Наконец, подробность уведомления определяется ролью получателя: владелец процесса и инженер эксплуатации могут видеть разные уровни технических сведений.
Итоговая памятка
- Пишите, какой этап не завершён и что стало с результатом.
- Показывайте только подтверждённую причину.
- Предлагайте одно безопасное следующее действие.
- Связывайте уведомление и журнал непрозрачным идентификатором.
- Разделяйте повтор операции и повторную диагностику.
- Не раскрывайте секреты, внутренние пути и необработанные исключения.
Дополнительные практические материалы доступны в разделе «Руководства», а определения терминов — в глоссарии.