Skip to content

[M] Упростить переключение LLM-провайдеров и улучшить диагностику интеграции #7

Closed

Description

@ashikov

Цель

Сделать переключение между OpenAI-совместимыми LLM-провайдерами предсказуемым и удобным для сравнительного тестирования, не привязывая приложение к Yandex AI и не добавляя SDK конкретных поставщиков.

Контекст

Issue #1 и PR #3 добавляют базовый OpenAiCompatibleGateway, работающий с общим подмножеством Chat Completions API. После стабилизации коннектора нужно явно зафиксировать границы совместимости, улучшить диагностику конфигурации и подготовить воспроизводимый способ сравнения нескольких провайдеров.

Входит в задачу

  • Описать поддерживаемый контракт провайдера: POST на Chat Completions endpoint, поля model, messages, temperature и ответ в choices[0].message.content
  • Зафиксировать, что Yandex AI является одной из конфигураций универсального коннектора, а не архитектурным дефолтом самого gateway
  • Добавить примеры конфигурации минимум для Yandex AI и одного стандартного Bearer-провайдера с собственными URL и моделью
  • Добавить контрактные тесты минимум для двух конфигураций: Yandex-style Api-Key с полным URI модели и стандартный Bearer с произвольными URL и именем модели
  • Проверить, что переключение провайдера выполняется только изменением переменных окружения и перезапуском приложения без пересборки кода
  • Явно различать полностью отсутствующую LLM-конфигурацию и частично заполненную некорректную конфигурацию
  • Для частично заполненной конфигурации возвращать понятную техническую ошибку при запуске, не выводя ключи и другие секреты
  • Использовать нейтральное пользовательское сообщение для временной недоступности настроенного провайдера вместо формулировки «генерация не подключена»
  • Определить безопасный способ передавать дополнительные обязательные заголовки для провайдеров, которым недостаточно стандартного Authorization
  • Добавить локальный smoke-check или короткий сценарий ручного сравнения моделей, который не запускается в CI и не требует хранения секретов в репозитории
  • Не добавлять SDK конкретных провайдеров, streaming, Responses API и автоматический выбор модели в рамках этой задачи
  • Перед завершением выполнить pnpm check

Критерии готовности

  • В документации однозначно описано поддерживаемое подмножество OpenAI-compatible API
  • Yandex AI и стандартный Bearer-провайдер проходят одинаковый транспортный контракт
  • Для переключения модели или провайдера достаточно изменить .env и перезапустить приложение
  • Неполная конфигурация диагностируется отдельно от полностью отключённой генерации
  • Пользовательское сообщение не утверждает, что генерация не подключена, если настроенный провайдер временно недоступен
  • Дополнительные заголовки можно настроить без изменения исходного кода и без утечки секретов
  • Smoke-check не зависит от CI и не публикует ключи или пользовательские тексты

Зависимости и параллельность

Задачу выполнять после merge issue #1 и стабилизации PR #3. Она не блокирует текущий MVP и может выполняться параллельно с подготовкой обезличенных сценариев из issue #6.

Остаточный срез — 04.11.2026

На актуальном main транспорт, диагностика, Yandex/Bearer примеры и ручной benchmark уже реализованы. Завершить настройку дополнительных обязательных заголовков через LLM_EXTRA_HEADERS — JSON-объект строковых значений. JSON здесь отражает map HTTP-заголовков внутри env, отдельный файл конфигурации не вводится.

Неизвестные, неполные или некорректные значения конфигурации отклоняются при запуске до provider request с безопасной ошибкой без имён и значений секретных заголовков. Имена/значения проверяются через стандартные HTTP primitives. Дубликаты без учёта регистра запрещены. Нельзя переопределять Authorization, Content-Type, служебные transport headers, x-folder-id или x-data-logging-enabled. Последние два остаются под управлением существующего контракта конфигурации и privacy.

При отсутствии новой переменной поведение сохраняется. Дополнительные заголовки передаются только настроенному endpoint существующим gateway, не попадают в diagnostics, logs и публичные ответы. Production env и модель не изменяются. Приёмка: разрешённый синтетический заголовок доходит до mocked transport, недопустимые значения fail closed, existing config/privacy tests проходят, документация содержит безопасный пример без реальных credentials. TDD, независимое review, make lint-md, pnpm check и git diff --check обязательны. Платные вызовы не нужны.

Отказ от перенаправлений

Независимое review воспроизвело передачу секретного дополнительного заголовка на другой origin через HTTP 307. Provider endpoint должен быть конечным: gateway отклоняет redirect до запроса получателю, без повторной попытки. Это явное уточнение транспортного контракта, сохраняющее действующие HTTP-коды приложения и безопасную диагностику. Приёмка — реальный локальный HTTP regression с синтетическим заголовком: первый сервер получает запрос, второй не получает ничего, генерация завершается контролируемой ошибкой без секрета. Production endpoint не меняется.

Завершено

Реализовано и доставлено в main через PR #327. Diff, тесты и CI PR проверены. Issue закрыта как completed после независимой сверки интеграции.

Activity

  1. ashikov commented on Nov 4, 2026

    @ashikov
    OwnerAuthor

    Оставшийся срез реализован в PR #327 (4fd1359bf271d0a3da1cf9a95ad1ff9899a43147) от актуального main. Дополнительные заголовки задаются через env, валидируются до provider request и не могут заменить служебные/privacy headers. HTTP redirects отклоняются, чтобы секретные заголовки не отправлялись другому получателю. Production-конфигурация не менялась.

    TDD и regression: конфигурация, повторные JSON-ключи, реальный HTTP redirect между двумя синтетическими серверами. make lint-md, pnpm check (1079 тестов, lint/typecheck/build), git diff --check — PASS. Независимое review обнаружило Medium по redirect, исправление проверено повторно, открытых findings нет.

    Платные attempts этой итерации: 0, расходы: 0 ₽. Общий расход марафона остаётся 7 attempts / 6,7688 ₽ по usage из 500 ₽. PR не слит, Task остаётся открытой до merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions