RU ▾

Отличия OpenAI-совместимого API от OpenAI

Два похожих соединительных разъема, сравниваемых штангенциркулем, показывающие различия между совместимыми API

Совместимость означает, что структура запросов и ответов совпадает, а не то, что сервисы одинаковы. Вот различия OpenAI-совместимого API от OpenAI, которые часто становятся неожиданностью, и конкретные пробелы в этом API.

Последнее обновление:

Итоги

  • Совместимость охватывает сетевой формат: структуру URL, аутентификацию Bearer, поля JSON и потоковую передачу SSE.
  • Идентификаторы моделей, лимиты, детали ошибок и дополнительные эндпоинты — это части, которые различаются у разных провайдеров.
  • Это API предлагает одну модель (uncensored), только текст, без эмбеддингов, изображений, аудио или дообучения.
  • Протестируйте именно те параметры, от которых вы зависите, перед миграцией, вместо того чтобы предполагать полное соответствие.

Что на самом деле гарантирует совместимость

API, совместимый с OpenAI, принимает те же HTTP-запросы, что и SDK OpenAI. Вы меняете базовый URL и ключ, и клиент продолжает работать. Это обещание закреплено на уровне протокола: путь /v1/chat/completions, токен Bearer в заголовке Authorization, тело JSON с полями model и messages, а также ответ с полями choices и usage. Потоковая передача следует тому же шаблону серверных событий (SSE).

Оно не гарантирует ту же модель, то же поведение, те же лимиты или тот же набор эндпоинтов. Компания, стоящая за оригинальным API, решает, что она предоставляет, а каждый другой провайдер самостоятельно решает, что копировать. Рассматривайте совместимость как способ избежать переписывания кода клиента, а не как гарантию того, что ничего больше не изменится.

Различия рядом

Таблица перечисляет области, которые различаются у провайдеров, и то, что верно для этого API. Правый столбец — это подсказка для вашего собственного тестирования при оценке любого сервиса.

ОбластьЭтот APIЧто проверять у любого провайдера
Идентификаторы моделейОдин идентификатор: uncensoredПринимается ли старое имя модели, отображается ли оно или отклоняется
Эндпоинты/v1/chat/completions, /v1/responses, /v1/modelsСуществует ли каждый эндпоинт, который вызывает ваш код
МодальностиТолько текстПоддержка изображений, аудио и видео, если она вам нужна
Эмбеддинги, дообучениеНе предлагаетсяКуда будут перенаправлены эти вызовы
Контекстное окно100 000 токенов, промпт плюс завершениеПокрывает ли лимит только ввод или оба направления
Параллельные запросы и лимитыПолный ключ: 8 одновременно, 300 в минуту. Пробный ключ: 2 одновременно, 60 в минутуКак измеряются лимиты и как сообщается об отказе
Вызов функций, режим JSONПоддерживаетсяСлучаи на границе, такие как потоковая передача вызовов функций
Поведение по контентуНастроена на ответы без отказов по контенту для законного использования взрослымиСлои модерации, которые изменяют то, что возвращает модель
БиллингПредоплаченный баланс, за токен, без подпискиМинимумы, срок действия, уровни подписки

Строка цен для этого API: $0,15 за 1M входных токенов и $0,50 за 1M выходных токенов. Для любого другого сервиса прочитайте его текущую страницу с ценами, а не полагайтесь на память или сводки третьих лиц.

Идентификаторы моделей и поведение

Самое существенное различие — это сама модель. В OpenAI вы выбираете из меню именованных моделей. Здесь вы отправляете "model": "uncensored" и получаете одну модель с открытыми весами от независимого провайдера. Это не официальное API какого-либо поставщика моделей и не маршрутизатор, перенаправляющий запросы нескольким поставщикам.

Это имеет два следствия. Во-первых, вы не можете проводить A/B-тестирование размеров моделей, меняя строку; вы запускаете одну модель и настраиваете промпты и параметры сэмплирования вокруг нее. Во-вторых, промпты, написанные для другой модели, могут потребовать небольших правок, потому что следование инструкциям, привычки форматирования и поведение при отказе различаются. Эта модель настроена на ответы без отказов по контенту для законного использования взрослыми, поэтому промпт с длинными преамбулами безопасности, написанными для более строгой модели, часто можно сократить.

