API и разработка

OpenAI-совместимый API: что проверить перед сменой base URL

Практический разбор совместимости API: адрес, модели, Chat Completions, параметры, SDK, ошибки и тесты, которые нужны до переключения приложения.

Редакция KvantoraТематический выпуск: Около 5 минут чтения
Обложка статьи «OpenAI-совместимый API: что проверить перед сменой base URL»

OpenAI-совместимый API обычно позволяет переиспользовать знакомый клиент и часть запросов, но не обещает все методы и параметры OpenAI. Перед сменой base URL сравните фактически используемый контракт, запустите узкий тест и проверьте обработку незавершённого ответа.

Совпадение формы — только начало

Если сервис принимает POST /v1/chat/completions с полями model и messages, существующий SDK может отправить первый запрос после смены адреса. На этом сходство не заканчивается, но и не становится полным. Различаться могут названия моделей, допустимые response_format, инструменты, обработка медиа и структура ошибок. Список несовместимостей нужен до изменения кода, а не после инцидента.

Составьте инвентарь одного рабочего сценария: endpoint, методы SDK, параметры, заголовки, ожидаемые поля ответа и поведение при повторе. Затем сопоставьте с матрицей нового маршрута. Если вы используете только текстовые Chat Completions, перенос может быть небольшим. Если задействованы hosted tools или строгое соответствие JSON Schema, понадобится отдельное проектное решение.

Адрес, ID и настройки SDK

Для примеров Kvantora переменная KVANTORA_BASE_URL содержит origin https://api.kvantora.ai. При настройке OpenAI SDK базовый адрес заканчивается на /v1; не добавляйте этот суффикс дважды. Публичный ID берите из /models или GET /v1/models, а не из старого кода поставщика. Перед запросом проверьте, что карточка разрешает нужную операцию.

Ключ храните только в серверном окружении. Он не должен попасть в NEXT_PUBLIC переменную, URL, сообщение об ошибке или браузерный bundle. Выдайте доступ к необходимым операциям и установите бюджет. Даже если тестовый запрос короткий, он показывает реальный доступ и может создавать расход; для первого шага используйте каталог и оценку без генерации.

SDK может автоматически повторять некоторые ошибки. Для обычного API это удобно; для платного вызова с неизвестным исходом нужна явная политика восстановления. В документированном примере Kvantora OpenAI SDK создаётся с maxRetries: 0, а логический запрос несёт Idempotency-Key. Сохраните то же тело и ключ до отправки. Если соединение исчезнет, восстанавливайте именно эту работу.

Пример конфигурации ниже показывает только настройку клиента; он не делает платного вызова. Переменные должны быть заданы на сервере, а ID модели подтверждён каталогом. После конфигурации проверьте реальные методы по документации Kvantora, поскольку сходство SDK не подтверждает каждый параметр конкретной версии.

JavaScript
import OpenAI from 'openai';
const client = new OpenAI({
  apiKey: process.env.KVANTORA_API_KEY,
  baseURL: process.env.KVANTORA_BASE_URL.replace(/\/$/, '') + '/v1',
  maxRetries: 0,
});

Ответ бывает не завершён

Успешный текстовый ответ ожидается в choices[0].message.content, но состояние расчёта тоже существенно. В быстром старте Kvantora завершённый клиентский результат признаётся только при объекте chat.completion и billing.status=settled. HTTP 202 обозначает ещё не готовый результат. Если приложение покажет его как пустой готовый ответ, пользователь может отправить запрос снова.

Для потоковой выдачи проверка ещё строже: получение первых символов не подтверждает окончание расчёта. Сохраняйте состояние до завершающего события и итоговых данных. При неполном потоке не делайте вид, что ответ завершён; восстановите запрос по его идентичности и покажите пользователю понятное состояние ожидания.

Проверяйте поле за полем

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

Не копируйте в собственный клиент все типы OpenAI SDK как обещание нового сервиса. Типы описывают возможности библиотеки, а сервер вправе принять меньше. В продукте оставьте только проверенное подмножество и сообщайте о недоступной функции до отправки платного запроса. Это избавляет пользователя от загадочного отказа после загрузки большого документа.

Минимальная матрица переноса

Проверьте положительный текстовый запрос, неверный ID модели, отсутствующее право ключа, недостаточный бюджет, лимит частоты и потерю соединения после отправки. Для каждого случая заранее запишите ожидаемое действие клиента. Неправильный параметр надо исправлять, а не повторять. Неизвестный исход надо выяснять, а не отправлять с новым ключом.

После локальной проверки сравните затраты и качество на нескольких одинаковых входах. Смена маршрута может поменять доступную модель и вывод даже при одинаковой форме JSON. Держите возможность вернуть прежнюю конфигурацию, пока тестовый трафик не подтвердит ожидаемое поведение.

Наиболее частая ошибка переноса появляется не в простом запросе, а в промежуточном состоянии. Старый клиент привык считать любой успешный HTTP-ответ готовой генерацией, а новый маршрут может сообщить об ожидании. Добавьте отдельную проверку статуса и расчёта в адаптер. Тогда UI не предложит пользователю повторить работу лишь потому, что ему пока нечего показать.

Когда «совместимый» не подходит

Если продукт критически зависит от функции, которой нет в новом контракте, честный ответ: оставить этот сценарий на старом маршруте или изменить архитектуру с отдельным тестом. Эмуляция недоступного режима через подсказку часто создаёт иллюзию гарантии. Например, просьба «ответь строго JSON» не равна серверной проверке схемы, а красивый ответ модели не выполняет внешнее действие.

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

Источники