Переезд на GPT-5.6: что мы переписали в коде и как изменился счёт за API

от автора

Мы делаем сервис доступа к моделям разных провайдеров, так что интерес в этой теме у нас прямой. В середине июля мы переносили внутренние сервисы на GPT-5.6. Работы планировали на день, но ушло две недели.

Ниже по порядку: что поменялось в линейке за одно поколение, во сколько после этого обходится один запрос и где ломается код, который формально продолжал работать.

Почему мы поехали на 5.6

GPT-5.6 вышла в общий доступ 9 июля 2026 года. В линейке три модели: флагманская Sol, средняя Terra и самая дешёвая Luna. У всех трёх контекст 1,05 млн токенов и максимальный вывод 128 тысяч. Если переводить в привычные единицы, в контекст влезает от тысячи до полутора тысяч страниц русского текста, а в один ответ около двухсот.

Причина переезда была в оплате. После июльского снижения цен Terra стала стоить $2 за миллион входных токенов и $12 за миллион выходных, то есть дешевле GPT-5.4 ($2,50 и $15) при сопоставимом для наших задач качестве. Так мы переезд и планировали: снять всё с 5.4 и поставить Terra.

Цены на день публикации:

Цена Sol здесь промо-акционная. OpenAI снизил её 21 августа с $5 и $30 и обещает держать минимум до 21 ноября 2026 года, а что будет дальше, не объявлял. В расчёт стоимости запроса ниже промо-цена входит, потому что платим мы сегодня по ней, а в планирование на квартал вперёд мы закладываем базовые $5 и $30.

Что пришлось переписывать в коде

Суффиксы уровней перестали работать

Раньше уровень модели кодировался суффиксом: gpt-5.4, gpt-5.4-mini, gpt-5.4-nano. В коде у была функция, которая собирала идентификатор из двух кусков: номера поколения и уровня из конфига. Дефис перед уровнем она добавляла, только если уровень не пустой.

В GPT-5.6 цифра стала означать поколение, а уровни получили собственные имена: gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna. Значения mini и nano в новой линейке не существуют, поэтому при переезде мы просто вычистили их из конфига, собираясь потом проставить нормальные. Функция получила пустой уровень, дефис не добавила и вернула gpt-5.6. Это валидный идентификатор: алиас, который ведёт на Sol. Сервис не упал, ошибки не выдал и две недели ходил на флагмане вместо Terra, то есть по цене вдвое выше запланированной. Заметили мы это по счёту: в ответах разница на глаз не читалась.

Проверьте у себя все места, где идентификатор модели собирается из кусков. На новой линейке такая сборка либо отвалится с 404, либо, что хуже, не отвалится.

Запись в кэш стала платной

До GPT-5.6 кэширование промпта работало само и стоило только денег за первый запрос: повторные обращения читали совпадающий префикс со скидкой, отдельной платы за создание кэша не было. С 5.6 запись тарифицируется по коэффициенту 1,25 к обычной входной ставке, а чтение стоит 10% от неё.

Заодно появились явные точки разрыва: параметр prompt_cache_breakpoint и prompt_cache_options с временем жизни 30m. Минимальное время жизни выросло с прежних пяти-десяти минут до получаса, и это хорошая новость: раньше при неравномерной нагрузке срок кэша заканчивался раньше, чем мы успевали отправить второе обращение к тому же документу.

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

У длинного контекста свой тариф

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

В привычных единицах это от трёхсот до четырёхсот страниц. Звучит как величина, до которой обычная задача не дотянется, но в агентской цепочке вход растёт на каждом шаге: мы досылаем историю диалога, результаты инструментов и приложенные пользователем файлы. Стоит на последнем шаге приложить один PDF, и по удвоенной ставке пересчитается вся ветка.

Мы теперь считаем длину входа до отправки. Если она подбирается к порогу, либо режем историю, либо уводим задачу на Luna. Второе спасает не от множителя, он одинаково применяется ко всем моделям линейки, а от базовой ставки: у Luna вход в двадцать раз дешевле, чем у Sol, так что даже с удвоением такой запрос обходится дешевле, чем обычный запрос к флагману.

Сколько на самом деле стоит один запрос

