Исследования ИИ

6 месяцев боли с AI-агентами в продакшне: что я понял про архитектуру

Тесты — 94%. Production — 4 инцидента за полгода. Тихие сбои, галлюцинации в числах, бесконечные циклы. Проблема не в модели — в отсутствии execution layer.

21 марта 2026 г.
9 мин чтения
мультиагентные системыИИ в финансах

Январь. AI-агент выходит в production. Классификация клиентских заявок, извлечение данных, проверка в базе, генерация ответа. Один промпт, шесть инструментов, линейная цепочка. Тесты — 94% точности. Demo для руководства — без единой ошибки.

К июлю: четыре инцидента, 340 часов инженерного времени на тушение пожаров и полная перестройка архитектуры. Не потому что модель плохая — Claude Sonnet работал отлично. Потому что всё вокруг модели было построено неправильно.

Хроника шести месяцев. Каждый инцидент — урок, за который я заплатил временем и нервами.

Месяц 1-2: медовый месяц и первый удар

Первые недели — эйфория. 50 заявок в день, стабильность 89%. Ниже тестовых 94%, но реальные данные грязнее — ожидаемо. Поправили промпт, подняли до 91%.

Потом обнаружили случайно: агент перестал вызывать check_compliance. Не на всех заявках — на 40%. Без ошибки. Без предупреждения. Просто пропускал шаг и шёл дальше.

127 заявок за 8 дней — без compliance-проверки.

Что случилось: Anthropic выкатили минорный апдейт Claude. Без анонса, без changelog для нашей версии API. Поведение модели чуть сдвинулось — она стала «оптимизировать» цепочку вызовов. Промпт говорил «проверь compliance». Для обновлённой версии это оказалось рекомендацией, а не требованием. В некоторых случаях модель решила, что проверка «очевидно не нужна».

Урок: промпт — не контракт. Это рекомендация, которую модель выполняет вероятностно. Минорный апдейт провайдера меняет вероятности без вашего ведома. Всё, что критично для бизнеса, должно быть гарантировано кодом — не текстом промпта.

Месяц 3: уверенная ложь в цифрах

Клиент написал: «Переведите 15 000 рублей.» Агент извлёк сумму: 150000. Не баг парсинга — галлюцинация. Модель прочитала «15 000» и вернула другое число.

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

Три заявки с неправильными суммами за неделю. Одну поймали. Две — нет.

Урок: LLM не может валидировать свой output. Просить модель проверить собственный результат — как просить человека увидеть собственную слепую зону. Валидация должна быть внешней: Pydantic, JSON Schema, regex — в коде, не в промпте.

class ExtractedAmount(BaseModel):
    amount: float
    
    @field_validator("amount")
    @classmethod
    def reasonable_range(cls, v):
        if v <= 0 or v > 5_000_000:
            raise ValueError(f"Amount {v} outside valid range")
        return round(v, 2)

После внедрения Pydantic: ноль ошибок в суммах за четыре месяца. Модель по-прежнему иногда галлюцинирует — но валидатор ловит и отправляет на retry с конкретной ошибкой. Модель получает обратную связь от кода, не от себя — и исправляет.

Месяц 4: $12 за одну заявку

Пятница, 17:40. Алерт: аномальный spike расходов на API. Один запрос сгенерировал 38 вызовов инструмента за 4 минуты.

Агент вошёл в цикл. Инструмент возвращал ошибку, агент повторял. Промпт: «Если ошибка — попробуй с другими параметрами.» Модель пробовала — формально с другими: переставила пробел, изменила регистр. Суть та же. Ошибка та же. 38 раз. Стоимость одной заявки: $12. При средней $0.15. В 80 раз дороже.

Урок: retry без ограничений — бомба замедленного действия. Промпт не задал максимум попыток. Не определил, что значит «другие параметры». LLM интерпретировал буквально и минимально.

for attempt in range(3):
    result = await tool.call(params)
    if result.success:
        break
    params = mutate_params_meaningfully(params, result.error)
    await asyncio.sleep(2 ** attempt)