Одно жесткое ограничение не меняется: нет сексуального контента с участием несовершеннолетних.

Эндпоинты и функции, которых нет

Совместимость редко бывает полной по всей поверхности OpenAI. Здесь пробелы намеренные: сервис обрабатывает только текст.

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

Имеющихся возможностей хватает для большинства чат-приложений: POST /v1/chat/completions, POST /v1/responses, потоковая передача, вызов инструментов с помощью tools и tool_choice, а также JSON-режим через response_format. Контрольные параметры сэмплирования, такие как temperature, top_p, stop, seed и штрафы, передаются модели.

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

Лимиты, ошибки и заголовки

Лимиты — это то место, где миграции удивляют людей, потому что они определяют, как ваш код должен вести себя под нагрузкой. Это API устанавливает 8 параллельных запросов и 300 запросов в минуту для полного ключа, 2 и 60 для пробного ключа, и максимальный размер тела 8 МБ. Запрос, превышающий лимит, возвращает HTTP 429. Код ошибки указывает, какой лимит вы исчерпали: rate_limited для запросов в минуту, concurrency для слишком большого количества запросов одновременно. Временная перегрузка также возвращает 429 и добавляет Retry-After: 5.

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

Ответы включают X-Request-Id, X-Balance-USD, X-RateLimit-Limit-Requests и X-RateLimit-Limit-Concurrency. Заголовок баланса — это дополнительная информация от провайдера: код SDK OpenAI игнорирует его, но вы можете прочитать его для отслеживания расходов. Баланс также доступен через GET /v1/balance и в стиле OpenAI через GET /v1/dashboard/billing/credit_grants.

Чек-лист миграции

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

  1. Замените базовый URL, ключ и идентификатор модели одновременно и поищите в репозитории старые имена моделей, спрятанные в файлах конфигурации.
  2. Удалите вызовы эндпоинтов, которых нет на новой стороне, и перенаправьте их к провайдеру, у которого они есть.
  3. Запустите набор промптов и сравните результаты. Ожидайте другого словесного оформления и форматирования от другой модели.
  4. Протестируйте потоковую передачу через каждый прокси и балансировщик нагрузки между вашими пользователями и API.
  5. Добавьте логику повторных попыток для 429, которая считывает код ошибки и заголовок Retry-After.
  6. Логируйте использование токенов на каждый запрос, чтобы неожиданные расходы проявлялись в течение дней, а не в конце месяца.

Быстрый тест совместимости

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

from openai import OpenAI

client = OpenAI(
    base_url="https://api.apicompatible.com/v1",
    api_key="YOUR_API_KEY",
)

# 1. Plain completion
r = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Reply with the word ready."}],
    temperature=0,
    seed=7,
)
print("plain:", r.choices[0].message.content)

# 2. JSON mode
j = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Return a JSON object with keys name and age for a fictional person."}],
    response_format={"type": "json_object"},
)
print("json:", j.choices[0].message.content)

# 3. Streaming
chunks = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Count from one to five."}],
    stream=True,
)
print("stream:", "".join(c.choices[0].delta.content or "" for c in chunks if c.choices))

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

Часто задаваемые вопросы

Является ли совместимое с OpenAI API таким же, как OpenAI?

Нет. Оно принимает запросы в том же стиле, но модель, лимиты, эндпоинты и политики принадлежат провайдеру, который его обслуживает. Это API не управляется компанией OpenAI или каким-либо поставщиком моделей.

Могу ли я продолжать использовать SDK OpenAI?

Да. Измените базовый URL на https://api.apicompatible.com/v1, используйте свой ключ и укажите идентификатор модели uncensored.

Поддерживает ли это API эмбеддинги или дообучение?

Нет. Это только текст, с завершениями чата, ответами и списком моделей. Для эмбеддингов, изображений или дообучения используйте другого провайдера.

Как узнать, какой лимит вы исчерпали при ошибке 429?

Прочитайте код ошибки в ответе. rate_limited означает слишком много запросов в минуту, concurrency — слишком много одновременно, а заголовок Retry-After со значением 5 указывает на временную перегрузку.

Получите свой ключ за секунды

Зарегистрируйтесь, скопируйте токен, обновите URL эндпоинта. Это вся необходимая конфигурация.

Открыть аккаунт