OpenAI-совместимый API без иллюзий: как оценить интеграцию до разработки
РусскийСлово «совместимый» часто воспринимают как обещание: можно заменить адрес сервера, оставить любой SDK и получить ровно то же поведение. Для производственной интеграции это слишком широкое толкование. Совместимость почти всегда относится к конкретной форме запросов и ответов, а не ко всей экосистеме провайдера, всем моделям, служебным методам API, параметрам и особенностям ошибок. Поэтому первый шаг — не писать код, а очертить поверхность контракта.
В AiHummer публично описан OpenAI-совместимый POST /v1/chat/completions с потоковой передачей ответа по SSE. Подробности находятся на странице Chat Completions и в Swagger. Важное ограничение документации: методы /v1/models и /v1/embeddings не предоставляются. Это не мелкая сноска. Клиент, который при запуске автоматически запрашивает список моделей или пытается отправить эмбеддинги на тот же базовый адрес, потребует адаптации.
Начните с матрицы, а не с логотипов
Составьте таблицу фактических операций. Для каждой строки укажите метод, путь, обязательные заголовки, тело, ответ, потоковый режим, коды ошибок, таймаут и повтор. Например, базовый чат использует Bearer-ключ AiHummer с префиксом ah-, сообщения и модель в теле, обычный JSON-ответ либо SSE-поток. Административные операции — это другая поверхность с другими областями прав и защитой. Не переносите права административного API на пользовательский клиент только потому, что так удобнее прототипу.
Полезно сверять смысл с первичной справкой OpenAI Chat Completions, но не считать её спецификацией AiHummer. Даже у оригинального API поддержка параметров зависит от модели. У совместимого сервера различия могут быть шире: отдельные поля игнорируются, некоторые значения не поддерживаются, структура расширенных объектов отличается. Источник истины для вашей интеграции — опубликованный OpenAPI конкретной версии AiHummer и контрольные запросы к тестовому экземпляру.
Что обычно ломается при «простой замене URL»
Первое — обнаружение моделей. Некоторые библиотеки вызывают /v1/models до первого чата, строят селектор или проверяют имя модели. Если метод отсутствует, задайте модель конфигурацией и отключите автоматическое обнаружение либо используйте тонкий адаптер. Не маскируйте 404 фиктивным списком: это создаст более трудную ошибку позднее.
Второе — стриминг. SSE — последовательность событий, которую клиент обязан читать постепенно, корректно собирать и завершать. Проверяйте разрыв соединения, пустые фрагменты, отмену пользователем, таймаут прокси и повтор после неизвестного результата. Для генерации текста повтор обычно безопаснее, чем для вызова инструмента с побочным эффектом. Если агент в ходе ответа может создать задачу или отправить сообщение, слепой повтор запроса способен продублировать действие.
Третье — ошибки. Не сводите любой не-200 к строке «модель недоступна». Различайте неверный ключ, недостаточную область прав, лимит, недоступность провайдера, ошибку валидации и внутренний сбой. Показывайте пользователю понятный результат, а оператору сохраняйте идентификатор запроса и машинный код без секретов. Никогда не журналируйте Bearer-ключ или полное тело, если в нём есть персональные данные.
Четвёртое — таймауты и отмена. Установите отдельные пределы на соединение, первый токен и полный ответ. Передавайте отмену вниз по стеку. Если интерфейс перестал ждать, сервер не должен бесконтрольно продолжать дорогую работу. Для интерактивного интерфейса показывайте состояние «подключаемся», «идёт ответ», «прервано» и «можно повторить», а не один вечный индикатор ожидания.
Где размещать адаптацию
Для одного приложения достаточно небольшой клиентской обёртки. Она хранит базовый адрес, добавляет авторизацию, нормализует ошибки и предоставляет два метода: обычный ответ и поток. Для нескольких продуктов лучше выделить внутренний шлюз-адаптер, чтобы различия не размножались по кодовой базе. Но не превращайте его в новый универсальный API, пока нет второго подтверждённого потребителя.
Контракт обёртки должен быть уже внешнего API. Например: sendMessage(conversation, signal) и streamMessage(conversation, onDelta, signal). Решение о том, какой агент обслуживает запрос, какой ключ имеет область прав chat и какой таймаут допустим, остаётся в конфигурации сервера. Так проще тестировать и ротировать ключи.
Если интеграция запускается в браузере, не вшивайте постоянный ключ в клиентскую часть. Браузерный код доступен пользователю. Используйте свою серверную часть, которая аутентифицирует пользователя, применяет лимиты и вызывает AiHummer от имени приложения. Для сервер-серверного сценария храните секрет в менеджере секретов или защищённом хранилище, выдавайте минимальную область прав и планируйте ротацию.
Минимальный набор контрактных тестов
Сделайте тест обычного ответа на короткий запрос. Отдельно проверьте SSE: порядок фрагментов, завершение, отмену и разрыв. Отправьте неверный ключ и ключ без нужной области прав. Проверьте неизвестную модель, некорректное тело и слишком большой запрос. Смоделируйте тайм-аут внешнего провайдера. Убедитесь, что клиент не вызывает отсутствующие /v1/models и /v1/embeddings, либо корректно переживает их отсутствие.
Следующий слой — семантика. Ответ модели недетерминирован, поэтому не сравнивайте текст побуквенно. Проверяйте форму: есть непустой контент, поток складывается в завершённое сообщение, ошибки распознаны, секреты не попали в логи. Если агент вызывает инструменты, используйте тестовый инструмент без внешнего эффекта и отдельно проверяйте одобрение или запрет.
Ограничения и честные ожидания
OpenAI-совместимость AiHummer не означает поддержку каждого SDK без настройки, всех параметров OpenAI или всех сопутствующих методов API. Фактический ответ зависит от выбранного в AiHummer провайдера и модели, их доступности, лимитов и географии. Поток SSE улучшает восприятие задержки, но не гарантирует время первого токена. API даёт вход в среду выполнения агента, однако память, знания, инструменты, права и маршрутизация требуют отдельной конфигурации.
Не обещайте фиксированную стоимость интеграции только по числу запросов: итог зависит от тарифа, инфраструктуры, выбранной модели и внешних сервисов. Не объявляйте готовность к промышленной эксплуатации после одного curl: нужны контрактные тесты, наблюдаемость, секреты, лимиты, отмена и план отказа.
Чек-лист интегратора
- Зафиксировать версию AiHummer и скачать её OpenAPI.
- Выписать только реально используемые операции и параметры.
- Подтвердить, что клиент не зависит от
/v1/modelsили/v1/embeddings. - Выдать отдельный ключ с минимальной областью прав
chat; не класть его в клиентскую часть. - Реализовать обычный и SSE-режимы, отмену и раздельные таймауты.
- Нормализовать ошибки без утечки ключей и содержимого.
- Определить правила повтора отдельно для чтения и для действий с побочным эффектом.
- Прогнать позитивные, негативные и отказные контрактные тесты.
- Снять техническую и продуктовую базовую линию до расширения трафика.
Удобство совместимого API именно в том, что знакомая форма сокращает путь к первому запросу. Надёжность появляется позже — когда команда явно знает, какая часть совместима, какие различия приняты и как клиент ведёт себя при сбое. Начните с двух страниц документации, одной матрицы контракта и десятка тестов: это дешевле, чем обнаруживать скрытую зависимость в промышленной эксплуатации.
Commentaires