else:
    await escalate_to_human(state)

Десять строк. Три попытки, конкретная мутация параметров, backoff, fallback на человека. Бесконечных циклов больше нет.

Месяц 5: маршрут в никуда

VIP-клиент. Заявка — одновременно жалоба (ошибка в счёте), срочная (дедлайн завтра) и содержит вопрос (как исправить). Три категории, три возможных маршрута.

Промпт: «Жалобу — в отдел качества. Срочное — эскалируй. Вопрос — в FAQ.» Без приоритетов. Без инструкции, что делать, когда всё сразу. Агент отправил в отдел качества. Без пометки «срочная». Без ответа на вопрос. VIP-клиент ждал сутки вместо эскалации за 2 часа.

Урок: бизнес-правила с приоритетами нельзя описать в промпте однозначно. Когда условия конфликтуют — модель выбирает одно и игнорирует остальные.

def route(state):
    pri = state["classification"]["priority"]
    flags = state["classification"]["flags"]
    
    if pri >= 4:              return "escalate"      # Первый приоритет
    if "complaint" in flags:  return "quality_team"   # Второй
    if "question" in flags:   return "faq"            # Третий
    return "standard" 

Явный приоритет. Тестируемо: 15 unit-тестов покрывают все комбинации. Промпт нельзя протестировать как функцию.

Месяц 6: перестройка

Четыре инцидента — четыре разных симптома, одна причина. Весь execution logic жил в промпте: порядок шагов, валидация, retry, маршрутизация, состояние. 2 800 токенов инструкций, которые LLM выполнял вероятностно.

Перестроил за две недели. Два слоя:

Execution engine (Python + LangGraph): граф шагов — порядок гарантирован; Pydantic — валидация каждого output; retry с backoff — три попытки, таймаут, fallback; conditional edges — маршрутизация по правилам; TypedDict — управление состоянием.

LLM (только мышление): классифицировать заявку, извлечь данные из текста, сгенерировать ответ, оценить неоднозначную ситуацию.

Промпт: с 2 800 до 300-400 токенов на шаг. Одна задача — один промпт. LLM не управляет выполнением.

Результат

Стабильность: месяцы 1-5 — 72-84%, месяц 6+ — 97%.
Инциденты: 4 за 5 месяцев → 0 за 6 месяцев.
Обнаружение сбоя: 1-8 дней → <5 минут.
Отладка edge case: 2-4 часа → 15-30 минут.
Апдейт модели: риск инцидента → без влияния.

Ноль инцидентов за полгода. Модель по-прежнему иногда возвращает невалидный JSON, галлюцинирует число. Но Pydantic ловит, retry исправляет, граф гарантирует порядок. Ошибки модели компенсируются кодом.

Пять правил, выученных болью

1. Модель — вероятностный исполнитель. Промпт — рекомендация. Апдейт провайдера меняет поведение без предупреждения. Критичное — в коде.

2. LLM не валидирует свой output. Pydantic, JSON Schema, regex — в коде. Каждый output проверяется до использования.

3. Retry без лимита — $12 за запрос. Три попытки. Backoff. Таймаут. Fallback. Десять строк кода.

4. Маршрутизация с приоритетами — if/elif/else. Однозначно, тестируемо, предсказуемо.

5. Мониторинг каждого шага. Не только результата. Какие инструменты вызваны? Что вернули? Прошла ли валидация? Без этого тихий сбой обнаруживается через неделю.

Что сказал бы себе в январе

Не выводи агента в production без execution layer. Не промпт, который описывает процесс — а код, который его контролирует.

Тесты покрывают happy path. Production подкидывает комбинации, которые ты не предусмотрел. Модель, оставленная без контроля, обработает их творчески. Иногда — гениально. Иногда — на $12 за запрос. Иногда — молча пропустив compliance-проверку на 127 заявках.

Промпт — для мышления. Код — для выполнения. Шесть месяцев и четыре инцидента, чтобы усвоить вещь, которая звучит очевидно постфактум.

Автор: Алик Завалишев

Эксперт по ИИ и автоматизации процессов

Больше статей