Две категории проблем
Миграция на Claude 5 даёт сбои двух разных типов, и опаснее вторая. Первая — явные ошибки 400: запрос отклоняется, вы видите сообщение и чините. Неприятно, но заметно.
Вторая — молчаливые изменения умолчаний. Код продолжает работать, ошибок в логах нет, а поведение изменилось: где-то вырос счёт, где-то опустел интерфейс. Такие вещи обнаруживаются через неделю по биллингу, а не по мониторингу.
Что теперь возвращает ошибку 400
Четыре вещи, которые надо вычистить из запросов перед сменой идентификатора модели.
- Префилл ассистента отклоняется на Fable 5, Opus 5, Sonnet 5 и всей ветке 4.6–4.8.
- Параметр output_format устарел, используется вложенный output_config.format.
- Идентификаторы Claude 5 самодостаточны — даты не дописываются.
| Что убрать | Чем заменить |
|---|---|
| thinking с budget_tokens | thinking типа adaptive и effort в output_config |
| temperature, top_p, top_k | Ничем — управление идёт через усилие |
| Префилл ответа ассистента | output_config.format или инструкция в системном промпте |
| Суффикс с датой в идентификаторе | Чистый идентификатор вида claude-opus-5 |
Тихие изменения, которых не будет в логах
Первое: на Opus 5 мышление включено по умолчанию. Если вы переезжаете с Opus 4.8 или 4.7, где отсутствие параметра означало «не думать», тот же самый код начнёт думать — и подорожает. Ошибки при этом не будет.
Второе: отображение рассуждения по умолчанию переключилось на пустое. Интерфейсы, показывавшие ход мысли, перестанут его показывать. Тоже без ошибок.
Третье: токенизатор. У Fable 5, Opus 5, Opus 4.8 и 4.7 он общий; при переезде между ними счётчики почти не меняются. А вот с Opus 4.6, Sonnet, Haiku и более старых моделей число токенов на том же тексте может вырасти примерно до полутора раз — то есть счёт изменится при неизменном коде. Перед переездом стоит перемерить объём подсчётом токенов, а не оценкой на глаз.
- Opus 5 думает по умолчанию — проверьте, ожидали ли вы этого.
- Ход рассуждения в интерфейсе надо запрашивать явно.
- С моделей до 4.7 включительно — перемерьте токены.
Новая причина остановки: отказ
У актуальных моделей появилась причина остановки refusal — отказ по соображениям безопасности. Приходит она обычным успешным ответом с кодом 200, а рядом лежит объект с категорией отказа и пояснением.
Код, который читает содержимое ответа, не проверив причину остановки, на таком ответе поведёт себя непредсказуемо: содержимое пустое или неполное, исключения нет. Проверка причины остановки перед чтением содержимого — обязательный шаг.
Важная деталь: объект с деталями остановки заполняется только при отказе. При обычном завершении, при упоре в max_tokens, при вызове инструмента он пустой, поэтому обращаться к его полям надо с проверкой.
- Отказ — это HTTP 200, а не исключение.
- Проверяйте причину остановки до чтения содержимого.
- Детали остановки заполнены только при отказе.
Инструменты и разбор ответов
Если вы используете серверные инструменты вроде веб-поиска, проверьте версию типа инструмента: на актуальных моделях доступны более новые варианты с динамической фильтрацией, и старые версии от них отличаются возможностями. Ещё одна деталь: у новых вариантов исполнение кода работает под капотом, поэтому отдельно объявлять инструмент исполнения кода не нужно — вторая среда исполнения только запутает модель.
И отдельная ловушка при разборе вызовов инструментов: модели Claude 5 могут иначе экранировать строки в JSON аргументов вызова — например, юникод или прямые слеши. Разбирайте аргументы штатным парсером JSON. Код, который делает поиск подстроки по сериализованному вызову, сломается на первом же нестандартном экранировании.
Ошибки серверных инструментов, кстати, тоже не выбрасываются как исключения: приходит успешный ответ, внутри которого лежит объект ошибки вместо списка результатов. Ветвиться нужно по типу содержимого.
- Проверьте версии типов серверных инструментов.
- Аргументы вызова инструментов — только через парсер JSON.
- Ошибка серверного инструмента приходит внутри успешного ответа.
Длинные ответы требуют стриминга
Актуальные модели поддерживают до 128 тысяч токенов на выход, но при больших значениях max_tokens обычный запрос упирается в таймаут HTTP раньше, чем модель закончит. Для таких запросов нужен потоковый режим — а если отдельные события потока вам не нужны, у SDK есть штатный помощник, который возвращает уже собранное финальное сообщение.
Заодно пересмотрите max_tokens: слишком маленькое значение обрезает ответ на середине мысли и требует повторного запроса, то есть экономит на бумаге и удорожает на практике.
- Большие max_tokens — только потоковый режим.
- Слишком низкий max_tokens обходится дороже, чем кажется.
- Таймаут клиента считается на попытку, а повторы его умножают.
Чек-лист перед переключением
Порядок действий, который экономит время: сначала чистим запрещённые параметры, потом фиксируем ожидаемое поведение мышления, потом перемеряем токены и только затем меняем идентификатор модели на проде.
- Убрать budget_tokens, параметры сэмплирования и префилл.
- Явно задать режим мышления и уровень усилия под каждый маршрут.
- Явно задать отображение рассуждения, если оно видно пользователю.
- Перемерить токены подсчётом, если переезжаете с моделей до 4.7.
- Добавить проверку причины остановки перед чтением содержимого.
- Перевести запросы с большим max_tokens на потоковый режим.
- Убрать суффиксы с датами из идентификаторов моделей.