Как добавить провайдера или протокол
Этот документ описывает практический чек-лист для расширения gpt2giga новым вышестоящим провайдером или новым публичным протоколом. Перед изменением набора API сначала нужно решить, что именно добавляется:
- новый публичный протокол: клиенты отправляют полезные нагрузки, совместимые с Gemini, а вышестоящий сервис остаётся GigaChat;
- новый вышестоящий провайдер: нормализованные запросы исполняются не только через GigaChat;
- оба слоя сразу.
Термины:
- адаптер протокола переводит внешний сетевой формат в нормализованные модели и обратно;
- адаптер провайдера исполняет нормализованный запрос в конкретном вышестоящем сервисе;
- роутер подключает HTTP-поверхность и занимается авторизацией, контекстом запроса, потоковой передачей и типом содержимого ответа;
- наблюдаемость, журналы трафика и метрики получают безопасные нормализованные поля или поля контекста запроса.
1. Зафиксировать область
Для нового протокола:
- определить маршруты, заголовки, ожидания по авторизации и политику псевдонима
/v1; - описать минимальные поддерживаемые операции: chat/messages, embeddings, эндпоинт типа responses, count tokens, models;
- решить, какие необязательные поля принимаются и игнорируются для совместимости с SDK.
Для нового вышестоящего провайдера:
- определить настройки авторизации и обращение с секретами;
- описать синхронные/без потоковой передачи и потоковые вызовы SDK;
- определить разрешение модели, метку параллелизма по моделям и семантику таймаута/повторов;
- решить, какие специфичные для провайдера поля можно хранить в
provider_metadata.
2. Добавить конфигурацию
Обновите:
gpt2giga/models/config.py: настройки, валидаторы, значения по умолчанию..env.example: новые переменные окружения и безопасные значения по умолчанию.docs/configuration.md: описание для пользователя.tests/test_config/test_config.py: значения по умолчанию, разбор окружения, некорректные значения.
Секреты должны оставаться в окружении/менеджере секретов. Не добавляйте секреты провайдера в примеры CLI, журналы трафика, метки метрик или отладочный вывод.
3. Добавить адаптер протокола
Файлы для нового публичного протокола обычно живут в
gpt2giga/protocols/<protocol>/.
Минимальный набор:
adapter.pyс реализациейProtocolAdapterизgpt2giga/core/interfaces.py;- преобразователь запроса в
NormalizedChatRequestили другую нормализованную модель; - преобразователь ответа из
NormalizedResponseв публичную форму ответа; - преобразователь потока из
NormalizedStreamEventв публичный формат SSE/событий; - санитайзер/классификатор параметров, если SDK присылает много необязательных полей.
Правила сопоставления:
- канонические поля кладите в нормализованные поля;
- неизвестные или принятые, но не исполняемые публичные поля кладите в
raw_extensions, если их нужно сохранить; - специфичный для провайдера проброс кладите в
provider_metadata; - не смешивайте заголовки авторизации/транспорта с полезной нагрузкой модели;
- схемы инструментов и вызовы инструментов приводите к
NormalizedToolиNormalizedToolCall; - использование токенов приводите к
input_tokens,output_tokens,total_tokens; - причины завершения приводите к общему набору вроде
stop,length,tool_calls, если это возможно.
Для уже подключённого протокола Gemini это сделано отдельным преобразователем Gemini-в-нормализованное, а не новой веткой внутри адаптера OpenAI. Специфичные для Gemini настройки безопасности, кандидаты, части контента, объявления инструментов и события потока должны быть либо подняты в канонические поля, либо явно сохранены в расширениях. Для будущих протоколов сохраняйте тот же принцип изоляции сетевого формата от адаптера OpenAI.
4. Добавить адаптер провайдера
Файлы для нового вышестоящего провайдера живут в gpt2giga/providers/<provider>/.
Обычно нужны:
adapter.py: реализация для вызовов без потоковой передачи и потоковых;auth.py: помощники для учётных данных/access-токена;client.py: фабрика SDK/клиента;streaming.py: фрагменты вышестоящего сервиса вNormalizedStreamEvent;types.py: локальные Protocol/типы, если типы SDK неудобны для тестов.
Адаптер провайдера должен:
- принимать
NormalizedChatRequest; - вызывать вышестоящий сервис в первую очередь асинхронно;
- обновлять фактическую модель в
RequestContextчерезupdate_request_context; - использовать
ModelConcurrencyLimiterс ограниченной меткой провайдера; - возвращать
NormalizedResponseдля вызовов без потоковой передачи; - возвращать
NormalizedStreamEventдля потоковых; - нормализовать ошибки провайдера в
NormalizedError; - сохранять только безопасные метаданные провайдера;
- не писать необработанные учётные данные, API-ключи, cookie и заголовки авторизации.
Если вышестоящий провайдер умеет нативно принимать нормализованную полезную нагрузку, не
нужно реконструировать форму OpenAI. Для GigaChat текущий адаптер пока
переиспользует OpenAI-подобную полезную нагрузку и прежний RequestTransformer; это
переходная деталь, а не требование для новых провайдеров.
5. Подключить маршруты
Обновите нужные слои:
gpt2giga/routers/<protocol>/: конкретные HTTP-обработчики.gpt2giga/api/<protocol>/routes.py: агрегация маршрутов.gpt2giga/app/factory.py: подключение, зависимости авторизации, debug/admin-флаги.gpt2giga/openapi_specs/: дополнения OpenAPI для новых эндпоинтов.gpt2giga/app_state.pyи настройка жизненного цикла, если нужен новый клиент.
Обработчик маршрута должен:
- читать тело через общие помощники;
- создавать или использовать контекст запроса;
- применять политику авторизации прокси/admin;
- вызывать адаптер протокола и адаптер провайдера;
- оборачивать итератор потокового тела так, чтобы метрики, журналы трафика и наблюдаемость видели финальный жизненный цикл;
- сохранять склейку диалогов только там, где семантика совпадает.
6. Добавить наблюдаемость
Новый провайдер/протокол должен быть виден в Phoenix/OpenTelemetry, метриках и журналах трафика без включения захвата промптов.
Обновите наблюдаемость LLM:
- используйте
build_llm_chat_completion_attributes()для чат-подобных сценариев, если запрос/ответ уже нормализованы; - добавьте отдельный помощник в
gpt2giga/sinks/observability/<protocol>.py, если публичный протокол имеет особый формат вывода/событий; - задайте имя спана, если нужен новый корневой спан, например
Gemini-Content; - выставляйте
gpt2giga.api_formatв ограниченное значение:chat_completions,responses,messages,generate_content,embeddingsили новый явный формат; - сопоставляйте вехи потока с событиями спана через
NormalizedStreamEvent, где возможно; - сохраняйте видимость инструментов: количество/имена по умолчанию, аргументы/схема только
при
GPT2GIGA_OBSERVABILITY_CAPTURE_CONTENT=TrueиGPT2GIGA_OBSERVABILITY_CAPTURE_TOOL_ARGS=True; - не добавляйте промпты, ответы, аргументы инструментов или необработанную полезную нагрузку провайдера в атрибуты без включения и маскирования.
Обновите наблюдаемость жизненного цикла запроса:
RequestContext.protocol, route, запрошенная/фактическая модель и провайдер должны заполняться до отправки;- LLM-маршруты должны выставлять
context.llm_observability_emitted=True, чтобы не дублировать успешный спан жизненного цикла; - ошибки должны попадать в
error_type,error_message, статус OpenTelemetry и нормализованные поля ошибок.
Обновите метрики:
- метки провайдера/протокола должны быть ограниченными;
- не добавляйте идентификатор запроса, идентификатор трейса, идентификатор пользователя, хеш API-ключа или необработанные варианты модели с высокой кардинальностью;
- проверьте число запросов, задержку, задержку вышестоящего сервиса, ошибки вышестоящего сервиса, суммарные токены, отключения потока и отброшенные события очереди.
Обновите журналы трафика:
- захват содержимого запросов/ответов остаётся включаемым;
- новые поля полезной нагрузки должны проходить маскирование;
- если схема хранилища требует новые индексируемые поля, добавьте миграцию и обновление шаблона OpenSearch;
- фильтры admin-логов должны использовать ограниченные поля.
7. Добавить отладочную трансляцию
Для нового протокола/провайдера расширьте защищённый debug API:
SUPPORTED_TRANSLATE_FORMATSвgpt2giga/api/admin/routes.py;- эндпоинт
<protocol>-to-normalized, если нужен короткий путь; - обработку универсальной пары
/_debug/translate; - фикстуры в
tests/fixtures/debug_translate/; - тесты на неподдерживаемые пары и безопасные ошибки.
Отладочная трансляция не должна требовать реальных учётных данных вышестоящего сервиса, кроме направлений, где нужно реально подготовить полезную нагрузку SDK провайдера. Необработанные секреты не должны попадать в ответ.
8. Добавить тесты
Минимальный набор:
- модульные тесты адаптера: запрос, ответ, инструменты, мультимодальный контент, ошибки;
- тесты преобразователя потока: события start/delta/tool/usage/end/error;
- тесты роутера: без потоковой передачи, потоковые, авторизация, некорректные параметры, откат;
- тесты наблюдаемости: спаны, атрибуты, флаги захвата, маскирование, события инструментов;
- тесты метрик/журналов трафика, если меняются метки или отправляемые поля;
- тесты OpenAPI;
- эталонные фикстуры (golden) для публичного формата ответа/SSE;
- smoke-тесты совместимости SDK, если есть доступный пакет клиента.
Для протокола Gemini отдельно проверьте сопоставление кандидатов, причины завершения, поля, связанные с безопасностью, объявления инструментов/вызовы функций, мультимодальные части и порядок событий потока.
9. Обновить документацию
Обновите:
docs/api-compatibility.md: статус маршрутов и ограничения.docs/client-parameter-compatibility.md: принятые/поддерживаемые/игнорируемые поля.docs/configuration.md: переменные окружения и режимы.docs/operations.md: метрики, журналы трафика, наблюдаемость, debug-эндпоинты.docs/deployment.md: изменения compose/окружения, если появились внешние сервисы.docs/architecture/normalized-messages.md: если изменился нормализованный контракт или статус выполнения.- таблицу документации в README, если появился новый документ для пользователя.
Документация должна явно разделять «реализовано сейчас» и «подготовлено для следующего шага». Это особенно важно для частично подготовленных семейств API, например Files/Batches, чтобы не обещать публичный маршрут, пока он не подключён и не покрыт тестами.
10. Проверить качество
Перед PR:
uv run ruff check .
uv run ruff format --check .
uv run pytest tests/ --cov=. --cov-report=term --cov-fail-under=80
Если менялись зависимости, обновите uv.lock. Если менялись контракты deploy/окружения,
проверьте .env.example, compose-файлы и документацию вместе.