Представьте внутреннего AI-агента, который помогает компании искать общие документы и управлять ими. Он работает. До тех пор, пока 12–15% запросов не начинают падать. Агент возвращает не тот документ, редактирует не тот файл, молча падает или уверенно ссылается на файл, которого не существует. Поиск по фото отказывает с той же частотой. Ошибки размазаны равномерно по пользователям, фичам и запросам.

Первое инстинктивное действие — поменять модель. Opus 4.5, GPT 5.5 или что там сейчас в топе лидерборда. Меняете. Счет за инференс растет в 4–5 раз, а общая доля ошибок снижается с 12% до 9%. Пользователи пишут о тех же проблемах. Бюджет следующего квартала сгорает за пару недель ради улучшения в 3 процентных пункта — и вы по-прежнему не понимаете, что именно было не так в системе и как улучшать ее дальше.

Эта статья — о том, почему смена модели обычно разочаровывает и куда стоит смотреть в первую очередь. Большинство сбоев AI-систем живет в слое обвязки — orchestration, retrieval, tool definitions, retries, context management, — а не в самой модели. Дальше — метод, как отличить проблемы обвязки от проблем модели, кейс, в котором одно исправление в обвязке подняло completion rate с 26% до 88% без смены модели, и чек-лист, который поможет найти такие сбои в вашей собственной системе. Если вы никогда не делали подобной диагностики — вероятнее всего, вы обнаружите хотя бы одну проблему, которую стоит починить.

Почему «слабая модель» — обычно ложный диагноз

В AI-системах модели живут внутри обвязки. Общая производительность системы складывается мультипликативно из производительности модели и обвязки вокруг нее. Сильная обвязка + слабая модель часто побеждает слабую обвязку + передовую модель — пока вы не упретесь в потолок возможностей модели.

В обвязку AI-агента входят: слой оркестрации, ретраи (к провайдеру API и во внутренних рутинах обвязки), retrieval, описания инструментов, менеджмент контекста, валидация вывода. Далеко не только промпт-инжениринг.

Хотя обвязка критична, есть три сигнала, что узкое место — действительно модель:

  1. Ошибки не сдвигаются при итерации промпта, ретраях или смене механизмов retrieval (например, многошаговый retrieval с постепенным ослаблением строгости).

  2. Характер ошибки указывает на известный capability gap (например, планирование на большом горизонте, глубокое рассуждение в узкой нише).

  3. Контролируемый A/B-тест между моделями на одной обвязке показывает явное улучшение.

И три сигнала, что дело в обвязке:

  1. Ошибки кластеризуются вокруг конкретных инструментов / сценариев / состояний.

  2. Поведение ретраев делает ошибки менее наблюдаемыми и склонно маскировать их.

  3. Та же модель на другой обвязке показывает существенно отличающиеся результаты на тех же входных данных.

Где ломается обвязка

Дальше — диагностический чек-лист. Прогоните по нему свою систему. Примерно в 8 из 10 продакшен-AI-систем, с которыми я работал, сбой принадлежал одной из этих категорий . Если вам удастся обнаружить его здесь — фикс будет стоить N часов инженерного времени, а не удвоенного счета за инференс.

  1. Оркестрация, поток управления:
    - Agent loop не знает, когда остановиться.
    - Плохие или отсутствующие терминальные условия.
    - Рекурсия в вызовах инструментов.

  2. Ретраи и обработка ошибок:
    - Тихие ретраи, не информирующие остальную систему.
    - Ретраи на неретраябельных операциях.
    - Нет различия между transient ошибками и структурными ошибками.

  3. Retrieval:
    - Неправильно настроенный баланс между релевантностью и точностью.
    - Чанки, смешивающие несвязанный контент.
    - Нет реранкинга.
    - Загрязнение контекста между ходами.

  4. Описания инструментов:
    - Описания, которые модель читает неверно.
    - Пересекающаяся семантика / ответственность инструментов.
    - Недоспецифицированные параметры.
    - Отсутствующие примеры использования.

  5. Управление контекстом:
    - Нет стратегии сжатия контекста (compact).
    - Накопление шума между ходами.
    - Утечка контекста между сессиями.

  6. Валидация вывода:
    - Отсутствующая или плохая проверка структурированного вывода.
    - Тихие падения парсеров на валидации.

Кейс из продакшена

Выше я изложил таксономию. Теперь — кейс из Kismet — AI-агента, которого я разрабатываю для автоматизации генерации кода на визуальном скриптом языке Unreal Engine (Blueprints), а также Material и Niagara-графов. Разберу один кейс подробно. Ландшафт сбоев меняется от системы к системе.

Небольшой Blueprint-граф в Unreal Engine — домен вывода агента. Типизированные пины, узлы потока управления (здесь — Switch on E_SpawnTeam) и попарные соединения пинов — то, что агент должен порождать и о чем рассуждать.
Небольшой Blueprint-граф в Unreal Engine — домен вывода агента. Типизированные пины, узлы потока управления (здесь — Switch on E_SpawnTeam) и попарные соединения пинов — то, что агент должен порождать и о чем рассуждать.

Примечание: проценты из текста ниже взяты из внутренних eval-прогонов Kismet на внутреннем бенчмарке. Они могут не обобщаться на другие AI-системы.

Дрейф состояния графа на длинных Blueprint-задачах

Симптом. На сложных Blueprint-задачах за пределами ~15–20 операций над нодами completion rate обрушивался. Агент пересоздавал ноды, которые уже создал, пытался соединять пины на несуществующих нодах или объявлял задачу выполненной, когда ключевые соединения flow-control отсутствовали.

