Constraint Decay: The Fragility of LLM Agents in Back End Code Generation
Я недавно наткнулся на исследование, которое заставило меня пересмотреть всё, что я думал о надёжности LLM-агентов (AI-модели, которые могут выполнять задачи автономно, обдумывая каждый шаг). Суть простая: когда задача становится сложнее, эти агенты начинают… терять голову. Не метафорически — буквально. Они забывают про ограничения, косячат в слое данных и в итоге выдают код, который работает «где-то примерно».
Называется это constraint decay — постепенный распад следования ограничениям. И если вы думаете, что это проблема только слабых моделей, — нет. Исследование показало падение на 30 баллов в assertion pass rates (процент успешно пройденных проверок — какая доля тестов показала, что код работает правильно) даже у сильных конфигураций. От бейслайна (исходный уровень, с которым сравнивают результаты — базовая версия без оптимизаций) до полностью специфицированной задачи.
Давайте разберёмся, почему так происходит и что с этим делать.
Что такое распад ограничений
Представьте: вы даёте агенту задачу написать бэкенд на FastAPI. Однофайловый хелло-ворлд — без проблем. Добавляете требования: REST-маршруты (адреса API — например `/users`, `/orders`, через которые приложение принимает запросы), модель базы данных, ORM-маппинг (Object-Relational Mapping — прослойка, которая превращает записи из базы данных в объекты в коде, чтобы программист работал не с таблицами, а с привычными структурами), миграции (скрипты, которые меняют структуру базы данных — добавляют таблицы, колонки, индексы), тесты — и начинается магия.
Constraint decay — это феномен, при котором агент по мере накопления структурных требований всё хуже следует ограничениям. Не потому что он тупой. А потому что каждый новый слой ограничений — это дополнительная нагрузка на контекст (в данном случае — вся информация, которую модель «держит в голове» во время работы), дополнительные правила, которые нужно удерживать.
РАСПАД ОГРАНИЧЕНИЙ ПО МЕРЕ РОСТА ЗАДАЧИ ───────────────────────────────────────── Простое задание ██████████ 95% точность + Архитектура ███████░░░ 80% + База данных █████░░░░░ 65% + ORM + миграции ███░░░░░░░ 45% + Тесты + интеграции ██░░░░░░░░ 30% Каждый слой = -15-20% точности
Исследователи измерили это на 80 задачах генерации с нуля и 20 задачах реализации фич. Восемь веб-фреймворков, единый API-контракт, двойная оценка: поведенческие тесты и статические верификаторы (инструменты, которые автоматически проверяют код: соответствует ли он правилам, нет ли ошибок в стиле, нарушена ли схема).
Где именно ломаются агенты
Самое интересное — где агенты косячат больше всего. Не в логике, не в алгоритмах. В слое данных.
Три главные проблемы:
1. Неправильная композиция запросов. Агент генерирует SQL или ORM-запрос, который выглядит разумно, но содержит ошибку: неправильное условие JOIN, отсутствующий фильтр, некорректный агрегат.
2. ORM runtime violations. Нарушения времени выполнения — попытка сохранить объект без обязательного поля, нарушение внешнего ключа, неправильный тип данных.
3. Накопление мелких отклонений. На первом шаге агент правильно использует схему. На пятом — уже нет. На десятом — вообще забыл, что схема была.
ЦЕПОЧКА ОШИБОК В МНОГОШАГОВОЙ ЗАДАЧЕ
──────────────────────────────────────
Шаг 1: Модель User ✓ Схема соблюдена
Шаг 2: Роут /users ✓ REST-конвенция
Шаг 3: CRUD-сервис ✓ Логика ОК
(Create, Read, Update, Delete —
сервис, который умеет создавать,
читать, изменять и удалять данные)
Шаг 4: Миграция ⚠ Мелкое отклонение
Шаг 5: Тесты ✗ Ограничения забыты
Шаг 6: Интеграция ✗ Контекст потерян
На шаге 5-6 агент "забывает" про ранние ограничения
Отдельно забавно про фреймворки. Flask — минималистичный, явный, мало магии — работает отлично. FastAPI и Django — конвенционально нагруженные (фреймворки с большим количеством встроенных правил и «магии», которую нужно знать), со своими правилами, скрытыми зависимостями — результаты заметно хуже. Агент хорошо справляется, когда всё написано руками. Когда нужно следовать «магическим» конвенциям фреймворка — начинаются проблемы.
Почему это важно для практики
Я вижу три категории людей, которых это касается напрямую.
Разработчики, которые уже используют AI-ассистентов для генерации бэкенд-кода. Если вы генерируете что-то простое — ок. Если пытаетесь получить готовый микросервис с базой, роутами и тестами — будьте готовы к сюрпризам.
Тимлиды и архитекторы, которые планируют внедрение AI-агентов в процессы. Исследование показывает: функционально корректный код — это ещё не production-ready код. Агенты хорошо справляются с «работает», но косячат на «правильно структурировано».
Авторы инструментов — если вы делаете что-то для AI-ассистированной разработки, учитывайте: статические верификаторы важнее, чем кажется. Поведенческие тесты покажут, что код работает. Верификаторы покажут, что он следует ограничениям.
Как снизить риск
Исследование не только описывает проблему — авторы дают направления. Вот что имеет смысл делать практически:
Разбивать задачи на короткие шаги. Вместо «напиши мне бэкенд» — «создай модель», «добавь роут», «напиши тесты». Каждый шаг — отдельный запрос с чёткими ограничениями.
Валидировать каждый шаг. Тесты, линтеры, статические анализаторы (программы, которые изучают код без его запуска и находят проблемы — от опечаток до серьёзных багов) — запускать после каждого сгенерированного файла, а не в конце.
Явно фиксировать ограничения. Если нужен конкретный ORM, схема базы, конвенция именования — указывать это явно в промпте (текстовый запрос к AI-модели — инструкция, что нужно сделать), а не надеяться, что агент догадается.
Использовать явные фреймворки. Если выбираете между Flask и Django для AI-генерируемого кода — Flask проще. Меньше магии, больше явных правил.
Коротко
LLM-агенты отлично справляются с изолированными задачами. Проблема начинается, когда задача обрастает ограничениями: архитектурой, базой данных, ORM, тестами, интеграциями. Каждый новый слой требований — это минус к точности.
Constraint decay — не баг конкретной модели, а системная проблема накопления. Решение: дробить задачи, валидировать часто, фиксировать ограничения явно.
Если вы используете AI для генерации бэкенда — не расслабляйтесь. Функционально корректный код и production-ready код — это разные вещи. Исследование это подтверждает цифрами.
Ссылки
Дмитрий Полухин — продуктовый дизайнер. Пишу про разработку, AI и дизайн интерфейсов. Обо мне, контакты и профили.