OpenAI-совместимый endpoint: что менять в коде, а что нет
Хорошая совместимость выглядит скучно: вы меняете два поля, а приложение продолжает думать, что разговаривает с OpenAI. Плохая совместимость начинается там, где «почти такой же» ответ ломает streaming, usage или обработку ошибок. Поэтому миграцию проверяем не по лендингу, а по четырём точкам: base URL, ключ, формат ответа и поведение стрима.
- В коде меняются
base_urlиapi_key. - Модель выбирается строкой из тарифа, а не привязкой к вендору.
- Streaming и ошибки проверяются отдельным запросом до переключения трафика.
1. Миграция — это два поля
В OpenAI SDK достаточно заменить адрес и ключ:
from openai import OpenAI
client = OpenAI(
api_key="ВАШ_КЛЮЧ",
base_url="https://postcorporate.tech/v1",
)
resp = client.chat.completions.create(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "привет"}],
stream=True,
)
Если приложение уже использует официальный SDK, менять сериализацию сообщений не нужно. Роль, content, tools, response_format и stream уезжают в том же виде.
2. Модель — это строка тарифа, а не религия
После смены endpoint не тащите за собой старую карту «вендор → модель». Смотрите на текущую таблицу цен и берите модель по задаче: фронтир для сложного кода, китайские модели для дешёвой рутины, vision-варианты для скриншотов. Один ключ не означает одну модель: он означает один баланс и один набор ограничений.
3. Streaming проверяется отдельно
Синхронный ответ может быть идеальным, а стрим — ломаться на SSE-разделителях или финальном usage. Минимальная проверка:
curl -N https://postcorporate.tech/v1/chat/completions \
-H "Authorization: Bearer ВАШ_КЛЮЧ" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet-5","stream":true,
"messages":[{"role":"user","content":"считай до трёх"}]}'
Смотрите, что события идут постепенно, завершаются [DONE], а клиент не повисает без таймаута.
4. Ошибки должны оставаться машиночитаемыми
Нормальный gateway не прячет 401/402/429/500 в HTML-страницу. Проверьте намеренно неверный ключ и слишком большую модель: код ошибки и JSON должны быть пригодны для retry-логики, а не для парсинга глазами.