Первая гипотеза. Лимит рабочего контекста. Модель не вытягивает контекст такого размера — со всеми инструментами, системными промптами, transient выводами тулзов, discovery-итерациями. Пробовал более длинные контекстные окна. Пробовал compact (суммаризацию) в середине. Доля ошибок практически не сдвинулась.

Что было на самом деле. Представление модели о Blueprint-графе было trace'ом тулзовых вызовов, а не актуальным состоянием графа. Когда тулзовый вызов отрабатывал частично, когда побочный эффект модификации графа выглядел не так, как модель предсказала, или когда слой ретраев что-то менял, расхождение накапливалось ход за ходом. К 20-му ходу модель планировала, основываясь на представлении о сильно измененном графе, который больше не соответствовал реальности.

Более сильная модель не помогала, потому что вход на каждом шаге был неправильный. Модель рассуждала корректно — но из испорченного состояния.

Фикс. Перед каждым ходом агента я начал инжектить актуальное структурированное состояние графа. Модель планирует из наблюдаемого состояния, а не пытается удерживать намерение в течение 20–30 ходов. Этот фикс не зависит от того, насколько умна модель. Стоит примерно 330 дополнительных токенов за ход (медиана на задачах средней сложности во внутреннем eval-бенчмарке). Это кардинально изменило производительность.

Итог. Completion rate на длинных задачах вырос с 26.3% до 87.9%. Ошибки пересоздания нод упали почти до нуля. Галлюцинации пинов и соединений — почти до нуля. Задачи, которые раньше требовали 30+ ходов (большую часть которых агент тратил на восстановление после операций по воображаемому графу), теперь решаются за медианные 7 ходов на задачах средней сложности.

Этот же тип сбоя проявился в других частях системы. Инструмент connect_pins (формирующий соединения между логическими нодами и собирающий поток выполнения по графу) принимал типы пинов как произвольные строки. Модель могла выдавать «Boolean», «Bool», «bool» вперемешку. Все проходили валидацию; вытекающие type mismatch'и всплывали только на ручном ревью. Система типов Blueprints в UE не согласует именования между семействами узлов, что создает реальную сложность для валидации.

Фикс был очевидным — перестать доверять выведенному контракту, отдавать модели на следующем ходе актуальное состояние типов и ограничений, позволить ей самой себя корректировать.

В обоих описанных сбоях смена модели потратила бы бюджет инференса ради в лучшем случае небольшого улучшения. Реальные исправления стоят практически ничего в инференсе и специфичны для обвязки.

Паттерн: везде, где ваша обвязка stateful — граф, типы, окружение, ретривал, ранжирование — и модель вынуждена выводить, а не наблюдать, у вас появляется кандидат на новый источник ошибок. Большинство таких сбоев проявятся только на масштабе или в экзотических условиях. И все они будут выглядеть как «модель не справляется». Или просто как шум, пока вы не присмотритесь.

Замечание перед началом диагностики

Перед списком действий — небольшая ремарка про подход к разработке.

Все в этой статье предполагает, что у вас есть система, работающая на сильной модели, и вы пытаетесь сделать ее дешевле или надежнее.

Когда вы запускаете что-то по-настоящему сложное — берите самую сильную модель, какую можете себе позволить, докажите, что задача в принципе решаема end-to-end, и только потом занижайте модель.

Если идти обратным путем — стартовать на дешевой и наращивать, если не работает, — это ловушка. Вы тратите дни, не понимая: это баг обвязки или потолок возможностей модели.

Если передовая модель не решает вашу задачу — более слабая не поможет, сколько ни вкладывай в обвязку.

Что попробовать до смены модели

Большинство шагов ниже стоит пару часов инженерного времени и ноль дополнительной стоимости инференса.

  1. Логируйте каждый тулзовый вызов, ретрай и терминальное состояние. Если не можете воспроизвести сбой — не сможете и найти проблему.

  2. В политике ретраев разделите transient ошибки и структурные ошибки.

  3. Измерьте точность retrieval на маленьком размеченном наборе, прежде чем винить генерацию во всех своих бедах.

  4. Тестируйте каждое описание инструмента изолированно.

  5. Добавьте возможность агенту отвечать «не знаю». Это валидный ответ, который большинство обвязок запрещают.

  6. Зафиксируйте размер контекста. Измерьте качество в строгом контекстном лимите.

  7. Валидируйте структурированный вывод. Ошибки должны быть verbose. Прокидывайте ошибки обратно агенту на следующий ход.

  8. Поменяйте модель на следующий тир на той же обвязке. Если разрыв в метриках небольшой — узкое место в обвязке.

Без раздельного наблюдения вы ничего из этого не увидите

Каждый шаг чек-листа предполагает, что вы локализуете источники сбоев. Большинство команд этого не делает. У них одна end-to-end метрика — success rate, стоимость токенов и немного продуктовых метрик типа удовлетворенности пользователей (вайбы). Когда эти метрики меняются, обвязка и модель неразличимы.

Решение — покомпонентные тесты и эвалы. Критически важно изолировать каждый слой обвязки.

Заключение

После всего сказанного, смена модели — последнее, что стоит пробовать (если вы изначально стартовали на достаточно сильной модели). Если нет — берите самую способную, какую можете себе позволить, докажите, что задача решаема, и только потом занижайте модель, чтобы оптимизировать счет за инференс. Основной рычаг, которым вы можете влиять на производительность, — обвязка, а не модель.

Комментарии (0)