Webrium
Подписаться

Агенты в продакшене: что отказывает на второй неделе

Сбои многошаговых агентов почти никогда не начинаются с модели. Они выводятся из арифметики шагов — и поэтому предсказуемы до запуска.

Шесть растущих столбцов: при том же коде контекст запроса агента увеличивается с каждым шагом истории, в продакшене уходя далеко за уровень показаКонтекст растёт

Показ агента почти всегда проходит хорошо. Программа получает задачу, ходит в три инструмента, возвращает разумный ответ. Через две недели после запуска начинаются жалобы, и обычно первым под подозрение попадает выбор модели.

Это почти всегда неверный адрес. Разница между показом и нагрузкой не количественная, а структурная, и её видно ещё до запуска — из арифметики.

Показ убирает четыре допущения сразу

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

Пользователь один. Значит, нет очереди, нет конкуренции за соединения к базе, нет лимитов у поставщика модели. Всё, что связано с параллелизмом, в показе просто отсутствует как класс проблем.

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

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

Вопрос формулирует тот, кто знает, как формулировать. Автор демонстрации спрашивает так, чтобы получилось. Живой пользователь спрашивает так, как думает, и половина его формулировок ведёт агента по маршруту, который никто не проверял.

Продакшен снимает все четыре одновременно. Дальше начинается счёт.

Арифметика, которую можно сделать до запуска

Если один шаг в худшем случае занимает тридцать секунд, а шагов пять, верхняя граница — две с половиной минуты. Пользователь при этом рассчитывал на десять секунд, потому что столько занимал показ.

Обратите внимание: чтобы получить этот вывод, не нужны ни замеры, ни инциденты. Достаточно перемножить худшее время шага на их число. Упражнение занимает пять минут и делается на салфетке:

Что перемножаем Откуда берётся
Худшее время шага Таймаут самого медленного инструмента, а не среднее по логам
Число шагов Максимум, который разрешает оркестратор, а не типичный случай
Множитель повторов Сколько раз шаг может быть повторён при неудаче

Три числа, одно умножение. Команды, которые делают это до релиза, ловят проблему на бумаге, а не в поддержке.

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

Первое, что пробуют, — и почему это не помогает

Обычная первая реакция — поднять таймаут. Логика понятная: запросы не укладываются, дадим им больше времени.

Это лечит симптом и усиливает причину. Таймаут на отдельный вызов ничего не говорит о суммарном времени запроса: пять шагов по сорок секунд — это уже больше трёх минут. Хуже того, увеличенный таймаут удлиняет и неудачные траектории. Если у оркестратора есть повторы, каждая неудача теперь стоит дороже, и вы платите за увеличенное время дважды: временем пользователя и деньгами.

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

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

budget = Deadline(seconds=20, max_steps=5, max_retries=1)

for step in agent.run(task, budget=budget):
    trace.emit(step)
    if budget.exhausted():
        return step.partial_result()

Это набросок, а не работающий фрагмент из проекта: он показывает, где стоит ограничитель, а не как устроен ваш оркестратор.

Существенно здесь одно — max_retries живёт на уровне цикла, а не внутри вызова инструмента. Разница кажется косметической, но она определяет порядок величины. Если положить ограничитель внутрь, пять шагов по два повтора дадут десять обращений вместо пяти. Причём в логе это будет выглядеть как обычная работа: никакой строчки «мы удвоили расходы» там не появится.

Частичный ответ как продуктовое решение

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

На практике наоборот. «Я нашёл три из пяти позиций, по остальным не успел» — это ответ, с которым человек может работать. Пустой экран через две минуты — нет. Плюс частичный ответ показывает, где именно агент застрял, что бесплатно даёт вам данные для разбора.

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

Три места, где ломается раньше всего

Время ответа. Прямое следствие арифметики выше. Заметно сразу, чинится ограничением бюджета. Из трёх — самое простое.

Стоимость. Проявляется на первом счёте, то есть с задержкой в месяц. Механизм — повторы: агент, не справившийся с первого раза, пробует ещё, и это умножается на число пользователей. Именно поэтому расходы растут нелинейно относительно трафика, и линейная экстраполяция с пилота систематически занижает счёт.

Возможность понять, что произошло. Самое неприятное из трёх, потому что единственное, что нельзя добавить задним числом дёшево.

Когда агент делает пять шагов, обычный лог превращается в стену текста: видно, что ответ плохой, и не видно, на каком шаге всё свернуло не туда. Трассировка шагов — это не улучшение наблюдаемости, а условие возможности разбора. Минимум, который должен попасть в запись каждого шага:

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

Последний пункт пропускают чаще всего, и именно он потом отвечает на вопрос «почему счёт вдвое больше расчётного».

Качество ответов модели в этом списке идёт последним, и это, пожалуй, главное, что стоит унести из текста.

Область ответственности расползается сама

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

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

Лекарство скучное: написанный список того, чего агент не делает. Не список умений — список отказов, с явным «здесь передаём человеку». Он занимает полстраницы и экономит месяцы, потому что превращает вопрос «а может он ещё и это» из обсуждения в проверку по списку.

Наше мнение

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

Условие, при котором мы неправы: если у вас один шаг, он детерминирован, а цена ошибки нулевая, всё вышенаписанное — лишняя работа. Такие задачи существуют, и для них агент просто избыточен.

Есть и второе условие, более узкое. Если агент работает в фоне и никто не ждёт его ответа, требование к времени снимается — остаются только стоимость и наблюдаемость. Это заметно более простая инженерная задача, и переносить на неё выводы про интерактивные сценарии не стоит.

Что стоит проверить у себя

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

Редакции: к этому материалу нужны собственные замеры — распределение времени шага, доля повторов и разброс числа шагов на реальном трафике. До их появления в тексте нет ни одной цифры, выдающей себя за измерение.

С чем это связано

Метка над заголовком говорит, зачем туда идти: продолжить тему, перейти к практике или увидеть возражение.

Сетка прогонов агента: успешными заполнена лишь часть ячеек, рядом счётчик типов отказовтипы отказов
Углубление

Оценка качества агента до релиза

Отказы второй недели видны и до релиза — если оценивать классы отказов, а не один успешный прогон.

Счёт за инференс, разогнанный повторами вызовов, растёт и пробивает порог бюджета, зажигая сигнал тревогисчёт с повторамимесяц
Усиление

Сколько стоит инференс: считаем до счёта, а не после

Что отказывает на второй неделе, вы уже знаете. Расходы на инференс можно посчитать своими числами за час — и главный множитель окажется не размером модели, а долей повторов.

Линия жёстких отказов агента пробивает порог и зажигает сигнал дежурному, а мягкие отказы остаются под порогом и сигнала не даютжёсткий отказэпизоды дежурства
Практика

Дежурство по агенту: порядок действий

Знать, что отказывает, — полдела; дежурному нужен регламент. Что считать жёстким отказом, а что мягким, почему рестарт и откат — тупик и как найти причину по трассе одного эпизода.

Поле, разделённое швом: слева ассистент, который лишь отвечает текстом, справа агент, который сам выполняет действия; элементы пересекают границу, показывая, чтАссистент отвечаетАгент делает
Предыстория

Что такое ИИ-агент и почему о нём все спорят

Без формул и английских слов без перевода: чем агент отличается от чат-бота и почему из-за этого отличия он дорожает.

Письмо по вторникам

Один разбор недели и короткий список того, что изменилось. Без дайджестов на сорок ссылок.

Начните вводить — материалы появятся здесь.

выбрать · Enter открыть · Esc закрыть