Переход с OpenAI или OpenRouter
Как подключить существующий код с библиотеками OpenAI к SpicyAPI: базовый URL, ключ, ID модели, отличия полей запроса и настройки, которые нужно убрать после OpenRouter.
Если ваш код уже вызывает чат-модель через официальные библиотеки OpenAI или инструмент с настройкой «совместимость с OpenAI», для перехода на SpicyAPI нужно изменить три значения: базовый URL, API-ключ и ID модели. На этой странице перечислены эти изменения и отличия в поведении, чтобы после миграции вы не столкнулись с неожиданным 400. Полные примеры программ — в разделе Примеры для чата.
Три изменения
| Настройка | Значение для SpicyAPI |
|---|---|
| Базовый URL | https://api.spicyapi.ai/v1 |
| API-ключ | Ключ SpicyAPI (начинается с sk-spicy-), передаваемый как Authorization: Bearer |
| Модель | Точный ID текстовой модели из актуального каталога, например в SPICY_MODEL (см. ID моделей) |
import os
from openai import OpenAI
# Before: client = OpenAI() (reads OPENAI_API_KEY, calls api.openai.com)
client = OpenAI(api_key=os.environ["SPICY_API_KEY"], base_url="https://api.spicyapi.ai/v1")
reply = client.chat.completions.create(
model=os.environ["SPICY_MODEL"],
messages=[{"role": "user", "content": "Say hello in one sentence."}],
)
print(reply.choices[0].message.content)Библиотеки OpenAI также читают OPENAI_BASE_URL и OPENAI_API_KEY из окружения. Если задать эти переменные, существующий код заработает без изменений, но это перенаправит и все остальные вызовы OpenAI в том же процессе. Поэтому лучше передавать значения явно, как в примерах выше.
ID моделей
ID текстовых моделей имеют вид publisher/model/chat. Копируйте их из актуального каталога, а не преобразуйте знакомое название с другого сервиса:
GET /api/v1/models?modality=textперечисляет только текстовые модели с ценами и добавляет для каждой моделиinputSchemaприincludeSchema=1. См. Каталог моделей и схемы.GET /v1/models— список в формате OpenAI, который читают инструменты. Без фильтра он включает модели изображений, видео и аудио, которые нельзя вызывать на/v1/chat/completions; добавьте?modality=text, чтобы получить только текстовые. Помимо четырёх полей OpenAI, каждый элемент содержитmodalityиtask, а чат-модели — такжеcontext_length,max_output_tokensиsupported_parameters(поля запроса, принимаемые моделью). Библиотеки OpenAI игнорируют дополнительные поля.
Несуществующий ID модели возвращает 404 с code: "model_not_found" и param: "model". Сообщение показывает формат ID и, если такой вариант есть, ближайшую доступную чат-модель. Вызов модели изображений или видео на чат-эндпоинте возвращает 400 с указанием, что это не чат-модель. ID других сервисов часто выглядят похоже, но не взаимозаменяемы: названия разработчиков могут писаться иначе, суффиксов вроде :free здесь нет, а текстовые модели заканчиваются на /chat.
Поля запроса
Каждая модель публикует принимаемые поля в своей inputSchema (а их названия — в supported_parameters на /v1/models).
- Параметры сэмплирования, которых нет в списке модели, игнорируются.
temperature,top_p,top_k,min_p,top_a,frequency_penalty,presence_penaltyиrepetition_penaltyменяют только случайность или повторяемость ответа. Многие клиенты передают их по умолчанию, поэтому модель, которая их не принимает, просто генерирует без них. То же относится кn: 1, пустомуstop, полюstopу модели без стоп-последовательностей иreasoning_effortу модели без уровней рассуждения. Ответ перечисляет проигнорированные поля в заголовкеX-Spicy-Ignored-Params, напримерfrequency_penalty, presence_penalty. - Значения вне допустимого диапазона заменяются ближайшим допустимым значением. Параметр сэмплирования за пределами диапазона модели ограничивается его границей; слишком длинный список
stopсохраняет первые элементы; отсутствующий у модели уровеньreasoning_effortзаменяется ближайшим доступным (при равном расстоянии — меньшим). Ответ перечисляет изменения какname=valueв заголовкеX-Spicy-Adjusted-Params, напримерreasoning_effort=low, temperature=1. - Любое другое поле, которого нет в списке модели, отклоняется с
400,code: "unsupported_parameter", полемparam, указывающим на него, и сообщением с его названием, напримерlogprobs: is not a supported field. Эти поля меняют состав результата, поэтому вы не оплачиваете ответ, созданный без настройки, которую считали переданной.
| Поле | Поведение в SpicyAPI |
|---|---|
messages | Тот же формат. Роли system, developer, user, assistant и tool. Текст работает везде; части image_url — только у моделей, схема которых их предусматривает |
max_tokens, max_completion_tokens | Принимаются оба с одинаковым значением. Токены рассуждения входят в этот лимит. У каждой модели свои значение по умолчанию и верхняя граница |
stream, stream_options | Поддерживаются с правилами использования токенов OpenAI: поток содержит данные об использовании только при include_usage, равном true (см. Ответы и потоки) |
tools, tool_choice | Поддерживаются всеми текстовыми моделями. Некоторые модели принимают только auto и none для tool_choice; принудительный выбор конкретного инструмента у них возвращает 400 |
parallel_tool_calls | Только у моделей, в списке которых есть это поле |
reasoning_effort | У большинства моделей, но допустимые значения зависят от модели: некоторые добавляют none, minimal, xhigh или max, а у некоторых нет medium. Недоступное значение заменяется ближайшим доступным, поэтому при важности точного уровня прочитайте enum модели |
temperature, top_p, top_k, frequency_penalty, presence_penalty | Используются у моделей, в списке которых есть эти поля, с ограничением значений диапазоном модели; у остальных игнорируются (перечисляются в X-Spicy-Ignored-Params). Некоторые модели не принимают ни одного параметра сэмплирования |
seed | Только у моделей, в списке которых есть это поле |
stop | Используется у моделей, в списке которых есть это поле; обрезается до максимального числа элементов модели. Игнорируется у моделей без стоп-последовательностей и при пустом значении |
response_format | json_object у моделей, в списке которых есть это поле; у остальных недоступно |
user, metadata, store | Принимаются и игнорируются |
n | 1 игнорируется; любое другое значение возвращает 400 у моделей, в списке которых нет этого поля |
logprobs, top_logprobs, logit_bias и любое другое поле, которого нет в списке модели | Отклоняются с 400 |
Чтобы увидеть поля модели и их допустимые значения до отправки запроса, выполните команду из раздела Примеры для чата: перед началом.
Ответы и потоки
Ответ без потоковой передачи — обычный объект chat.completion, поэтому reply.choices[0].message.content и reply.usage работают как прежде. Отличий немного:
reasoning_content. Модели, которые рассуждают перед ответом, возвращают этот текст вmessage.reasoning_content(илиdelta.reasoning_contentпри потоковой передаче), рядом сcontent. Он уже учтён вusage.completion_tokens.- ID — это ID запроса.
idимеет видchatcmpl-req_..., а заголовок ответаx-request-idсодержит то же значениеreq_.... Укажите его при обращении в поддержку. Второй заголовок,X-Spicy-Task-Id, указывает задачу, в которой учтена оплата (см. Стоимость и использование). - Нет
system_fingerprintиlogprobs.
Потоки используют те же события chat.completion.chunk, завершаются строкой data: [DONE] и следуют правилам OpenAI для данных об использовании:
- Данные об использовании только по запросу. Без
stream_options.include_usageни один фрагмент не содержитusage, и у каждого непустой списокchoices. При"include_usage": trueдополнительный фрагмент с пустымchoicesи итоговымusageприходит непосредственно перед[DONE]; у всех остальных фрагментов —usage: null. Код на основе примеров потоковой передачи OpenAI работает без изменений; проверкаchoicesперед чтениемchoices[0]защищает от ошибки на последнем фрагменте. - Один
finish_reasonна каждый вариант ответа. Каждый вариант завершается ровно одним фрагментом с егоfinish_reason, независимо от модели. - Строки поддержания соединения. Пока модель рассуждает, поток передаёт строки-комментарии
: keep-alive, чтобы соединение оставалось открытым. Библиотеки OpenAI их пропускают; собственный парсер должен делать то же.
Для длинных ответов или высокого reasoning_effort используйте потоковую передачу. Если запрос без потока выполняется дольше примерно 30 секунд, соединение поддерживается пробельными символами перед JSON-телом и заголовком X-Spicy-Keepalive: 1, поэтому библиотеки OpenAI по-прежнему разбирают ответ. Но при последующей ошибке её объект приходит в теле ответа 200, который библиотеки не считают ошибкой. См. Тайм-ауты и потоковая передача.
Ошибки
Ошибки используют формат OpenAI, {"error": {"message", "type", "param", "code"}}, и обычные HTTP-статусы, поэтому библиотеки OpenAI вызывают стандартные исключения. Поле param указывает на проблемное поле в виде пути через точки, например temperature или messages.1.content.0; code различает ошибки с одинаковым статусом: unsupported_parameter (поле или часть сообщения, которую модель не принимает), invalid_request (отсутствующее поле или недопустимое значение), content_rejected (отказ по правилам контента, также 400) и model_not_found (404). Одно отличие от OpenAI: 402 используется, когда баланс или лимит расходов не покрывает запрос. Полная таблица с действиями для каждого кода — в разделе Примеры для чата: если что-то пошло не так.
Библиотеки OpenAI самостоятельно повторяют запросы после ответов 429 и 5xx. Здесь это безопасно: неудавшийся запрос не оплачивается. Если передаёте Idempotency-Key, задавайте его для каждого вызова отдельно и сначала прочитайте Ключи идемпотентности на текстовых эндпоинтах.
Стоимость и использование
Ответы показывают число токенов в usage, а не цену. Цены за миллион входных, кешированных входных и выходных токенов указаны на странице каждой модели и в каталоге. Чтобы узнать фактическую стоимость вызова, прочитайте заголовок ответа X-Spicy-Task-Id (job_…), присутствующий в каждом принятом запросе — потоковом или обычном, — и найдите задачу через GET /api/v1/jobs/recordInfo?taskId=<job_…>. Поле cost становится итоговым, когда settled равно true. Элементы GET /api/v1/jobs также содержат requestId создавшего их вызова (заголовок X-Request-Id), а раздел Консоль → Логи показывает те же задачи. Как прочитать заголовок через библиотеки OpenAI — в разделе Примеры для чата: узнать стоимость вызова; см. также Расчёт цены и оплата.
Перед выполнением запроса из баланса резервируется сумма, покрывающая сообщения и весь объём выходных токенов max_tokens (значение по умолчанию модели, если поле не задано). Вы платите только за фактически использованные токены, но сначала должна помещаться вся резервируемая сумма. Поэтому небольшой баланс вместе с большим max_tokens приводит к 402. Задайте реалистичный max_tokens или настройте лимиты расходов ключа; см. Оплата.
Эндпоинты, которых здесь нет
Генерация текста доступна в форматах OpenAI Chat Completions, OpenAI Responses, Anthropic Messages и Google Gemini; подробности — в разделе Текст и потоковые ответы. Следующие эндпоинты OpenAI отсутствуют и возвращают 404: /v1/embeddings, устаревший /v1/completions, /v1/images/*, /v1/audio/*, /v1/moderations, /v1/files, /v1/batches, /v1/assistants, а также дообучение. Модели изображений, видео и аудио вызываются через API задач, а видео — также через /v1/videos.
Переход с OpenRouter
OpenRouter также использует формат OpenAI, поэтому действуют те же три изменения: замените базовый URL https://openrouter.ai/api/v1 на https://api.spicyapi.ai/v1, а также ключ и ID моделей. Затем уберите поля, существующие только в OpenRouter: здесь они возвращают 400:
| Поле OpenRouter | Что делать |
|---|---|
models (список резервных моделей) и route | Удалить. Передавайте один ID модели; SpicyAPI выбирает способ его обслуживания |
provider | Удалить. Выбирать провайдера для отдельного запроса нельзя |
reasoning (объект вроде {"effort": "high"}) | Преобразуется в верхнеуровневое reasoning_effort (enabled: false становится none, если модель его поддерживает); остальные ключи внутри игнорируются. Явная передача reasoning_effort понятнее |
usage ({"include": true}) | Удалить. Обычные ответы всегда содержат usage; для потоков передавайте stream_options: {"include_usage": true} |
transforms, plugins | Удалить |
Заголовки HTTP-Referer и X-Title безвредны и игнорируются.
Контрольный список
- Базовый URL —
https://api.spicyapi.ai/v1, ключ — SpicyAPI. - ID модели скопирован из актуального каталога и заканчивается на
/chat. - Поля запроса сверены с
inputSchemaмодели; неподдерживаемые поля, не относящиеся к сэмплированию, удалены. Заголовки ответаX-Spicy-Ignored-ParamsиX-Spicy-Adjusted-Paramsпроверены хотя бы один раз, чтобы увидеть изменения. - При передаче
stream_options.include_usageцикл обработки потока пропускает последний фрагмент с пустым спискомchoices. - Для
max_tokensзадано реалистичное значение либо оставлено значение по умолчанию модели; на ключе настроены лимиты расходов. - Длинные запросы или запросы с высоким уровнем рассуждения используют
stream: true.
Дополнительные материалы
Примеры для чата · Текст и потоковые ответы · Каталог моделей и схемы · Аутентификация · Оплата
Примеры для чата
Полные рабочие программы для многошаговых диалогов, ролевого общения, потоковой передачи в свой интерфейс и вызова инструментов на Python, Node.js и curl.
Пошаговое руководство «Изображение в видео»
Начните с одного изображения на своём компьютере и закончите скачанным видеофайлом. На каждом шаге показаны CLI, TypeScript SDK и обычный HTTP.

