Ранас Мукминов – Оркестрация ИИ-агентов. Claude Opus 4.7 (страница 90)
Схема в долгоживущем рое меняется, и это — точка, где формат сообщений смыкается с версионированием (см. главу 22). Здесь действуют те же законы совместимости, что и в распределённых системах, но с поправкой на недетерминизм производителя.
Совместимость назад означает, что новый потребитель понимает сообщения, созданные по старой схеме. Совместимость вперёд означает, что старый потребитель не ломается на сообщениях по новой схеме (например, игнорирует незнакомые поля вместо отказа). Безопасная эволюция схемы сообщения подчиняется правилу вариантности из главы 18: на стороне выхода можно добавлять необязательные поля и нельзя убирать или ужесточать существующие; на стороне входа можно ослаблять требования и нельзя ужесточать. Добавление обязательного поля в схему — несовместимое изменение, ломающее всех производителей, которые его не заполняют; превращение необязательного поля в обязательное — то же самое со стороны входа.
Поправка на недетерминизм такова: в рое опасны не только явные, объявленные изменения схемы, но и тихий дрейф формы при неизменной схеме. Новая версия модели может начать заполнять необязательное поле иначе, опускать его чаще, менять формулировки в свободных подполях — формально схема соблюдается, фактически семантика сместилась. Поэтому версия схемы в конверте необходима, но недостаточна: она ловит объявленные изменения структуры, но не дрейф наполнения. Против дрейфа работает только проверка поведения на границе при смене модели (контрактные тесты сообщений, см. главу 18) и наблюдаемость распределения значений полей во времени.
Полезно видеть схему как мембрану на границе двух миров: недетерминированного (модель, порождающая нагрузку) и детерминированного (код, обрабатывающий сообщение). До мембраны — вероятностный вывод, который может принимать любую форму. После мембраны — данные, форма которых гарантирована, потому что всё, что не прошло мембрану, отвергнуто. Вся ценность схемы в рое — в существовании этой мембраны: она локализует недетерминизм перед границей и не пускает его дальше в систему.
Из этого взгляда следует, где схему проверять: ровно на переходе от модели к коду. Сообщение, рождённое моделью, проходит валидацию по схеме до того, как любой детерминированный потребитель начнёт на него опираться. Если валидация размещена позже — после того как сообщение уже разошлось по маршрутизатору, записалось в общую память, запустило инструмент, — мембрана дырява: недетерминизм просочился в детерминированную часть, и сбой проявится далеко от места, где форма была нарушена. Это та же логика, что и у проверки контракта на стыке (см. главу 18): граница недоверия должна стоять на входе детерминированного мира, а не где-то в его глубине.
В обычной распределённой системе парсинг сообщения тривиален: отправитель сериализовал структуру по схеме, получатель десериализует её обратно; если байты не бьются со схемой, это сетевая порча или баг отправителя — редкое событие. В рое всё иначе. Отправитель полезной нагрузки — модель, которая порождает текст, а структуру лишь имитирует по инструкции. Поэтому невалидное сообщение здесь — не аномалия, а ожидаемая доля потока: модель то обернёт ответ в лишний поясняющий текст, то закроет структуру не до конца, то добавит непредусмотренное поле, то выдаст почти-валидную форму с одной ошибкой. Парсинг межагентного сообщения — это не десериализация, а извлечение структуры из ненадёжного источника с заранее известной долей брака.
Это меняет постановку задачи. Вопрос не «как десериализовать сообщение», а «что делать с непрерывным потоком, часть которого структурно не соответствует ожиданию». Ответ — конвейер из нескольких стадий, каждая из которых обрабатывает свой класс отклонений, и явная политика для того, что не удалось разобрать ни на одной стадии. Рой без такого конвейера обрабатывает только идеальные выводы модели и спотыкается на первом неидеальном — то есть очень скоро.
Разбор полезной нагрузки от модели удобно строить как последовательность стадий с понижающейся толерантностью и явным исходом на каждой.
Стадия извлечения. Из сырого вывода модели выделяется кандидат на структурированную нагрузку. Модель часто оборачивает структуру в поясняющий текст («Вот результат: …», маркеры разметки, рассуждение до и после). Извлечение отделяет структурный кандидат от обёртки детерминированными средствами. Это первая и самая дешёвая защита: значительная доля «невалидных» сообщений на деле содержит валидную структуру внутри текстовой обёртки, и их спасает простое извлечение, а не повтор запроса к модели.
Стадия ремонта (опциональная и ограниченная). Извлечённый кандидат может быть почти валиден: незакрытая структура, висящий разделитель, очевидная мелкая поломка формата. Ограниченный детерминированный ремонт способен починить такие случаи без обращения к модели. Здесь важна дисциплина: ремонт допустим только для строго формальных, однозначно исправимых дефектов формы и никогда — для домысливания содержания. Ремонт, который угадывает недостающее значение поля, — это уже не парсинг, а порождение данных, и он опаснее отказа: он молча подставляет выдуманное там, где система должна была отвергнуть сообщение. Граница ремонта: чинить форму, не трогать смысл.
Стадия валидации. Кандидат, прошедший извлечение и при необходимости ремонт, проверяется по схеме соответствующего типа (тип берётся из конверта). Это детерминированная проверка структуры: поля, типы, обязательность, перечни. За ней — проверки свойств для строгих сообщений (суммы, ссылки, диапазоны), которые схема выразить не может. Валидация — это и есть мембрана между моделью и кодом: всё, что её прошло, дальше считается данными с гарантированной формой.
Стадия решения. То, что валидацию не прошло, требует явной политики — это самостоятельный раздел ниже. Ключевое: исход стадии решения наблюдаем и зарегистрирован, потому что доля сообщений, не прошедших разбор, — это метрика здоровья роя (см. главу 79), а конкретные провалы — материал постмортема (см. главу 82).
Стадии расположены по возрастанию стоимости и по убыванию частоты применения: извлечение дёшево и помогает часто, ремонт дороже и применим реже и осторожнее, повторный запрос к модели (если он входит в политику) — самый дорогой шаг. Конвейер устроен так, чтобы дешёвые стадии снимали основную массу отклонений до того, как дело дойдёт до дорогих.
Сообщение, не прошедшее разбор и валидацию, нельзя ни тихо проигнорировать, ни пропустить дальше. Нужна явная политика, и выбор между её вариантами — это выбор между стоимостью, латентностью и риском.
Политика | Что делает | Стоимость | Риск | Когда уместна
Отвергнуть и зарегистрировать | Сообщение в очередь разбора ошибок, исход помечен как провал | Низкая | Потеря результата работы | По умолчанию для большинства сообщений
Повторный запрос к производителю | Производителя просят выдать сообщение заново, часто с указанием на дефект формата | Высокая (ещё один вызов модели) | Зацикливание при систематической ошибке | Дорогой результат, который жаль потерять
Деградация до частичного | Извлечь валидную часть, пометить нагрузку как неполную | Низкая | Распространение неполных данных как полных | Толерантные к неполноте потребители
Эскалация человеку | Сообщение и контекст — оператору | Очень высокая (внимание человека) | Усталость оператора (см. главу 96) | Критический путь, где автоматический отказ дорог
Две оговорки делают политику безопасной. Первая: повторный запрос к производителю должен иметь жёсткий предел числа попыток, иначе систематическая ошибка формата (например, модель в принципе не умеет выдать нужную структуру для данного входа) превращается в зацикливание (см. главу 74), пожирающее токены и время без сходимости. Предел повторов — это инвариант контракта на бюджет (см. главы 18, 71), применённый к разбору. Вторая: любой исход, кроме чистого успеха, наблюдаем. Тихо отвергнутое сообщение неотличимо от никогда не отправленного, и рой, который молча роняет невалидные сообщения, теряет работу, не зная об этом, — это потеря, маскирующаяся под нормальную работу.
Валидация межагентного сообщения — это не только проверка формы, но и точка применения zero trust в рое (см. главу 85). Получатель не доверяет тому, что ему прислали, даже если отправитель — «свой» агент того же роя, по трём причинам, и каждая требует своего рода проверки.
Первая причина — недетерминизм: «свой» агент мог честно ошибиться формой, потому что он недетерминирован, а не злонамерен. Защита — структурная валидация по схеме. Вторая причина — компрометация: отправитель мог быть сбит prompt injection (см. главу 86) и формирует сообщение, которое формально валидно, но несёт вредоносное содержание или команду, выводящую получателя за рамки его задачи. Защита — не только схема, но и проверка того, что содержание нагрузки относится к ожидаемому домену и не содержит управляющих конструкций, адресованных получателю как модели. Третья причина — распространение испорченного состояния: даже добросовестный отправитель мог передать дальше данные, которые сам получил испорченными (см. главу 53 об отравлении общей памяти). Защита — проверки свойств и согласованности с известным состоянием, а не только формы.