Вт. Июн 9th, 2026

Когда изменился Claude, изменилось всё: Управление радиусом воздействия ИИ в продакшене

Наша система выполняла одну функцию, и делала это хорошо: она преобразовывала запросы на естественном языке в вызовы API. Пользователями были аналитики, менеджеры по работе с клиентами и руководители операционных отделов. Они точно знали, какие данные им нужны, но их ручной сбор требовал обращения к четырем дашбордам, двум BI-инструментам и конструктору отчетов Salesforce. С нашей системой они просто вводили запрос на обычном языке. Запрос вроде «Составить отчет по объему продаж за январь-март 2026 года для северо-восточного региона с разбивкой по городам» транслировался в вызов API, который система могла обработать:

{
  "description": "User requested sales volume for the given date range, here is the API call to get the response",
  "api_call": "/api/sales_volume",
  "post_body": {
    "start_date": "2026-01-01",
    "end_date": "2026-03-31",
    "region": "northeast"
  }
}

Остальная часть конвейера представляла собой традиционную разработку. Система отправляла вызов в соответствующий бэкенд — у нас были интеграции с внутренними порталами отчетности, Salesforce и несколькими собственными сервисами — применяла JSON-запрос, сгенерированный большой языковой моделью (LLM), для фильтрации и формирования ответа, а затем доставляла его по электронной почте, в виде документа Google Drive или в виде графика в браузере. К середине 2025 года система генерировала несколько сотен отчетов в месяц. Эти отчеты использовались руководством и аналитиками, а также распространялись среди внешних заинтересованных сторон. Система стала стандартным способом получения большинства команд для ad-hoc данных.

Контрактом между LLM и остальной частью системы был структурированный JSON-объект, как описано в примере выше.

Мы построили систему на базе Claude Sonnet 3.5 в начале 2025 года. Без инцидентов мы обновились до версии 3.7, а затем до 4.0. К моменту выхода Sonnet 4.5 мы стали самонадеянны относительно стабильности и предсказуемости LLM в решении, как нам тогда казалось, простой задачи. Обновления моделей стали рутинным делом, подобно обновлению минорной версии хорошо себя зарекомендовавшей библиотеки. Затем мы внедрили 4.5. Для значительного процента запросов модель начала встраивать содержимое поля `post_body` в поле `description`. Это привело к двум сценариям сбоя.

Первое: параметры фильтрации так и не достигли API. Наша система воспринимала `post_body` как источник истины для полезной нагрузки запроса, а это поле возвращалось пустым. Вызов API совершался без фильтра по диапазону дат или региону. В зависимости от вызываемого API, бэкенд либо возвращал объем продаж за все время или по всем регионам, либо выдавал ошибку 500.

Второе: модель начала задавать уточняющие вопросы в своем ответе. Это было ново. Предыдущие версии всегда старались максимально эффективно обработать неоднозначный запрос и возвращали структурированный объект. Sonnet 4.5, будучи более осторожным, иногда отвечал вопросом. В нашей системе не было предусмотрено такого сценария. Она была построена на предположении, что каждое invocation модели приведет к вызову API. Не было компонента «человек в контуре» (human-in-the-loop) и состояния для хранения частично завершенного запроса. Это вызвало сбои в последующих системах по нескольким направлениям.

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

Почему традиционная инженерная дисциплина терпит неудачу здесь

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

Системы на основе LLM нарушают это предположение. Компонент, который производит ваш вывод, находится вне вашего контроля. Вы не можете сравнить версии модели с 4.0 на 4.5. Это полная замена функциональности, от которой зависит ваша система. Это то, что мы называем «бесконечным радиусом воздействия»: изменения, последствия которых нельзя заранее перечислить, потому что пространство ввода (естественный язык) и типы сбоев (все, что модель может сделать иначе) являются неограниченными.

Анатомия сбоя

Анализ причин сбоя показал, что наш промпт всегда был недоопределен. Мы проинструктировали модель вернуть JSON-объект с тремя полями. Мы описали назначение каждого поля. Мы не указали явно, что поле `description` должно быть строкой на естественном языке и не должно содержать сериализованные представления других полей. Более ранние версии модели выводили это ограничение из контекста. Sonnet 4.5, очевидно, лучше справлялся с «полезными» форматировочными решениями, решив, что запрос на уточнение или включение тела запроса в описание делает ответ более полезным. С точки зрения модели, это была разумная интерпретация неоднозначной инструкции. Однако это нарушило предположения, на которых была построена наша система.

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

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

Архитектура «сначала эвалюации»

Дисциплина, которая закрывает этот пробел, заключается в том, чтобы рассматривать набор эвалюаций — а не промпт — как формальную спецификацию системы. Промпт — это реализация спецификации. Модель — это интерпретатор. Эвалюации — это сама спецификация, и любое изменение модели или промпта считается действительным только в том случае, если оно проходит их.

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

def test_description_contains_no_serialized_payload(response):
    desc = response['description'].lower()
    forbidden = ['curl', 'post_body', '{', 'http://', 'https://']
    assert not any(token in desc for token in forbidden), \
        f'description leaked structured content: {response['description']}'

Несколько сотен таких свойств, некоторые написанные вручную для известных важных инвариантов, некоторые сгенерированные как регрессионные тесты из реального производственного трафика, некоторые оцененные LLM-как-судьей для более расплывчатых качеств, таких как тон, становятся «воротами». Обновления моделей и изменения промптов должны рассматриваться как pull request, которые должны сделать набор эвалюаций зеленым перед слиянием.

Эвалюации дороги в создании и поддержке. Они дрейфуют по мере изменения вашего продукта. Оценка LLM-как-судьей вносит свою собственную вариативность в результаты. И набор эвалюаций может выявить только те типы сбоев, о которых вы подумали, что нужно указать — вы не можете «эвалюировать» свой путь к безопасности от категории сбоев, которую вы никогда не представляли.

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

Дорожная карта

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

By Дмитрий Корсаков

Дмитрий Корсаков - спортивный журналист с 15-летним опытом работы в Екатеринбурге. Специализируется на освещении хоккея и фигурного катания. Начинал карьеру как блогер, сейчас - штатный автор нескольких федеральных спортивных изданий.

Related Post