Разрешение провайдера во время выполнения
Hermes имеет общий механизм разрешения провайдера во время выполнения, используемый в:
- CLI
- gateway
- заданиях cron
- ACP
- вызовах вспомогательных моделей
Основные реализации:
hermes_cli/runtime_provider.py— разрешение учетных данных,_resolve_custom_runtime()hermes_cli/auth.py— реестр провайдеров,resolve_provider()hermes_cli/model_switch.py— общий конвейер/model(CLI + gateway)agent/auxiliary_client.py— маршрутизация вспомогательных моделейproviders/— ABC + точки входа реестра (ProviderProfile,register_provider,get_provider_profile,list_providers)plugins/model-providers/<name>/— плагины для каждого провайдера (встроенные), которые объявляютapi_mode,base_url,env_vars,fallback_modelsи регистрируют себя в реестре при первом обращении. Пользовательские плагины в$HERMES_HOME/plugins/model-providers/<name>/переопределяют встроенные с тем же именем.
get_provider_profile() в providers/ возвращает ProviderProfile для заданного идентификатора провайдера. runtime_provider.py вызывает его во время разрешения, чтобы получить канонические base_url, список приоритетов env_vars, api_mode и fallback_models без необходимости дублировать эти данные в нескольких файлах. Добавление нового плагина в plugins/model-providers/<your-provider>/ (или $HERMES_HOME/plugins/model-providers/<your-provider>/), который вызывает register_provider(), достаточно для того, чтобы runtime_provider.py его подхватил — не нужно добавлять ветвление в самом механизме разрешения.
Если вы пытаетесь добавить нового стороннего провайдера инференса, прочитайте Добавление провайдеров и Руководство по плагину провайдера модели вместе с этой страницей.
Приоритет разрешения
На высоком уровне разрешение провайдера использует:
- явный запрос CLI/во время выполнения
- конфигурацию модели/провайдера из
config.yaml - переменные окружения
- значения по умолчанию для провайдера или автоматическое разрешение
Этот порядок важен, потому что Hermes считает сохраненный выбор модели/провайдера источником истины для обычных запусков. Это предотвращает случайное переопределение конечной точки, выбранной пользователем в hermes model, устаревшим экспортом оболочки.
Провайдеры
Текущие семейства провайдеров включают (полный встроенный набор см. в plugins/model-providers/):
- AI Gateway (Vercel)
- OpenRouter
- Nous Portal
- OpenAI Codex
- Copilot / Copilot ACP
- Anthropic (нативный)
- Google / Gemini (
gemini,google-gemini-cli) - Alibaba / DashScope (
alibaba,alibaba-coding-plan) - DeepSeek
- Z.AI
- Kimi / Moonshot (
kimi-coding,kimi-coding-cn) - MiniMax (
minimax,minimax-cn,minimax-oauth) - Kilo Code
- Hugging Face
- OpenCode Zen / OpenCode Go
- AWS Bedrock
- Azure Foundry
- NVIDIA NIM
- xAI (Grok)
- Arcee
- GMI Cloud
- StepFun
- Qwen OAuth
- Xiaomi
- Ollama Cloud
- LM Studio
- Tencent TokenHub
- Пользовательский (
provider: custom) — основной провайдер для любой совместимой с OpenAI конечной точки - Именованные пользовательские провайдеры (список
custom_providersв config.yaml)
Результат разрешения во время выполнения
Механизм разрешения во время выполнения возвращает такие данные, как:
providerapi_modebase_urlapi_keysource- метаданные, специфичные для провайдера, например, информация об истечении/обновлении
Почему это важно
Этот механизм разрешения — основная причина, по которой Hermes может совместно использовать логику аутентификации/времени выполнения между:
hermes chat- обработкой сообщений gateway
- заданиями cron, выполняемыми в новых сессиях
- сессиями редактора ACP
- задачами вспомогательных моделей
AI Gateway
Установите AI_GATEWAY_API_KEY в ~/.hermes/.env и запускайте с --provider ai-gateway. Hermes получает доступные модели из эндпоинта /models gateway, фильтруя языковые модели с поддержкой использования инструментов.
OpenRouter, AI Gateway и пользовательские базовые URL, совместимые с OpenAI
Hermes содержит логику, чтобы избежать утечки неверного API-ключа на пользовательскую конечную точку, когда существует несколько ключей провайдеров (например, OPENROUTER_API_KEY, AI_GATEWAY_API_KEY и OPENAI_API_KEY).
API-ключ каждого провайдера привязан к своему базовому URL:
OPENROUTER_API_KEYотправляется только на конечные точкиopenrouter.aiAI_GATEWAY_API_KEYотправляется только на конечные точкиai-gateway.vercel.shOPENAI_API_KEYиспользуется для пользовательских конечных точек и как запасной вариант
Hermes также различает:
- реальную пользовательскую конечную точку, выбранную пользователем
- запасной путь OpenRouter, используемый, когда не настроена пользовательская конечная точка
Это различие особенно важно для:
- локальных серверов моделей
- API, совместимых с OpenAI, не от OpenRouter и не от AI Gateway
- переключения провайдеров без повторного запуска настройки
- сохраненных в конфигурации пользовательских конечных точек, которые должны продолжать работать, даже если
OPENAI_BASE_URLне экспортирован в текущей оболочке
Нативный путь Anthropic
Anthropic теперь не только "через OpenRouter".
Когда разрешение провайдера выбирает anthropic, Hermes использует:
api_mode = anthropic_messages- нативный API Messages от Anthropic
agent/anthropic_adapter.pyдля преобразования
Разрешение учетных данных для нативного Anthropic теперь предпочитает обновляемые учетные данные Claude Code скопированным токенам окружения, когда присутствуют и те, и другие. На практике это означает:
- файлы учетных данных Claude Code рассматриваются как предпочтительный источник, если они содержат обновляемую аутентификацию
- ручные значения
ANTHROPIC_TOKEN/CLAUDE_CODE_OAUTH_TOKENпо-прежнему работают как явные переопределения - Hermes выполняет предварительную проверку обновления учетных данных Anthropic перед вызовами нативного API Messages
- Hermes все равно повторяет попытку один раз при 401 после перестроения клиента Anthropic в качестве запасного пути
Путь OpenAI Codex
Codex использует отдельный путь Responses API:
api_mode = codex_responses- выделенное разрешение учетных данных и поддержка хранилища аутентификации
Маршрутизация вспомогательных моделей
Вспомогательные задачи, такие как:
- vision
- суммаризация извлеченного веб-контента
- суммаризация сжатия контекста
- суммаризация поиска по сессиям
- операции skills hub
- операции MCP helper
- сброс памяти
могут использовать собственную маршрутизацию провайдера/модели, а не основную диалоговую модель.
Когда вспомогательная задача настроена с провайдером main, Hermes разрешает ее через тот же общий путь времени выполнения, что и обычный чат. На практике это означает:
- пользовательские конечные точки, определяемые через переменные окружения, по-прежнему работают
- пользовательские конечные точки, сохраненные через
hermes model/config.yaml, также работают - вспомогательная маршрутизация может отличить реальную сохраненную пользовательскую конечную точку от запасного пути OpenRouter
Запасные модели
Hermes поддерживает настроенную цепочку запасных провайдеров — список кортежей (provider, model), которые используются по порядку, когда основная модель сталкивается с ошибками. Устаревший словарь fallback_model (одна пара) по-прежнему принимается для обратной совместимости (и мигрируется при первой записи).
Как это работает внутри
-
Хранение:
AIAgent.__init__сохраняет словарьfallback_modelи устанавливает_fallback_activated = False. -
Точки срабатывания:
_try_activate_fallback()вызывается из трех мест в основном цикле повторных попыток вrun_agent.py: - После превышения максимального числа повторных попыток при недопустимых ответах API (None choices, отсутствующее содержимое)
- При не подлежащих повторению клиентских ошибках (HTTP 401, 403, 404)
-
После превышения максимального числа повторных попыток при временных ошибках (HTTP 429, 500, 502, 503)
-
Поток активации (
_try_activate_fallback): - Возвращает
Falseнемедленно, если уже активирован или не настроен - Вызывает
resolve_provider_client()изauxiliary_client.pyдля создания нового клиента с правильной аутентификацией - Определяет
api_mode:codex_responsesдля openai-codex,anthropic_messagesдля anthropic,chat_completionsдля всего остального - Заменяет на месте:
self.model,self.provider,self.base_url,self.api_mode,self.client,self._client_kwargs - Для запасного варианта anthropic: создает нативный клиент Anthropic вместо совместимого с OpenAI
- Повторно оценивает кеширование промптов (включено для моделей Claude на OpenRouter)
- Устанавливает
_fallback_activated = True— предотвращает повторное срабатывание -
Сбрасывает счетчик повторных попыток на 0 и продолжает цикл
-
Поток конфигурации:
- CLI:
cli.pyчитаетCLI_CONFIG["fallback_model"]→ передает вAIAgent(fallback_model=...) - Gateway:
gateway/run.py._load_fallback_model()читаетconfig.yaml→ передает вAIAgent - Валидация: оба ключа
providerиmodelдолжны быть непустыми, иначе запасной вариант отключен
Что НЕ поддерживает запасной вариант
- Делегирование сабагентам (
tools/delegate_tool.py): сабагенты наследуют провайдера родителя, но не конфигурацию запасного варианта - Вспомогательные задачи: используют собственную независимую цепочку автоматического определения провайдера (см. Маршрутизацию вспомогательных моделей выше)
Задания cron поддерживают запасной вариант: run_job() читает fallback_providers (или устаревший fallback_model) из config.yaml и передает его в AIAgent(fallback_model=...), следуя шаблону _load_fallback_model() из gateway. См. Внутреннее устройство Cron.
Тестовое покрытие
См. tests/test_fallback_model.py для всесторонних тестов, покрывающих всех поддерживаемых провайдеров, семантику однократного вызова и граничные случаи.