Система делала одну вещь, и делала её хорошо: превращала вопросы на естественном языке в API-запросы. Пользователи - аналитики, аккаунт-менеджеры, операционные руководители. Они знали, какие данные им нужны, но собирать их вручную означало лазить по четырём дашбордам, двум BI-инструментам и билдеру отчётов Salesforce. Система решала это одной фразой. А потом Claude обновился. Новости claude anthropic пишут о таких кейсах всё чаще, и этот - один из самых поучительных.

Как это работало

Пользователь печатал что-то вроде «Собери отчёт по объёму продаж за январь–март 2026 по Северо-Восточному региону, с разбивкой по городам». Система превращала это в JSON-объект с тремя полями: description, api_call, post_body - и отправляла запрос в нужный бэкенд. К середине 2025 года система генерировала несколько сотен отчётов в месяц. Отчёты читало руководство, их рассылали внешним стейкхолдерам. Система стала основным способом получать ad-hoc данные.

Стек был собран на Claude Sonnet 3.5 в начале 2025 года. Переход на 3.7 прошёл без инцидентов, на 4.0 - тоже. Когда вышла версия 4.5, команда уже привыкла: обновление модели - это как поднять минорную версию библиотеки. Никто не ждал подвоха.

Что пошло не так с Sonnet 4.5

Первое: модель начала складывать содержимое post_body в поле description. Параметры фильтра не доходили до API - бэкенд возвращал данные за всё время или падал с 500-й ошибкой.

Второе: модель начала задавать уточняющие вопросы. Раньше она всегда брала лучшее приближение и возвращала структуру. Sonnet 4.5 решила, что вежливее спросить. У системы не было маршрута для этого - она умела только вызывать API.

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

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

Инженерия ПО держится на способности ограничить эффект от изменений. Ты обновляешь драйвер или библиотеку - читаешь release notes, прогоняешь юнит-тесты. Система детерминирована настолько, что её поведение можно предсказать или хотя бы плотно засэмплировать. Радиус взрыва (blast radius) ограничен по построению.

Системы на LLM ломают это допущение. Компонент, который производит твой выход, не под твоим контролем. Ты не можешь сделать diff между моделью 4.0 и 4.5. Это полная замена функциональности, от которой зависит вся система.

«Infinite blast radius - это изменение, чьи эффекты невозможно перечислить заранее, потому что и входное пространство (естественный язык), и режимы отказов (всё, что модель может сделать иначе) - оба безграничны»

Анатомия ошибки: промпт был недоопределён

Постмортем показал: промпт всегда был недоопределён. Команда сказала модели вернуть JSON с тремя полями. Описала, для чего каждое. Но не сказала явно, что description - это строка на естественном языке и не должна содержать сериализованные представления других полей.

Ранние версии модели выводили это ограничение из контекста. Sonnet 4.5, будучи «более полезной» в форматировании, решила, что уточнить вопрос или вставить тело запроса в описание - полезнее для пользователя. С точки зрения модели - разумная интерпретация неоднозначной инструкции. Но она нарушила допущения, на которых была построена система.

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

«Тот факт, что три предыдущих обновления прошли гладко, не значит, что четвёртое пройдёт. Каждый апгрейд модели - это замена чёрного ящика, поведение которого ты не контролируешь»

Архитектура evals-first

Дисциплина, которая закрывает этот разрыв - относиться к eval-сюите как к формальной спецификации системы. Промпт - это реализация спецификации. Модель - интерпретатор. Evals - сама спецификация. Любое изменение модели или промпта валидно только если проходит её.

Для этого кейса eval, который поймал бы регрессию 4.5, выглядел бы так: проверка, что поле description не содержит сериализованных полезных нагрузок. Несколько сотен таких свойств - написанных вручную для известных инвариантов, сгенерированных из продакшен-трафика, оценённых LLM-as-judge для размытых характеристик вроде тона - становятся шлюзом.

Как строить evals: три слоя

1. Ручные проверки - критические инварианты: «description не содержит JSON», «api_call всегда начинается с /api/»

2. Регрессионные тесты - из реальных продакшен-запросов, которые когда-либо ломались

3. LLM-as-judge - для размытых метрик вроде тона, полноты, релевантности

Проблема в том, что evals дороги в поддержке. Они дрейфуют вместе с продуктом. LLM-as-judge вносит собственную дисперсию. И сюита ловит только те режимы отказов, которые ты додумался специфицировать. Никто в той команде не написал проверку «поле description не должно содержать curl-команду» - потому что никому не приходило в голову, что модель может её туда вставить.

Что это значит для бизнеса

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

Для компаний во Владивостоке и на Дальнем Востоке, которые только начинают внедрение искусственного интеллекта, этот кейс особенно показателен. Проблема не в том, какую модель выбрать. Проблема в том, как выстроить систему так, чтобы смена модели не ломала продукт. Автоматизация бизнес-процессов с помощью ИИ должна строиться не вокруг конкретной модели, а вокруг eval-сюиты, которая определяет, что такое «хорошая работа».

Потому что модели будут меняться. Гарантии стабильности не даёт ни один вендор. Единственный способ защититься - перестать считать промпт спецификацией и начать считать evals ей. Это непривычно, дорого и требует дисциплины. Но альтернатива - однажды обнаружить, что ваш Claude «поумнел», и ваш продукт перестал работать.