Интеграцию, которую в поиске называют OpenAI Completions API, переносят на Responses API по одному рабочему сценарию: меняют адрес вызова, форму входа и чтение ответа, а прежний путь держат включённым рядом до тех пор, пока результаты сходятся. В руководстве OpenAI по миграции Chat Completions описан как поддерживаемый интерфейс, поэтому срочности нет, и перенос оправдан там, где сервису нужны встроенные инструменты или память диалога на стороне платформы. Если текущий вызов стабилен, покрыт тестами, а встроенные инструменты и память платформы ему без надобности, оставьте его как есть.
Что переносим
Chat Completions остаётся поддерживаемым, а Responses рекомендован для новых проектов, поэтому переносят по одному сценарию, с переключателем и сравнением выходов на фиксированном наборе примеров.
Возьмём внутренний сервис, который разбирает входящие письма по темам: на входе текст письма, на выходе JSON с темой и признаком срочности. Сейчас он шлёт запрос на /v1/chat/completions, передаёт массив messages с ролями system и user, читает choices[0].message.content и разбирает JSON собственным кодом. Именно такой вызов обычно и называют «completions api»: отдельная функция, одна задача, понятный контракт.
Причины для переноса OpenAI перечисляет в руководстве по миграции: несколько вызовов инструментов внутри одного запроса, состояние на стороне платформы, поддержка будущих моделей. Общий разбор нового интерфейса вынесен в статью про Responses API под один бизнес-сценарий, а здесь речь только о переезде уже работающей интеграции. Ключ и доступ к проекту описаны в материале про выдачу ключа и управление доступом.
Перед любыми правками составьте опись вызова: какие роли сообщений используются, есть ли описания функций, задан ли формат ответа, включён ли потоковый режим, где хранится история диалога, как обрабатываются ошибки. Опись превращается в список проверок, и каждый её пункт получает свой тест на следующих шагах.
Что меняется в вызове
Руководство OpenAI описывает различия по нескольким точкам. Таблица ниже сводит их к тому, что нужно найти в вашем коде и чем проверить.
| Элемент | Chat Completions | Responses | Что проверить у себя |
|---|---|---|---|
| Адрес | /v1/chat/completions | /v1/responses | Единая точка в клиенте, без десятка разбросанных строк |
| Вход | Массив messages с ролями | Поле input: строка или набор элементов | Как собирается контекст: инструкция, письмо, примеры |
| Чтение ответа | choices[0].message.content | Свойство output_text; полный выход состоит из типизированных элементов | Весь код, который разбирает ответ, включая обработку пустого результата |
| Формат ответа | Параметр response_format | Параметр text.format | Схема JSON и разбор на вашей стороне |
| Функции | Описание обёрнуто полем type | Описание без обёртки | Все схемы инструментов, имена и обязательные поля |
| Строгость схем | По умолчанию нестрогие | Без указания strict платформа пробует строгий режим, а при несовместимой схеме работает нестрого | Схемы, поведение которых меняется без правки кода; задайте strict явно |
Последняя строка таблицы скрывает сюрприз: поведение схемы меняется без единой правки в вашем коде. Строгий режим предъявляет к схеме дополнительные требования, и схема, прежде принимавшая лишние поля, может перестать им соответствовать. Задайте strict явно на обоих путях, запустите каждую схему отдельным тестовым вызовом и сохраните тексты ошибок. Эту работу выполняет разработчик с доступом к коду, и языковая модель здесь разве что собеседник: приняты ли все схемы, проверяет скрипт.
Если сервис выводит ответ по частям, обработчики потока тоже переписываются: события становятся типизированными, и каждый тип нужно обработать явно. Приёмы работы с потоком, отмену запроса и ошибку посреди ответа разбирает статья про потоковый режим OpenAI API; в переносе достаточно убедиться, что собранный из фрагментов текст совпадает с результатом обычного вызова.
Отдельно найдите места, где код опирается на форму ответа Chat Completions: поле choices, причину остановки, подсчёт токенов. Каждое такое место заверните в маленькую функцию-адаптер, чтобы остальной код получал одну и ту же внутреннюю структуру при любом интерфейсе. Адаптер потом и делает откат дешёвым.
Инструменты и состояние
Сервис разбора писем обходится без истории диалога, и переносить ему нечего: каждый вызов самодостаточен. Состояние понадобится, если рядом живёт другой сценарий, например уточняющий чат по сложному письму. Руководство называет три способа: связать ответы через previous_response_id, вручную вернуть в следующий запрос элементы предыдущего выхода либо воспользоваться Conversations API с постоянным объектом диалога.
Выбор определяется тем, кто хранит данные. Передача элементов вручную оставляет историю у вас: вы решаете, что сохранить, как долго и кому показать. Цепочка через идентификатор и объект диалога перекладывает хранение на платформу, и до включения на данных клиентов прочтите в документации, где и как долго они лежат. Для писем с персональными данными безопаснее начать с варианта, при котором история остаётся в вашей базе.
С инструментами схема похожая: функции вашей системы вызываются так же, но их результаты возвращаются в виде элементов нового формата. Платформенные инструменты вроде веб-поиска или поиска по файлам в первом переносе подключать незачем. Сначала добейтесь совпадения старого результата, затем добавляйте возможности по одной, каждую со своим тестовым набором. Первым переносят самый простой вызов, без инструментов и состояния.
Какой из ваших вызовов OpenAI перенести первым?
Тест совместимости
Если сервис разбора писем уже живёт на проде, его результаты есть, и это лучший тестовый материал. Соберите фиксированный набор обезличенных писем: типовые случаи, пограничные, пустое письмо, очень длинное, письмо на другом языке. Набор версионируйте рядом с кодом.
- Заведите переключатель в конфигурации: старый путь остаётся по умолчанию, новый включается для тестового запуска.
- Прогоните весь набор через оба пути и сохраните пары ответов вместе с техническим статусом каждого вызова.
- Сравнивайте смысл, а текст слово в слово оставьте в покое: совпала ли тема, признак срочности, структура JSON. Расхождения разберите вручную.
- Отдельно проверьте ошибочные случаи: неверная схема, слишком длинный вход, отозванный ключ. Платформа должна возвращать ошибку, а адаптер превращать её во внутренний статус.
- Зафиксируйте результат в журнале прогона: версия набора, версия инструкции, список расхождений и решение владельца сценария.
Совместимость допускает разные тексты: две корректные формулировки темы письма расходятся, а вот разный признак срочности для одного и того же письма считается дефектом. Заранее договоритесь, какие расхождения допустимы. Сравнение объёма расходов по токенам тоже включите в отчёт, но решение принимайте по качеству, а потом по цене, и цифры берите со страницы цен вендора, без опоры на память. Для общей практики замеров пригодится заметка про оценку моделей.
Откат и допуск
Откат готовят до первого запуска. Он состоит из переключателя, рабочего старого пути и условия, при котором переключатель возвращают: рост доли ответов с ошибкой разбора, расхождение признака срочности на контрольных письмах, жалобы сотрудников на качество. Условие записывают числом и владельцем решения до пилота. Без этого откат превращается в спор в момент сбоя, когда времени на разговоры уже нет, а у каждого участника своё представление о допустимом.
Запускайте новый путь на малой доле обращений, например на одном почтовом ящике, и держите старый путь работающим всё время наблюдения. Когда результаты стабильны, расширяйте долю. Старый код удаляют лишь после того, как на новом пути прошла полная смена обращений разных типов, а решение об удалении принимает владелец сервиса.
Пока работают оба пути, храните версию интерфейса в журнале каждого вызова: по ней видно, где возникла ошибка. Секреты и тексты писем в журнал исключены, достаточно технического идентификатора. Если перенос затрагивает сразу несколько сервисов, общий порядок работ описан на странице про внедрение ИИ в рабочие сервисы.
Выберите один вызов с одним форматом ответа, составьте опись по шести пунктам и соберите тестовый набор писем до первой строки нового кода. Первой метрикой возьмите долю совпавших признаков на контрольном наборе, а типичную ошибку ищите в схемах функций: режим strict подводит первым.