18+
реклама
18+
Бургер менюБургер меню

Ранас Мукминов – Оркестрация ИИ-агентов. Claude Opus 4.7 (страница 38)

18

Узкое место лечат двумя способами. Первый — передекомпозиция: медленную стадию дробят на несколько более лёгких, перераспределяя работу так, чтобы выровнять латентности. Второй — репликация узкой стадии: если стадия не имеет общего изменяемого состояния (share-nothing, см. главу 54), её можно размножить и обрабатывать несколько элементов потока параллельно именно на этой стадии. Реплицированная стадия превращается локально в мини-fan-out внутри конвейера: один распределитель раздаёт элементы N копиям медленной стадии, результаты возвращаются в общий поток.

Репликация работает только при двух условиях: стадия не зависит от порядка (иначе параллельная обработка нарушит последовательность, см. главу 29) и стадия не делит изменяемое состояние с другими копиями. Если стадия ревью пишет в общий журнал замечаний, её копии будут конкурировать за этот журнал, и репликация введёт гонку (см. главу 41). Поэтому перед репликацией стадию проверяют на отсутствие разделяемого изменяемого состояния — это инвариант, а не оптимизация.

Приём | Когда применим | Чем оплачивается

Передекомпозиция стадии | Стадию можно разбить на независимые фазы | Больше границ, больше handoff, больше дрейфа

Репликация стадии | Стадия share-nothing и не зависит от порядка | Стоимость параллельных копий, усложнение сборки

Сокращение выхода стадии | Стадия многословна без необходимости | Риск потери нужного контекста

Кэширование входа стадии | Повторяющиеся входы | Сложность инвалидации кэша

Конвейер по своей природе последователен: стадия k+1 не может начать обработку элемента, пока стадия k не закончила. Для одного элемента это означает, что время прохождения — строго сумма времён стадий, и никакой параллелизм этого не сократит. Это прямое проявление закона Амдала (см. главу 56): последовательная доля работы в конвейере близка к единице для отдельного элемента. Выигрыш конвейерного параллелизма проявляется только на потоке и ограничен самой медленной стадией. Поэтому глубокий конвейер из многих стадий, спроектированный «чтобы каждая стадия была максимально специализирована», часто проигрывает короткому: каждая дополнительная стадия добавляет латентность передачи и риск дрейфа, но не добавляет параллелизма для отдельной задачи. Глубина конвейера — это стоимость, а не достоинство.

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

Главный и наиболее коварный отказ конвейера — семантический дрейф (drift): постепенное искажение смысла исходной задачи при прохождении через стадии. Каждая стадия интерпретирует вход своего предшественника, и каждая интерпретация вносит малое смещение. На одной границе смещение незаметно. На цепочке из шести стадий смещения накапливаются мультипликативно, и финальный артефакт может отвечать на задачу, которую никто не ставил.

Механизм дрейфа специфичен для агентов. Классический конвейер передаёт данные без интерпретации — байты не «понимают» себя иначе на разных стадиях. Агент же интерпретирует вход на естественном языке, и его интерпретация недетерминирована: одна и та же стадия дважды поймёт пограничный артефакт чуть по-разному. Когда исходная постановка задачи не протащена явно через все стадии (потоковая модель данных), поздние стадии работают не с задачей, а с интерпретацией интерпретации. Это и есть эффект испорченного телефона, перенесённый в мультиагентную систему.

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

Защита от дрейфа — архитектурная, и она состоит из нескольких независимых мер:

— Протаскивать исходную постановку. Исходная задача (или её стабильное ядро) передаётся вместе с артефактом на каждую стадию, а не только на первую. Каждая стадия может сверить, что её результат всё ещё отвечает на исходную задачу, а не на её искажённую тень. Это стоит токенов, но это самая прямая защита от дрейфа.

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

— Сверять с исходником в конце. Финальная стадия (или валидатор после неё) сверяет итог с исходной постановкой, а не только с выходом предпоследней стадии. Это ловит накопленный дрейф там, где он стал суммарно значимым.

Линейная топология означает, что ошибка ранней стадии необратимо отравляет все последующие. Если стадия исследования собрала неверный факт, стадия плана построит план вокруг неверного факта, стадия черновика напишет вокруг неверного плана, а стадия ревью — если она проверяет внутреннюю связность, а не истинность исходных данных — одобрит связный текст, построенный на ложном основании. Ошибка не локализуется на стадии-источнике; она распространяется вниз и обрастает корректной с виду надстройкой, что делает её всё труднее обнаружить с каждой стадией.

Это фундаментальное отличие конвейера от ансамбля (см. главу 62): в ансамбле независимые агенты ошибаются по-разному, и их ошибки можно отфильтровать голосованием; в конвейере стадии зависимы, и ошибка ранней стадии не отфильтровывается поздними — она ими наследуется. Конвейер не усредняет ошибки, он их аккумулирует. Поэтому ранние стадии конвейера несут непропорционально большой вес: ошибка на входе дороже ошибки на выходе. Из этого следует правило размещения проверок: валидацию стоит ставить как можно ближе к источнику потенциальной ошибки, а не только в конце, потому что чем дальше ошибка прошла, тем дороже её откатить.

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

Дисбаланс стадий порождает два симметричных отказа. Если стадия быстрее своих потребителей, перед потребителем растёт очередь — переполнение. Если стадия медленнее своих поставщиков, её потребители простаивают — голодание (starvation). Оба отказа в агентном конвейере имеют денежную цену: переполнение замораживает оплаченную работу в очереди, голодание оплачивает простаивающие, но всё ещё «зарезервированные» ресурсы (например, удержанные сессии или арендованные лимиты у провайдера).

Без механизма обратного давления конвейер при дисбалансе деградирует предсказуемо плохо: быстрая стадия исследования генерирует артефакты, медленная стадия ревью не справляется, очередь растёт, память (или бюджет) исчерпывается, и система отказывает каскадно. Backpressure — сигнал от перегруженной стадии вверх по потоку «притормози» — превращает каскадный отказ в управляемое замедление. Это прямое заимствование из теории потоковых систем, и для агентного конвейера оно обязательно, потому что цена непродуманного переполнения здесь не только в потерянных данных, но и в потраченных деньгах.

Механически обратное давление в агентном конвейере реализуют через ограниченные очереди между стадиями. Каждая граница получает буфер фиксированной ёмкости; когда буфер перед медленной стадией заполнен, поставщик не может положить в него новый артефакт и вынужден ждать. Ожидание распространяется вверх по цепочке: заполнение буфера перед ревью останавливает стадию черновика, та перестаёт забирать из своего буфера, останавливается план, и в итоге притормаживает стадия исследования — самый дешёвый способ не тратить токены на работу, которую узкое место всё равно не успеет принять. Ограниченная очередь автоматически вводит верхний предел объёма незавершённой работы и тем самым ограничивает и память, и замороженную в очереди стоимость. Альтернатива без буферов — синхронная передача, при которой стадия блокируется до готовности преемника принять артефакт; она проще, но полностью лишает конвейер pipelining-параллелизма, поэтому применима только там, где поток заведомо медленнее любой стадии. Выбор ёмкости буфера — это компромисс между сглаживанием неравномерности нагрузки (больший буфер) и ограничением замороженной стоимости и задержки реакции на дисбаланс (меньший буфер).