Интеграция API
JSON Schema в OpenAI-совместимом API: как получить проверяемый ответ
Текст от модели удобен для человека, но приложение обычно ждёт поля: категорию обращения, риск, краткое резюме, список действий. Если парсить свободный ответ регулярным выражением, один перенос строки превращается в ошибку интеграции. Надёжнее сначала описать небольшой JSON-контракт, попросить модель следовать ему и затем проверить результат на своём сервере. Такой подход полезен для классификации, извлечения данных, черновиков форм и маршрутизации, но не отменяет валидацию и бизнес-правила.
Начните с решения, а не с большого промпта
Хороший структурированный ответ отвечает на один конкретный вопрос. Для маршрутизации тикета не нужен полный профиль клиента: достаточно topic, urgency, summary и, возможно, needs_human. Чем меньше контракт, тем легче объяснить его разработчику, покрыть тестами и безопасно изменить. Не помещайте в схему секреты, паспортные данные, платёжные реквизиты или поля, которые приложение не имеет права обрабатывать. Сначала минимизируйте данные на входе, затем храните только результат, необходимый для сценария.
Отделите три уровня. Первый — синтаксис: получился ли корректный JSON. Второй — типы и обязательные поля: строка ли summary, входит ли urgency в разрешённый список. Третий — бизнес-ограничения: может ли автоматизация реально закрыть этот запрос и достаточно ли уверенности, чтобы не передавать его человеку. Модель помогает подготовить предложение, но последнее решение и действие остаются за вашим кодом и правилами.
Проектируйте схему как публичный контракт
Имена полей должны быть стабильными и понятными команде. Укажите, какие значения допустимы, ограничьте максимальную длину текста и запретите лишние поля там, где это важно. Версия контракта пригодится, когда продукт добавит новую категорию: сервер может принимать старую и новую формы некоторое время, а метрики покажут долю перехода. Не требуйте от модели точных цен, доступности модели или юридического вывода, если эти данные не загружаются из проверяемого источника.
Положите рядом с контрактом набор примеров: обычный запрос, пограничный случай, пустой текст, запрещённый ввод и ответ, который должен уйти на ручную проверку. Это ваш контрактный тест, а не декоративная документация. Ту же дисциплину применяют при проверке каталога и смене endpoint-а: сначала проверьте доступные возможности своим ключом, как описано в руководстве по /v1/models, затем включайте новый путь малой доле трафика.
Безопасный серверный пример
Ниже пример показывает общий механизм: ключ читается только на сервере, вход ограничен, ответ разбирается и проверяется. Поле response_format и конкретный формат зависят от фактического совместимого endpoint-а; если он не документирован для выбранной модели, не считайте пример обещанием поддержки. В таком случае запросите JSON текстом и оставьте ту же строгую проверку после ответа.
const allowedUrgency = new Set(['low', 'normal', 'high']);
export async function classify(text) {
if (typeof text !== 'string' || text.length < 1 || text.length > 4000) {
throw new Error('invalid_input');
}
const response = await fetch('https://russiaapi.com/v1/chat/completions', {
method: 'POST',
headers: { 'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.RUSSIAAPI_API_KEY}` },
body: JSON.stringify({ model: process.env.RUSSIAAPI_MODEL,
messages: [{ role: 'user', content: `Верни только JSON: ${text}` }] })
});
if (!response.ok) throw new Error(`api_${response.status}`);
const payload = await response.json();
const result = JSON.parse(payload.choices?.[0]?.message?.content ?? '{}');
if (typeof result.summary !== 'string' || result.summary.length > 280 ||
!allowedUrgency.has(result.urgency) || typeof result.needs_human !== 'boolean') {
throw new Error('invalid_model_output');
}
return result;
}Этот минимальный фрагмент не является готовым публичным route. В production добавьте аутентификацию пользователя, лимит запросов, timeout, журналирование request ID без содержимого секрета и обработку AbortError. Перед автодействием снова проверьте результат: например, классификация «high» не должна сама отправлять письмо, менять тариф или выполнять инструмент. Если нужен вызов инструмента, применяйте allow-list и серверную валидацию аргументов; детали разбирает статья о function calling.
Ошибки — часть контракта
Не возвращайте пользователю сырой JSON парсера или текст ответа внешнего сервиса. Для UI достаточно устойчивых состояний: «не удалось распознать формат», «операция временно недоступна», «нужна ручная проверка». В журнале сохраните время, версию схемы, класс ошибки и обезличенный request ID. Не пишите Authorization, API Key, cookie, полную историю чата и персональные данные в логи ради отладки.
429 не исправляют бесконечным повтором. Уменьшите параллелизм, поставьте очередь и используйте ограниченный backoff с jitter только для безопасного чтения или повторяемой операции. При timeout не предполагается, что работа не началась: верните честный статус и проверяйте результат, если контракт предоставляет идентификатор операции. Эти границы описаны в материалах про 429 и backoff и тайм-ауты AI API.
Как выпускать схему без сюрпризов
Сначала запустите режим наблюдения: модель формирует JSON, но приложение не меняет путь пользователя. Сравните результат с размеченным набором, посмотрите долю невалидных ответов и случаи, ушедшие на ручную проверку. Затем включите feature flag для небольшой группы и сохраните rollback: предыдущая версия схемы должна продолжать работать, пока новая не доказала предсказуемость. Не измеряйте только среднюю задержку — считайте валидность, стоимость успешной классификации, долю retry и фактические решения человека.
Перед релизом проверьте русский текст, пустой ввод, длинные сообщения, Unicode, неверный JSON, неизвестное значение enum, 401/403, 429 и оборванное соединение. Используйте синтетические данные. Так вы не превращаете реальную переписку в тестовый набор и не публикуете ложное обещание «всегда корректного» ответа.
Проверьте контракт на собственном тестовом ключе
Создайте в консоли RussiaAPI отдельный ключ для тестов, сверяйте каталог моделей и документацию, а затем подключайте схему через серверный маршрут. Начинайте с наблюдаемого сценария и оставляйте человеку право подтверждать рискованные действия.
Открыть консоль RussiaAPIFAQ
Гарантирует ли JSON Schema готовый для действия ответ?
Нет. Она уменьшает риск формата, но приложение всё равно проверяет JSON, типы, длину и бизнес-ограничения. Схема не заменяет авторизацию, валидацию входа и серверную политику.
Можно ли держать ключ API в браузере?
Нет. Храните собственный ключ RussiaAPI в серверной переменной окружения или менеджере секретов. Ключ, попавший в bundle, DevTools или сетевой запрос браузера, нужно считать скомпрометированным.
Что делать без поддержки нужного параметра?
Проверьте текущую документацию. Можно запросить JSON текстом, затем строго распарсить и валидировать его на сервере; не называйте этот режим гарантированной совместимостью.