Прайс в долларах за миллион токенов плохо ложится на интуицию. Пока не переведёшь его в цену одного обращения, непонятно, что вообще значит разница между $2 и $4 за миллион, и этот перевод мы сделали для себя в первую же неделю.

На латинице один токен покрывает примерно четыре символа, на кириллице два-три, потому что русские символы занимают по два байта и слова чаще дробятся. Страница A4 русского текста на 2000 знаков даёт 700–1000 токенов. Вход и выход тарифицируются отдельно, выход дороже входа в пять-шесть раз в зависимости от модели.

Берём обращение: две страницы на вход (2000 токенов) и страница на выход (1000 токенов). По курсу ЦБ на 26 августа доллар стоил 84,46 ₽, так что рублёвые цифры в правой колонке верны только на эту дату.

Разрыв между флагманом и бюджетной моделью на одном и том же запросе в семнадцати с половиной раз. Эта цифра поменяла наш план переезда. Мы шли ставить везде Terra, а после расчёта сделали дефолтом Luna и оставили Terra на ассистентах и разборе документов, где она действительно нужна. Sol теперь включается точечно, там, где Luna уже ошиблась на конкретном типе задач.

Кэш срабатывает вторым рычагом, но только на подходящем сценарии: длинная стабильная часть в начале, переменная задача в конце. У нас это обработка одного документа несколькими разными промптами подряд. Документ на 20 тысяч токенов, отправленный десять раз на Sol без кэша, обходится в $0,80. С кэшем первое обращение стоит дороже обычного, $0,10 вместо $0,08, потому что в него входит платная запись, зато девять следующих идут по $0,008. Итого $0,17 против $0,80, экономия почти в пять раз. Работает это при точном совпадении префикса и на запросах от 1024 токенов, ниже порога кэш не включается вообще.

Для ночных задач гоняем Batch API: он режет обе ставки вдвое, ответ приходит в течение суток. Для чат-бота бесполезно, для пересчёта эмбеддингов и разметки датасета подходит идеально.

Час на пустой переменной

Всё, что выше, можно вычитать из документации. Дальше история, которой в ней нет.

Ключ мы держали в переменной окружения, сервис читал его при старте. Мы экспортировали ключ в терминале, прогнали скрипт руками, получили ответ, задеплоили. На проде сервис начал отвечать 401 на каждый запрос:

{  "error": {    "message": "Incorrect API key provided: . You can find your API key at https://platform.openai.com/account/api-keys.",    "type": "invalid_request_error",    "code": "invalid_api_key"  }}

Первая версия была, что ключ отозвали или он не пережил деплой, и она увела нас в сторону примерно на час. Мы его перевыпустили, проверили баланс проекта, проверили права, стали смотреть, не начались ли проблемы у OpenAI. Всё было в порядке. Переменная в проде оказалась пустой: процесс запускался супервизором, который не наследовал окружение интерактивной сессии, где мы этот ключ и экспортировали.

Ответ был прямо в тексте ошибки. Посмотрите на кусок Incorrect API key provided: .: после двоеточия там нет ничего. Мы прочитали эту строку несколько раз подряд и каждый раз видели в ней сообщение о неправильном ключе.

SDK не проверяет, что в переменной вообще что-то есть. Он берёт значение, подставляет в заголовок Authorization: Bearer и отправляет запрос. Заголовок формально на месте, токен в нём пустой, сервер отвечает invalid_api_key. С точки зрения API вы прислали неправильный ключ. С точки зрения вашего кода вы прислали переменную, которую сами же и определили.

У 401 есть ещё два источника, которые в поддержку приносят даже чаще. Первый источник это угловые скобки: в документации ключ обозначен плейсхолдером <YOUR_API_KEY>, и его копируют вместе со скобками. Второй это пробел или перенос строки в конце при копировании из кабинета, их вообще не видно глазами.

Поэтому если поймали 401, а ключ точно рабочий, дальше стоит идти цифрами. Печатать сам ключ в логи не нужно и опасно, достаточно длины:

printf "%s" "$OPENAI_API_KEY" | wc -c

Это первое, что мы просим прислать, когда в чат приходят с 401.

