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

Зачем говорить о надёжности агентных систем
Агентная система — это связка LLM + инструменты + окружение, где модель не просто отвечает на вопросы, а сама планирует шаги, вызывает API, ходит в базы данных, запускает задачи и принимает решения на основе обратной связи.
Такие системы уже используют для поддержки клиентов, аналитики данных, internal tooling, автоматизации DevOps, маркетинговых операций и работы с документами. В прототипах они выглядят впечатляюще: пара промптов, несколько инструментов — и кажется, что можно сразу ставить в прод.
Почему прототипы разваливаются в продакшене
В лабораторных демо всё обычно «сходится»: данных мало, запросы контролируемы, нагрузка невысокая, а человек всегда рядом, чтобы подправить ответ. В продакшене всё иначе:
- растёт количество одновременных запросов и цепочек действий;
- появляются редкие и «грязные» кейсы, которых не было в PoC;
- ошибки уже бьют по деньгам, SLA и репутации.
То, что казалось «немного нестабильным», превращается в постоянные падения сценариев, залипшие воркфлоу и трудноотлавливаемые баги.
Откуда берётся нестабильность
Ключевые источники хрупкости агентных систем:
- Сеть: таймауты, недоступность внешних API, дублирующиеся запросы.
- Инструменты: нестабильные SDK, неочевидные побочные эффекты, несогласованные контракты.
- Модель: галлюцинации, нарушение формата, непредсказуемое следование инструкциям.
- Данные: частичные, устаревшие или конфликтующие источники правды.
Без явной архитектуры под эти риски агент ведёт себя как «чёрный ящик», чьи сбои почти невозможно воспроизводить.
Цель статьи
Цель этого материала — показать практичные инженерные приёмы, которые помогают агентным системам не рассыпаться при реальной нагрузке: паттерны повторов и идемпотентности, машины состояний и workflow-оркестрацию, жёсткие контракты инструментов, стратегии обработки ошибок и наблюдаемость.
Дальше по разделам мы разложим эти элементы по полочкам и соберём из них архитектурный каркас, пригодный для продакшена.
Из чего на самом деле состоит агентная система
LLM-вызов против настоящего агента
Одноразовый LLM-вызов — это просто функция:
вход → промпт → один ответ модели → выход.
Нет состояния, нет циклов, нет внешних вызовов. Такой вызов легко масштабировать и отлаживать: запрос либо прошёл, либо нет.
Агент — это уже процесс:
цель → план → серия шагов с инструментами и памятью → результат.
Он делает несколько итераций, принимает решения по ходу, читает и обновляет состояние, ходит во внешние сервисы и может работать долго (минуты, часы, иногда днями через планировщик).
Почему память, инструменты и циклы всё усложняют
Как только вы добавляете:
- память (history, векторное хранилище, БД),
- инструменты (API, базы, очереди, внутренние сервисы),
- итеративный цикл ("пока цель не достигнута"),
вам приходится решать вопросы, которых не было у single-call LLM:
- где хранить и как восстанавливать состояние шага;
- что делать при частичных отказах инструментов;
- как не задублировать действия при повторах;
- как ограничивать длительность, стоимость и побочные эффекты работы агента.
Именно здесь и рождаются проблемы надёжности.
Типовая архитектура агентной системы
Практически всегда можно нарисовать одни и те же блоки:
- Оркестратор агента — управляет циклом: вызывает LLM, выбирает и дергает инструменты, решает, когда остановиться, где поставить retry или таймаут.
- Инструменты — тонкие адаптеры к внешним системам: HTTP‑API, БД, очереди, файловые хранилища, внутренние микросервисы.
- Хранилище состояния — куда кладутся контекст, память, прогресс задачи и техническое состояние (какой шаг сейчас выполняется, какие уже завершены).
- Наблюдаемость — логи шагов, трассировка цепочки вызовов, метрики по каждому запуску агента.
Роль внешних зависимостей
Агент почти никогда не живёт в вакууме. На его надёжность напрямую влияют:
- нестабильные внешние API (rate limit, 5xx, непредсказуемые ответы);
- БД и очереди (задержки, блокировки, потери сообщений);
- планировщики (cron, job-раннеры), которые перезапускают или обрывают задачи.
По сути, агентная система — это не "умный промпт", а распределённое приложение, где LLM — лишь один из компонентов, а не центр вселенной.
Типичные причины провалов агентов в продакшене
Даже аккуратно собранный прототип агента часто разваливается при первых реальных нагрузках. Основные причины почти всегда одни и те же.
Непредсказуемые ответы модели
LLM по природе вероятностна: она может галлюцинировать факты, нарушать формат ответа, зависать на сложных промптах и упираться в таймауты.
Типичные сбои:
- модель игнорирует требования к формату JSON, и парсер падает;
- агент уверенно «выдумывает» данные вместо того, чтобы признать, что их нет;
- длинные цепочки размышлений приводят к превышению токен-лимитов и таймаутам.
Без жёстких проверок формата, валидаторов и ограничений по времени такие ответы быстро приводят к отказам всего сценария.
Хрупкие промпты и отсутствие контрактов на вход/выход
Промпт легко ломается при малейшем изменении: другой язык пользователя, новый тип запроса, дополнительное поле в контексте.
Когда:
- нет строгих схем входа/выхода;
- модель может вернуть «что-то примерно похожее» вместо точного формата;
- изменения промпта не проходят регрессионные тесты,
любой релиз превращается в лотерею. Система зависит от текста промпта сильнее, чем от кода.
Инструменты без ограничений и явных ошибок
Частая проблема — инструменты (API, базы, сервисы), к которым обращается агент, не имеют:
- чётких лимитов (rate limit, число ретраев);
- единого формата ошибок и кодов статуса;
- договорённости, какие ошибки фатальные, а какие — временные.
В итоге агент может зациклиться на бесконечных ретраях, заблокировать внешнюю систему или, наоборот, сдаться при первой сетевой ошибке.
Нет состояния и идемпотентности
Без управляемого состояния агент не может корректно продолжить после сбоя: неизвестно, что уже сделано, что ещё нет, и какой шаг безопасно повторять.
Отсутствие идемпотентности приводит к:
- двойным платежам и дубликатам заявок при повторах;
- рассинхронизации между внешними системами;
- невозможности отката или повторного запуска сценария.
Слабая наблюдаемость
Когда нет нормальных логов, трассировок и метрик, команда видит только «что-то упало».
Без:
- логирования шагов агента и вызовов инструментов;
- сохранения промптов и ответов модели (с обезличиванием, если нужно);
- метрик по ошибкам, таймаутам и ретраям,
невозможно понять, где именно агент ломается, какие сценарии нестабильны и что нужно чинить в первую очередь.
Паттерны повторов и идемпотентности для агентов
Поведение LLM-агента нестабильно по определению, поэтому повторы и идемпотентность — обязательная часть архитектуры, а не «обёртка вокруг HTTP».
Повторы на разных уровнях
Стоит сознательно разделять три слоя повторов:
- HTTP-уровень: сетевые ошибки, таймауты, 5xx, rate limit. Здесь помогают клиентские ретраи с экспоненциальным backoff и джиттером.
- Уровень инструмента: сам tool может падать по временным причинам (БД недоступна, очередь перегружена). Повторы делаем внутри адаптера инструмента, зная его семантику.
- Шаг агента: LLM дал плохой план, не тем параметром вызвал инструмент, вернул полупустой ответ. Здесь повтор — это рестарт шага (или подшага) с учётом сохранённого состояния.
Важно, чтобы эти уровни не умножали повторы бесконтрольно: задавайте лимиты попыток и общий дедлайн на запрос.
Типы ошибок и стратегии
Полезно явно классифицировать ошибки:
- Временные (transient): таймауты, временная недоступность, rate limit. Разрешаем автоматические повторы с backoff.
- Постоянные (permanent): валидация, 4xx, «нет такого ресурса». Повтор бессмысленен — сразу останавливаем шаг.
- Бизнес-ошибки: «недостаточно средств», «лимит заказов исчерпан». Это не сбой системы, а ожидаемый сценарий, который агент должен обработать логикой, а не ретраями.
Стратегия: для transient-ошибок — 3–5 попыток, экспоненциальный backoff с джиттером, общий дедлайн на шаг/запрос (например, 20–30 секунд).
Идемпотентные операции
Чтобы повторы были безопасными, операции должны быть идемпотентны: повторный вызов с теми же входными данными не меняет итоговое состояние.
Приёмы:
- Использовать idempotency key для операций с побочными эффектами (платёж, бронирование).
- Записывать операции в БД как upsert (по ключу) вместо «вставить всегда».
- Делать инструменты так, чтобы они могли ответить «уже выполнено» при повторном вызове.
request_id / step_id для отслеживания повторов
Минимальная схема аудита и идемпотентности шагов агента может выглядеть так:
CREATE TABLE agent_steps (
request_id TEXT, -- внешний запрос / сессия
step_id INT, -- логический шаг агента
attempt INT, -- номер попытки шага
status TEXT, -- pending / success / failed
input_hash TEXT, -- хэш входных данных шага
output_data JSONB,
error_code TEXT,
created_at TIMESTAMPTZ,
PRIMARY KEY (request_id, step_id, attempt)
);
Логика агента:
- Ищет последнюю запись по
(request_id, step_id). - Если статус
successиinput_hashсовпадает — не выполняет шаг повторно, а переиспользует результат. - Если были неуспешные попытки и лимит исчерпан — поднимает ошибку на уровень выше.
Такой подход позволяет безопасно ретраить шаги, не дублируя реальные бизнес-операции.
Использование машин состояний и workflow-оркестрации
Почему «бесконечный цикл агента» опасен
Наивная схема агента часто выглядит так:
while not done:
ответ = LLM(контекст)
выполнить_инструменты(ответ)
обновить_контекст()
Цикл не ограничен явной моделью состояния. Вся «логика», на каком шаге мы находимся, какие инструменты уже вызывались, что можно повторять, а что нет, живёт только в тексте промпта и внутренних «рассуждениях» модели.
Результат:
- зацикливания и хаотичные повторы
- невозможность корректно восстановиться после падения
- трудности с дебагом: непонятно, где именно всё пошло не так
Нужна явная модель состояния вне LLM.
Машина состояний для агента
Машина состояний (FSM) задаёт конечный набор состояний и переходов между ними. Пример высокоуровневых состояний агента:
INIT— получили задачуPLANNING— спланировали шагиEXECUTING_STEP— выполняем текущий шаг / инструментWAITING_EXTERNAL— ждём внешнего события или callbackDONE— задача завершенаFAILED— невосстановимая ошибка
Переходы между состояниями запускаются событиями:
user_request_receivedtool_result_receivedtimeoutvalidation_errorcancel
LLM в этой схеме не «гуляет» как хочет. Он получает текущее состояние и может предложить действие (следующий шаг, набор инструментов), но оркестратор проверяет, допустим ли такой переход и что делать при ошибке.
Бизнес-состояние vs системное состояние
Важно разделять:
- Бизнес-состояние: данные задачи пользователя — корзина, заказ, профиль клиента, статус заявки.
- Системное состояние: где мы в сценарии — текущий шаг workflow, номер попытки, список уже вызванных инструментов, последний код ошибки.
Бизнес-состояние нужно доменной логике и пользователю. Системное — только оркестратору и мониторингу. Разделение упрощает миграции, отладку и повторное выполнение шагов без порчи бизнес-данных.
Хранение и обновление состояния между вызовами модели
Состояние агента должно лежать в надёжном хранилище, а не только в промпте:
- ключ:
task_id/conversation_id - значение: сериализованный объект вида:
{
"fsm_state": "EXECUTING_STEP",
"current_step": "PAYMENT_VALIDATION",
"attempt": 2,
"business_state": { "order_id": 123, "total": 49.9 },
"last_error": null
}
Оркестратор при каждом событии:
- Загружает состояние по ключу.
- Применяет переход FSM (включая логику повторов/ошибок).
- Сохраняет новое состояние транзакционно.
- Только после этого вызывает LLM или инструмент.
Так обеспечивается идемпотентность: при повторном событии (например, дубль callback’а) мы видим, что состояние уже перешло дальше, и просто игнорируем лишний вызов.
Пример упорядоченного workflow
Возьмём сложный запрос: «Оформить кредит и открыть счёт компании».
Workflow можно задать так:
COLLECT_COMPANY_DATA— агент собирает реквизиты и документы.RISK_CHECK— вызывается скоринговый сервис.OFFER_SELECTION— LLM подбирает подходящий продукт по правилам.ACCOUNT_OPENING— вызов внутренних API открытия счёта.CONTRACT_SIGNING— генерация и подписание документов.DONE/FAILED— финальный статус.
Каждый шаг — отдельное состояние. LLM может:
- уточнять данные в пределах
COLLECT_COMPANY_DATA - объяснять пользователю результат
RISK_CHECK
но не может «перепрыгнуть» напрямую к CONTRACT_SIGNING, пока FSM не позволит такой переход.
Такой подход делает поведение агента предсказуемым: последовательность шагов фиксирована, точки ошибок и повторов формализованы, а LLM используется там, где нужна гибкая генерация текста и принятие мягких решений, а не для управления всей жизнью процесса.
Жёсткие контракты инструментов и схемы данных
Агент без жёстких контрактов с инструментами превращается в гадалку: он «примеряет» аргументы и интерпретирует ответы как придётся. Это главный источник скрытых, плохо воспроизводимых багов.
Что такое контракт инструмента
Контракт инструмента — это чётко определённые:
- схема входа: какие поля обязательны, какие опциональны, типы (string/int/float/bool/enum/array/object), форматы (email, URL, дата), единицы измерения (метры vs футы, рубли vs доллары);
- схема выхода: структура ответа, типы полей, возможные варианты статуса, перечень ошибок;
- инварианты: какие значения недопустимы, какие диапазоны считаются корректными, что гарантированно не меняется между вызовами.
Агент не «угадывает» формат, а опирается на этот контракт при планировании и верификации своих действий.
Строго типизированные схемы
Используйте формальные описания вместо «устной договорённости» в коде:
- JSON Schema для описания формата JSON-запросов/ответов;
- pydantic / dataclasses в Python для строгой модели данных на стороне оркестратора;
- при необходимости — Protobuf / Avro для межсервисного взаимодействия.
Схема должна быть единственным источником правды. Генерируйте из неё типы клиента, документацию и подсказки для промптов, чтобы агент и разработчики смотрели на один и тот же контракт.
Коды ошибок и статусы, не только текст
Текстовые сообщения удобны человеку, но бесполезны для стратегии агента. Инструмент должен возвращать машинно-обрабатываемые признаки:
status(например,success | temporary_error | permanent_error | invalid_input);- стабильный
error_codeиз ограниченного набора (enum); - человекочитаемое
error_messageкак дополнение.
Так агент может принимать осознанные решения: повторить запрос, скорректировать аргументы, отключить инструмент или завершить задачу с объяснением.
Валидация до и после вызова
Минимум два уровня проверки:
-
До вызова инструмента: валидация аргументов по схеме.
- Проверка типов и обязательных полей.
- Нормализация единиц (перевод в базовые единицы контракта).
- Логические проверки (дата окончания не раньше даты начала и т.п.).
-
После вызова: валидация ответа.
- Соответствие схемe: нет ли неожиданных полей, не нарушены ли типы.
- Проверка инвариантов (суммы, диапазоны, формат идентификаторов).
Нарушения контракта фиксируйте как ошибку инструмента, а не агента. Это сильно ускоряет отладку.
Эволюция без поломок: неизменяемость и совместимость
Контракты инструментов должны эволюционировать аккуратно. Базовые правила:
- Неизменяемость смысла: не меняйте интерпретацию существующих полей (например, не превращайте
amountиз «в рублях» в «в долларах» без смены имени/версии). - Аддитивность изменений: добавляйте поля, но не удаляйте и не переименовывайте старые без переходного периода.
- Версионирование: при радикальных изменениях — новая версия контракта (
v1,v2) и параллельная поддержка, пока агенты не мигрируют. - Чёткая политика депрекации: логирование использования старых полей, метки
deprecated, отдельные алармы.
Так вы избежите ситуации, когда малозаметное изменение в одном микросервисе приводит к каскадным сбоям всех агентов в продакшене.
Стратегии обработки ошибок и таймаутов в агентной среде
Агентная система живёт в мире ненадёжных сетей, медленных API и непредсказуемых моделей. Если ошибки и таймауты не спроектированы заранее, агент начинает вести себя «магически» и непоследовательно.
Классические проблемы: с чем придётся столкнуться
Для LLM-агентов критичны те же проблемы, что и для микросервисов, но осложнённые стохастичностью модели:
- Таймауты: медленные внешние API, долгие запросы к БД, подвисшие инструменты.
- Частичные сбои: один из инструментов упал, остальные работают; треть запроса выполнилась, остальное — нет.
- Деградация сервисов: рост латентности, лимиты провайдера LLM, троттлинг внешних API, снижение качества ответов.
Если не зафиксировать политику обработки каждого из этих сценариев, агент будет каждый раз «решать с нуля», и ошибки станут хаотичными.
Технические vs бизнес-ошибки
Важнее всего различать два класса ошибок:
- Технические: сеть недоступна, таймаут, HTTP 5xx, ошибка парсинга ответа инструмента, превышен лимит токенов.
- Бизнес-ошибки: «заказ не найден», «нет прав доступа», «лимит бюджета исчерпан», «данные противоречат политике».
Для агента это разные ветки сценария:
- Техническая ошибка — повод повторить, включить fallback или деградацию.
- Бизнес-ошибка — повод менять план: задать уточняющий вопрос пользователю, предложить альтернативу, остановить действие.
Смешивание этих двух типов ведёт либо к бесконечным повторам, либо к бессмысленным отказам.
Circuit breaker, fallback и деградация
Circuit breaker для инструментов агентов работает так же, как и в обычных сервисах:
- При серии неудач по инструменту («пять таймаутов за минуту») вы отключаете его на время.
- Агент получает сигнал: инструмент временно недоступен и должен выбрать другую стратегию.
Вместе с этим нужны явные политики:
- Fallback: альтернативный источник данных, более грубая модель, кеш, чтение из снапшота.
- Деградация качества вместо полного отказа: дать более общий ответ, уменьшить глубину анализа, отказаться от «автодействия» и перейти в «режим подсказок» пользователю.
Главное — описать это как часть протокола агента, а не надеяться, что LLM сам догадается.
Как честно сообщать пользователю о неуспехе
Агент не должен «притворяться, что всё получилось». Нужен явный шаблон сообщений об ошибках, который модель использует в промпте:
- Что пошло не так (без лишних технических деталей).
- Что уже было предпринято (повторы, альтернативные источники).
- Что пользователь может сделать (попробовать позже, изменить параметры запроса, выбрать ручной режим).
Отдельно важно различать:
- Сообщения для пользователя (простым языком, без стек-трейсов).
- Сообщения для разработчиков в логах и трассировке (подробный стек, идентификаторы запросов, параметры).
Хранение причин отказа и контекста
Каждый серьёзный провал агента должен оставлять след:
- Код ошибки и её тип (техническая/бизнес).
- Какой инструмент, с какими параметрами, на каком шаге упал.
- Контекст: фрагмент промпта, идентификатор сессии, id пользователя (если допустимо).
- Что делал агент до и после ошибки (шаги плана, уже выполненные действия).
Эти данные нужны не только для отладки, но и для последующего обучения: по ним можно строить эвристики, улучшать промпты и определять, где агенту вообще не стоило пытаться действовать автоматически.
Наблюдаемость: как увидеть, где и почему агент ломается
Надёжный агент без наблюдаемости быстро превращается в «чёрный ящик». Сначала нужно договориться о сигналах, которые вы собираете.
Ключевые сигналы
- Логи — подробный след принятия решений агентом: шаги планирования, вызовы инструментов, ошибки, ретраи.
- Метрики — агрегированные числа по трафику и качеству работы.
- Трейсы — связанная цепочка шагов одной сессии (distributed tracing для агентов).
- События аудита — кто и когда запустил агента, какие данные затронуты, какие внешние системы использованы.
Метрики, специфичные для LLM-агентов
Помимо стандартных RPS и latency, важны:
- Длина сессии (по времени и по шагам) — не растёт ли она из‑за скрытых циклов.
- Число шагов на задачу — всплеск может означать плохое планирование.
- Частота отказов (task_failure_rate) — доля задач, завершившихся ошибкой или эскалацией к человеку.
- Ошибка инструментов (tool_error_rate) — проблемы интеграций, смена схемы, таймауты.
Разметка логов
Каждый лог‑запись должна содержать чёткий контекст:
{
"trace_id": "...",
"user_id": "...",
"task_id": "...",
"step_id": 7,
"agent_name": "support-bot",
"tool": "crm.lookup",
"level": "error"
}
Без таких идентификаторов сложно понять, где именно сломался сценарий.
Промпты, ответы и приватность
Логируйте промпты и ответы частично и с маскированием:
- вырезайте или хэшируйте PII (email, телефоны, номера карт);
- храните образцы (sampling), а не 100% трафика;
- отделяйте логи для отладки от логов для аудита доступа.
Алерты на патологии агента
Минимальный набор триггеров:
- всплеск ошибок инструментов или рост tool_error_rate;
- рост времени ответа или медианного числа шагов;
- аномальный рост длины сессий — признак циклов без выхода;
- серия неуспешных задач по одному типу сценария (task_type + failure).
Такие алерты позволяют поймать момент, когда агент начал «ломаться», задолго до жалоб пользователей.
Тестирование, песочницы и эксперименты с агентами
Надёжность агента начинается не с продакшена, а с того, насколько безопасно и системно вы умеете на нём экспериментировать.
Песочница и тестовое окружение
Агенту нужна полноценная песочница:
- отдельные аккаунты и базы данных,
- тестовые ключи внешних API,
- синтетические или анонимизированные данные,
- жёсткие квоты и ограничение прав.
В песочнице вы проверяете рискованные стратегии (новые инструменты, автодействия без подтверждения пользователя) и паттерны восстановления после сбоев, не рискуя реальными деньгами и данными.
Юнит-тесты: промпты, схемы, ошибки
Для агентных систем юнит-тесты — это не только про код:
- Промпты: фиксируйте примеры входов/выходов и проверяйте, что структурированный ответ модели соответствует ожиданиям.
- Схемы: валидируйте JSON-схемы и контракты инструментов; любой breaking change должен падать тестами.
- Ошибки: тестируйте разбор нестандартных ответов, пустых результатов, частичных данных.
Температура модели в тестах — 0, чтобы минимизировать вариативность.
Сценарные тесты и record & replay
Сценарные (end-to-end) тесты фиксируют последовательность шагов агента: запросы к модели, ответы, вызовы инструментов.
Подход record & replay:
- Один раз выполняете сценарий и записываете ответы LLM.
- В последующих прогонках «проигрываете» эти ответы из файла.
Так вы проверяете логику оркестрации и обработки состояний, не упираясь в нестабильность модели и квоты провайдера.
Нагрузка и моделирование сбоев
Нагрузочные тесты для агентов важны по двум причинам:
- всплывают проблемы с очередями, таймаутами и конкурирующими апдейтами состояния;
- видны реальные задержки при цепочках инструментов.
Добавьте моделирование сбоев внешних сервисов: задержки, 5xx, кривые ответы, частичную недоступность. Это позволяет проверить стратегии повторов, обратных откатов и переключения на деградированный режим.
Эксперименты и A/B-тесты в проде
Даже хорошая песочница не заменяет эксперименты на реальном трафике.
Практики:
- Shadow-mode: новый агент получает те же запросы, но не влияет на пользователя, лишь логируется.
- A/B-тесты: часть пользователей идёт через старую стратегию, часть — через новую; меряются бизнес‑метрики и частота ошибок.
- Feature flags: возможность быстро откатить неудачный вариант.
Так вы эволюционируете агента по шагам, удерживая риск под контролем.
Деплой и конфигурация надёжных агентных систем
Продакшен-агент — это не только prompt и модель, но и дисциплина деплоя. Ошибки здесь бьют по устойчивости не хуже багов в коде.
Лимиты, таймауты и ретраи по окружениям
Для LLM-агентов критично конфигурировать «ограничители» отдельно для dev, staging и prod:
- лимиты запросов к LLM-провайдеру и внешним API;
- максимальная глубина цепочки вызовов инструментов;
- таймауты на шаг агента и на отдельные инструменты;
- стратегии повторов (кол-во, backoff, какие ошибки ретраить).
На dev можно разрешить более длинные таймауты и детальные логи, на prod — агрессивнее резать по времени, но с продуманными ретраями и fallback’ами. Конфигурацию лучше хранить в одном формате (например, YAML/JSON), но с различными профилями окружений.
Конфигурация как код + переменные окружения
Основной принцип — «конфигурация через код»: все важные значения описаны в репозитории и проходят code review. Сюда входят:
- параметры оркестрации (конкурентность, очереди, политики перезапуска);
- схемы маршрутизации трафика между версиями агентов;
- включение/отключение отдельных инструментов.
Переменные окружения используются для чувствительных и быстро меняющихся вещей: ключи, URL сервисов, лимиты, привязанные к инфраструктуре. Так вы сохраняете повторяемость и при этом можете оперативно менять настройки без релиза.
Миграции состояния и контрактов без даунтайма
У агентов часто есть долговременное состояние: сессии, контексты, прогресс workflow. Чтобы не «ронять» прод при изменении схем:
- делайте эволюционные миграции: сначала добавить новые поля, потом начать их использовать, и только потом удалять старые;
- обеспечьте backward compatibility: старая версия агента должна уметь читать новые записи хотя бы частично;
- при изменении контрактов инструментов вводите версионирование API:
/tools/report/v1,/tools/report/v2и поэтапно переводите трафик.
Хорошая практика — blue‑green или canary‑деплой: часть трафика уходит на новую версию агента, и при проблемах откат занимает минуты.
Feature flags и версионирование агентов
Новые возможности агента лучше включать через feature flags:
- rollout по проценту пользователей;
- включение по регионам или типам клиентов;
- быстрый kill‑switch при некорректном поведении.
Версионируйте не только код, но и:
- «идентичности» агентов (agent_checkout:v1, v2);
- схемы сообщений и форматов контекста;
- версии инструментов и их контрактов.
Одновременно держите несколько поколений: новая версия обкатывается на части трафика, старая остаётся безопасным fallback’ом. Это делает эволюцию агентной системы прогнозируемой, а инциденты — управляемыми.
Анти-паттерны и границы применимости агентных архитектур
Агентная архитектура легко превращается в дорогостоящий эксперимент, если не договориться заранее о границах, ответственности и рисках. Ниже — типичные ловушки и ориентиры, когда агенты действительно уместны.
Типичные анти‑паттерны
1. «Агент умеет всё»
Один универсальный супер‑агент с инструкцией «решай любые задачи»:
- смешивает бизнес‑логику, оркестрацию и доступ к инструментам в одном промпте;
- плохо тестируется: непонятно, что именно сломалось;
- эволюционирует хаотично: добавление нового кейса ломает старые.
2. Монолитный промпт вместо архитектуры
Вся логика зашита в один длинный системный промпт:
- нет явных модулей и интерфейсов — только текст;
- невозможно переиспользовать части поведения;
- любое изменение требует регрессионных тестов «всего и сразу».
Это «монолитный промпт» — аналог монолитного приложения без слоёв и сервисов.
3. Скрытые побочные эффекты инструментов
Инструменты:
- меняют данные без явного указания в контракте (например, «getUser» ещё и обновляет статус);
- неидемпотентны, но вызываются повторно при ретраях;
- маскируют сетевые и бизнес‑ошибки под «успех».
Агент в такой среде неотличим от хаотичного скрипта, а не от управляемого компонента.
4. Чрезмерная автономия без ограничений
Агенту разрешено всё: любой инструмент, любая длительность сессии, любой объём запросов наружу. Это ведёт к:
- бесконечным или очень длинным петлям размышлений;
- непредсказуемой стоимости;
- действиям за пределами ожидаемого сценария (например, изменение прод‑данных в экспериментальном режиме).
Как приручить сложность: границы и роли
Разбивайте на специализированные роли:
- планировщик (формулирует план шагов);
- исполнитель (вызывает инструменты по плану);
- проверяющий / критик (валидирует результат против формальных критериев).
Вместо одного «агента на всё» лучше несколько агентов или модулей с узкой зоной ответственности и явным контрактом.
Ограничивайте:
- список доступных инструментов и прав;
- максимальное число шагов и время сессии;
- бюджет (количество токенов / стоимость / число внешних вызовов).
Явно фиксируйте, что агент не делает: не пишет в прод‑БД, не шлёт письма клиентам, не меняет конфигурацию без дополнительного подтверждения.
Когда агенты не нужны
Откажитесь от агентной архитектуры в пользу детерминированной логики, если:
- процесс жёстко формализован и меняется редко (чёткие правила, чек‑листы, расчёты);
- важнее предсказуемость и простота аудита, чем гибкость;
- задача сводится к простой трансформации данных, конвертации форматов, валидации по фиксированным правилам;
- можно описать решение как несколько понятных if/else или конечный автомат — и этого достаточно.
Во многих случаях достаточно обычного LLM‑запроса, RAG‑слоя или классического сервиса с чёткими правилами. Агентная архитектура окупается там, где есть высокая вариативность задач, необходимость адаптации по ходу выполнения и ценность частичной автоматизации сложных, слабо формализованных процессов.
Чек-лист для запуска агента, который не развалится в проде
К агенту в проде требования простые: не терять деньги, данные и нервы команды. Ниже — концентрированный чек-лист и базовый шаблон, с которого разумно начинать.
Базовый архитектурный шаблон
Минимальный прод-вариант может выглядеть так:
- API-слой (HTTP/gRPC), принимающий запросы и возвращающий ответы.
- Оркестратор агента (service/worker), который держит логику шагов и вызовов LLM.
- Хранилище состояния (БД/kv-store) для сессий, шагов, контекста.
- Слой инструментов (микросервисы, функции), вызываемых агентом через чёткие контракты.
- Наблюдаемость: централизованные логи, метрики, трассировка.
Всё остальное (сложные воркфлоу, многоагентность, стриминг и т.п.) добавляется только после того, как этот базис стабильно работает.
Чек-лист надёжности
Повторы и идемпотентность
- Есть ли idempotency-key на запрос/шаг?
- Можно ли безопасно повторить вызов инструмента/LLM без побочных эффектов?
- Настроены ли политики ретраев (что повторять, а что нет)?
Состояние и переходы
- Все важные шаги пишутся в хранилище (state machine / workflow id, статус, вход/выход)?
- Есть ли ограничение на глубину/количество шагов, чтобы агент не зациклевался?
Контракты инструментов и данных
- Для каждого инструмента описана схема входа/выхода (JSON Schema / pydantic и т.п.)?
- LLM промпт жёстко привязан к этой схеме и проверяется на валидность ответа?
Ошибки, таймауты, деградация
- У каждого вызова есть таймауты и понятная стратегия: повторить, зафейлить, вернуть упрощённый ответ?
- Есть graceful degradation: что делает агент, если ключевой инструмент недоступен?
Наблюдаемость и тесты
- Логируются ли все шаги агента с корреляцией по request_id/session_id?
- Есть технические метрики: время ответа, частота ошибок, число шагов на запрос?
- Есть юнит- и интеграционные тесты хотя бы для основных сценариев и инструментов?
Конфигурация и запуск
- Промпты, ключи моделей, лимиты — в конфиге, а не в коде?
- Есть sandbox-окружение, где можно погонять агента на реальных событиях перед выкладкой?
Эволюция: от простого к сложному
- Сначала один агент, один основной сценарий, минимальный набор инструментов.
- Меряем ценность: сокращение ручного труда, SLA ответов, частоту эскалаций к человеку.
- Лишь после стабилизации добавляем новые инструменты, сложные воркфлоу, многоагентные схемы.
Надёжность здесь — не «магия ИИ», а дисциплина: код-ревью на промпты и схемы, контроль изменений конфигурации, регулярный просмотр логов и инцидентов. Команда, которая следует этому чек-листу, получает не эксперимент, а рабочий продукт.
FAQ
С чего практически начать, если у нас уже есть прототип агента, но мы боимся выводить его в прод?
Начните с минимально полезного и наблюдаемого сценария.
- Определите один конкретный бизнес-кейс:
- чёткий вход (какие запросы поддерживаем);
- ожидаемый выход (что считается успехом).
- Разделите архитектуру:
- тонкий API‑слой;
- оркестратор агента (шаги, состояние, ретраи);
- слой инструментов с контрактами;
- БД/kv-store для состояния.
- Введите базовые ограничения:
- максимальное количество шагов и токенов на задачу;
- таймауты и лимиты на вызовы инструментов.
- Добавьте наблюдаемость:
- логи по шагам с request_id / task_id;
- метрики ошибок и времени ответа.
- Тесты и песочница:
- прогоните ключевые сценарии на тестовых данных;
- сделайте shadow‑режим или A/B на малой доле трафика.
Когда один сценарий стабилен, расширяйте набор задач и инструментов поэтапно, а не «включайте всё сразу».
Как понять, когда вообще стоит использовать агента, а когда достаточно обычного LLM или простого сервиса?
Используйте агента только там, где нужна вариативность и принятие «мягких» решений.
Оставьте обычный LLM / RAG / правила если:
- процесс стабилен и хорошо формализован (чёткие шаги, мало ветвлений);
- важна жёсткая предсказуемость и простой аудит;
- задача — форматирование, извлечение фактов, поиск по документам.
Имеет смысл агентная архитектура, если:
- шаги и порядок действий зависят от контекста и меняются по ходу;
- нужно сочетать несколько инструментов и источников данных;
- ценна частичная автоматизация сложного процесса (подготовка, сбор данных, черновики решений).
Практический фильтр: если можно честно описать задачу как конечный автомат или набор if/else — начните с этого, а агента добавляйте только для плохо формализуемых участков (например, общение с пользователем или выбор стратегии).
Как реализовать идемпотентность для операций с побочными эффектами (платежи, заявки, изменения данных)?
Цель — чтобы повторный вызов не создавал новых побочных эффектов.
Основные приёмы:
-
Idempotency key:
- генерируете
operation_id(или берёте внешнийrequest_id); - передаёте его во все опасные инструменты (платежи, бронирования);
- инструмент хранит у себя этот ключ и при повторе отвечает «уже выполнено» с тем же результатом.
- генерируете
-
Запись операций в БД:
- используйте upsert по
operation_idвместо «insert всегда»; - храните статус (
pending/success/failed) и параметры вызова.
- используйте upsert по
-
Логика агента:
- перед выполнением шага ищите запись по
operation_id; - если уже
success— не выполняете действие повторно, а берёте сохранённый результат; - если были неудачные попытки и лимит исчерпан — поднимаете управляемую ошибку.
- перед выполнением шага ищите запись по
-
Контракты инструментов:
- явное поле
idempotency_keyв схеме; - документированное поведение при повторном вызове.
- явное поле
Так вы можете смело добавлять ретраи без риска двойных платежей и дубликатов заявок.
Как правильно описывать и внедрять контракты инструментов, чтобы ими надёжно пользовался агент?
Контракт должен быть одинаково понятен и коду, и модели.
-
Формализуйте контракт:
- опишите вход/выход в JSON Schema или pydantic‑моделях;
- зафиксируйте типы, обязательные поля, диапазоны и форматы;
- введите
statusи ограниченныйerror_code, а не только текст ошибок.
-
Встроите контракт в промпты:
- включайте в системный промпт выдержку схемы аргументов и ответа;
- просите модель возвращать строго структурированный JSON по этой схеме;
- приводите 2–3 примера корректных вызовов.
-
Валидация:
- до вызова: проверяйте сгенерированные моделью аргументы по схеме, при ошибке — просите модель «исправить ввод»;
- после вызова: проверяйте ответ инструмента, нарушения логируйте как ошибку интеграции.
-
Эволюция:
- только аддитивные изменения (новые поля, не ломая старые);
- версионируйте API (
v1,v2), если меняется смысл полей.
Так агент перестаёт «угадывать» формат и работает по тем же правилам, что обычные сервисы.
Как ограничивать стоимость и ресурсы агентной системы (токены, время, внешние API)?
Нужно ограничивать и глубину рассуждений, и обращения к внешним ресурсам.
Что контролировать:
-
Время и шаги:
- максимальный таймаут на запрос пользователя;
- лимит шагов агента на одну задачу (например, 10–20);
- ограничение длительных workflow общим дедлайном.
-
Токены и вызовы моделей:
- лимит токенов на вход и выход для каждого шага;
- ограничение числа LLM‑вызовов на задачу;
- более строгие лимиты на дорогие модели, fallback на дешёвые.
-
Инструменты:
- per‑tool rate limit и общее ограничение внешних API‑вызовов;
- circuit breaker при частых ошибках.
-
Конфигурация:
- все лимиты в конфиге (per‑env: dev/stage/prod), а не в коде;
- возможна динамическая настройка через feature flags.
Агент должен уметь честно завершать сценарий при превышении бюджетов и объяснять пользователю, что было сделано и что осталось несделанным.
Какие элементы наблюдаемости нужно внедрить в первую очередь, чтобы понимать, где агент ломается?
Сделайте минимальный, но связный набор сигналов.
Минимум, что стоит внедрить сразу:
-
Корреляция:
trace_id/request_id/task_idво всех логах;step_id, имя агента, имя инструмента.
-
Логи:
- каждый шаг агента: план, вызванные инструменты, статусы, ошибки;
- ключевые фрагменты промптов и ответов (с маскированием PII).
-
Метрики:
- время ответа по типам задач;
- доля неуспешных задач (failure / escalation rate);
- ошибка инструментов по каждому tool (
tool_error_rate); - среднее число шагов на задачу.
-
Алерты:
- всплеск ошибок инструментов;
- рост времени ответа или числа шагов;
- аномальный рост длины сессий (зацикливания).
Это уже позволяет быстро локализовать: «сломался агент целиком, один сценарий или конкретный инструмент».
Как безопасно менять промпты и логику агента, чтобы не сломать продакшен?
Разделите тестирование на уровни и держите изменение под контролем.
-
Юнит‑тесты промптов:
- фиксируйте пример входа и ожидаемую структуру выхода;
- в тестах вызывайте модель с
temperature=0или используйте записанные ответы; - проверяйте: валидный JSON, заполнены обязательные поля, нет лишних ключей.
-
Тесты контрактов:
- прогоняйте JSON Schema / pydantic‑валидацию для всех инструментов;
- любые breaking changes должны падать в CI.
-
Сценарные тесты (record & replay):
- один раз выполняете сценарий и сохраняете ответы модели;
- затем «прокручиваете» их из файла, проверяя только логику оркестрации.
-
Эксперименты в проде:
- сначала shadow‑режим (новая версия не влияет на пользователя);
- затем A/B‑тест на части трафика;
- feature flag для быстрого отката.
Так изменения промптов проходят тот же цикл, что и код: тесты, review, поэтапный rollout.
Как безопасно включать режим автодействий агента (изменение реальных данных без человека)?
Для авто-действий нужен более жёсткий контроль, чем для «советника».
-
Ограничьте зону ответственности:
- список разрешённых действий (какие именно записи можно менять);
- запрет на операции с высоким риском без явного подтверждения (платежи, удаление данных).
-
Добавьте явную верификацию:
- LLM‑критик или отдельный валидатор, который проверяет план перед выполнением;
- формальные проверки инвариантов (лимиты сумм, статусов, прав доступа).
-
Лимиты и аудит:
- бюджет на число автодействий в единицу времени;
- подробный аудит‑лог: кто/что/когда изменил, с какими параметрами.
-
Постепенный rollout:
- сначала «режим подсказок» — агент предлагает действия оператору;
- затем полуавтомат: авто‑действия только для низкорисковых кейсов;
- после стабилизации — расширение списка действий.
Важно, чтобы в любой момент можно было быстро отключить автодействия через feature flag или конфиг.
Как эволюционировать схемы данных и контракты инструментов без даунтайма и каскадных сбоев?
Подход тот же, что и в микросервисах, но с учётом состояния агента.
-
Для данных и состояния:
- эволюционные миграции: сначала добавить новые поля, потом начать их заполнять, затем переносить логику, и только в конце удалять старые;
- хранить версии схем в данных (например,
schema_version), чтобы агент понимал, как интерпретировать запись.
-
Для инструментов:
- версионирование API (
/tool/v1,/tool/v2); - постепенный перевод агента на новую версию (canary‑подход);
- параллельная поддержка старой и новой версии в переходный период.
- версионирование API (
-
Для самого агента:
- blue‑green или canary‑деплой: часть трафика идёт на новую версию, остальное — на стабильную;
- возможность быстро откатиться (старый агент и контракты продолжают работать).
Ключевой принцип — не менять сразу и схему БД, и контракты инструментов, и логику агента. Делайте маленькие, совместимые шаги, каждый из которых можно откатить.
Как понять, что наша агентная архитектура спроектирована неправильно, и какие первые шаги по её оздоровлению?
На проблемы часто указывают повторяющиеся симптомы.
Обратите внимание, если вы видите:
-
Хаотичные, плохо воспроизводимые сбои:
- одни и те же кейсы то проходят, то падают без явной причины;
- в логах мало контекста (нет request_id, step_id, имен инструментов).
-
Сверхсложный промпт:
- вся логика «зашита» в один гигантский системный промпт;
- любое изменение промпта ломает старые сценарии.
-
Нет явных состояний и шагов:
- агент крутится в бесконечном цикле
while not done; - затруднено восстановление после падения (неясно, что уже сделано).
- агент крутится в бесконечном цикле
-
Инструменты ведут себя непредсказуемо:
- изменяют данные «мимо контракта»;
- не различают технические и бизнес‑ошибки;
- неидемпотентны при ретраях.
Быстрые шаги по исправлению:
- ввести простую FSM или workflow с явными шагами и статусами;
- описать схемы входа/выхода для основных инструментов и включить валидацию;
- добавить коррелированные логи и базовые метрики;
- ограничить число шагов и токенов на задачу, чтобы отсечь бесконечные циклы.
Уже этих мер обычно достаточно, чтобы превратить «магический скрипт» в управляемую систему.