Ноль закрывает вопрос сразу. Если число не совпадает с длиной ключа в кабинете на один-два символа, ищите скобки и пробелы. Печатать эту длину надо из окружения самого сервиса, а не из своего терминала: там и расходятся «работает у меня» и «не работает на проде». Причина при этом не обязана быть в супервизоре. Мы потом наступали на то же самое из-за .env, который никто не загрузил, потому что python-dotenv не был подключён, и из-за секрета в CI, названного иначе, чем переменная в коде.

С тех пор ключ в терминале не экспортируем вообще. Держим его в .env рядом с проектом или в менеджере секретов, а клиент при инициализации падает, если переменная пустая. Проверка в три строки дешевле часа в проде.

Лимиты, деньги и код 429

Пока на балансе ноль, API возвращает 429 с кодом insufficient_quota. По этому коду все ждут превышения скорости, а тут пустой счёт, и бэкофф не поможет ничем. Настоящее превышение приходит с rate_limit_exceeded, вот его действительно лечат очередью и экспоненциальной задержкой. Читать в обоих случаях нужно тело ответа: API отдаёт retry-after-ms и остаток по каждому лимиту, по ним видно, во что именно вы упёрлись.

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

Правило «сначала проверь статусную страницу провайдера, потом дебажь свой код» работает для массовых пятисотых и для отказов, которые начались у всех сразу. К единичному 401 на своём сервисе оно не относится, и в тот раз мы полезли смотреть статус OpenAI ровно потому, что перепутали одно с другим.

Доступ из России и четыре биллинга

Официальный сценарий занимает пять минут. Заходите на platform.openai.com, создаёте аккаунт, подтверждаете его номером телефона, добавляете карту, пополняете баланс. Ключ создаётся в разделе API keys, показывается один раз, начинается с sk-. Из России этот путь упирается сразу в три вещи, и обойти нужно все три одновременно. Запросы из неподдерживаемых сетей возвращают 403 с кодом unsupported_country_region_territory. Подтверждение аккаунта требует номера из поддерживаемой страны. Карты российских банков к биллингу не привязываются.

Есть и вторая причина, по которой к посредникам идут даже те, у кого с картой всё в порядке. Чуть выше написано, что при массовых пятисотых надо идти на статусную страницу провайдера. В такие дни выясняется неприятное. Пока фолбэк работает внутри одной линейки, он стоит одну строчку кода: Sol отдал 503, мы отправили задачу на Terra. Но если провайдер лёг целиком, соседняя модель не спасает, и нужен другой вендор, а это уже не строчка кода.

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

Мы и сделали агрегатор, чтобы свести эти четыре подключения к одному ключу и одному балансу: оплата рублями с российской карты или по счёту для юрлица, один комплект закрывающих. В коде меняются две строки: адрес в base_url и префикс провайдера в имени модели, openai/gpt-5.6-terra вместо gpt-5.6-terra. Переключение на другого вендора после этого сводится к правке той же строки: поменяли префикс, попробовали, сравнили счёт внутри одного биллинга.

Минусы тоже есть. Новые модели подключаем позже релиза, от нескольких часов до нескольких дней, так что в день выхода очередного поколения вы будете смотреть на него со стороны. Часть функционала платформы проходит не полностью: в n8n приходится снимать галочку Use Responses API, и вместе с ней отваливается встроенный веб-поиск, а асинхронные операции возвращают 201 вместо 200, из-за чего родной фреймворк OpenAI считает ответ ошибкой. Лимиты тоже свои и с официальными не совпадают.

Если провайдер у вас один и карта есть, всё это не нужно: официальный путь дешевле, функциональнее и быстрее по новым моделям.

Ещё про покупку доступа. В прайсе OpenAI есть GPT-5.6 Cyber по $12,50 и $75, но самостоятельно её подключить нельзя: доступ выдаётся через одобренных партнёров программы Daybreak после проверки организации. Всё, что продаётся на маркетплейсах под видом ключей к ней, скам по определению. То же касается «безлимитных ключей за 200 рублей»: это либо украденный ключ, который отключат в течение дня, либо ничего. И через чужой ключ проходят ваши промпты со всем, что в них лежит.

Что мы поменяли у себя после переезда

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

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

Если у вас на этой же линейке ломалось что-то другое, расскажите в комментариях.

ссылка на оригинал статьи https://habr.com/ru/articles/1075914/