Пулы учётных данных

Пулы учётных данных позволяют зарегистрировать несколько API-ключей или OAuth-токенов для одного провайдера. Когда один ключ достигает лимита запросов или квот биллинга, Hermes автоматически переключается на следующий здоровый ключ — поддерживая вашу сессию активной без смены провайдера.

Это отличается от резервных провайдеров, которые полностью переключаются на другого провайдера. Пулы учётных данных — это ротация в рамках одного провайдера; резервные провайдеры — это отказоустойчивость между провайдерами. Сначала пробуждаются пулы — если все ключи пула исчерпаны, тогда активируется резервный провайдер.

Как это работает

Ваш запрос
  → Выбрать ключ из пула (round_robin / least_used / fill_first / random)
  → Отправить провайдеру
  → 429 превышение лимита?
      → Повторить с тем же ключом один раз (временный сбой)
      → Второй 429 → переключиться на следующий ключ пула
      → Все ключи исчерпаны → fallback_model (другой провайдер)
  → 402 ошибка биллинга?
      → Немедленно переключиться на следующий ключ пула (24-часовой тайм-аут)
  → 401 истекла аутентификация?
      → Попробовать обновить токен (OAuth)
      → Обновление не удалось → переключиться на следующий ключ пула
  → Успех → продолжить нормально

Быстрый старт

Если у вас уже есть API-ключ, установленный в .env, Hermes автоматически обнаружит его как пул из одного переключателя. Чтобы воспользоваться преимуществами пула, добавьте больше ключей:

# Добавить второй ключ OpenRouter
hermes auth add openrouter --api-key sk-or-v1-your-second-key

# Добавить второй ключ Anthropic
hermes auth add anthropic --type api-key --api-key sk-ant-api03-your-second-key

# Добавить учётные данные OAuth Anthropic (требуется план Claude Max + дополнительные кредиты использования)
hermes auth add anthropic --type oauth
# Открывает браузер для входа через OAuth

Проверьте свои пулы:

hermes auth list

Вывод:

openrouter (2 credentials):
  #1  OPENROUTER_API_KEY   api_key env:OPENROUTER_API_KEY ←
  #2  backup-key           api_key manual

anthropic (3 credentials):
  #1  hermes_pkce          oauth   hermes_pkce ←
  #2  claude_code          oauth   claude_code
  #3  ANTHROPIC_API_KEY    api_key env:ANTHROPIC_API_KEY

запишите текущую выбранную учётную запись.

Интерактивное управление

Запустите hermes auth без подкоманд для интерактивного мастера:

hermes auth

Это покажет полный статус вашего пула и предложит меню:

Что вы хотите сделать?
  1. Добавить учётные данные
  2. Удалить учётные данные
  3. Сбросить тайм-ауты для провайдера
  4. Установить стратегию ротации для провайдера
  5. Выйти

Для провайдеров, поддерживающих как API-ключи, так и OAuth (Anthropic, Nous, Codex), процесс добавления типа запроса:

anthropic поддерживает как API-ключи, так и вход через OAuth.
  1. API-ключ (вставьте ключ из панели управления провайдера)
  2. Вход через OAuth (аутентификация через браузер)
Введите [1/2]:

Команды CLI

Команда Описание
гермес авт Интерактивный мастер управления пулом
список аутентификации Гермеса Показать все пулы и учётные данные
список аутентификации Гермеса <поставщик> Показать пул конкретного провайдера
hermes auth add <провайдер> Добавить учётные данные (запрашивает тип и ключ)
hermes auth add <провайдер> --type api-key --api-key <ключ> Добавить API-ключ неинтерактивно
hermes auth add <провайдер> --type oauth Добавить учётные данные OAuth через вход в браузер
hermes auth удалить <поставщик> <индекс> Удалить учётные данные по индексу (с 1)
сброс аутентификации Гермеса <поставщик> Очистить все тайм-ауты/статус исчерпания

Стратегии ротации

Настраиваем через hermes auth → "Установить таймер ротации" или в config.yaml:

credential_pool_strategies:
  openrouter: round_robin
  anthropic: least_used
Стратегия Поведение
fill_first (по умолчанию) Используйте первый здоровый ключ, пока он не исчерпан, а затем перейдите к следующему
round_robin Равномерно перебирать ключи, переключаясь после каждого выбора
наименее_используемый Всегда выбирайте ключ с наименьшим количеством запросов
случайный Случайный выбор среди здоровых ключей

Восстановление после ошибок

Пул обрабатывает разные ошибки по-разному:

Ошибка Поведение Тайм-аут
429 Превышение лимита Повторить с тем же ключом один раз (временный). Второй последовательный 429 переключает на следующую клавишу 1 час
402 Биллинг/Квота Немедленно переключиться на следующий ключ 24 часа
401 Стекло аутентификации Сначала попробуйте обновить OAuth-токен. Переключить только если обновление не удалось
Все ключи исчерпаны Перейдите к fallback_model, если по настроению

Флаг has_retried_429 сбрасывается при каждом успешном вызове API, поэтому один временной код 429 не вызывает ротации.

Пользовательские пулы конечных точек

Пользовательские конечные точки, совместимые с OpenAI (Together.ai, RunPod, локальные серверы), получают свои собственные пулы, ключом которых является имя конечной точки из custom_providers в config.yaml.

Когда вы настраиваете пользовательскую конечную точку через «модель Hermes», она автоматически автоматически генерирует имя, например «Together.ai» или «Local (localhost:8080)». Это имя становится ключом пула.

# После настройки пользовательской конечной точки через hermes model:
hermes auth list
# Показывает:
#   Together.ai (1 credential):
#     #1  config key    api_key config:Together.ai ←

# Добавить второй ключ для той же конечной точки:
hermes auth add Together.ai --api-key sk-together-second-key

Пользовательские пулы конечных точек сохраняются в auth.json под credential_pool с префиксом custom::

{
  "credential_pool": {
    "openrouter": [...],
    "custom:together.ai": [...]
  }
}

Автообнаружение

Гермес автоматически обнаруживает учётные данные из нескольких источников и заполняет пул при запуске:

Источник Пример Автозаполнение?
Переменные окружения OPENROUTER_API_KEY, ANTHROPIC_API_KEY Да
OAuth-токены (auth.json) Код устройства Codex, код устройства Nous Да
Учётные данные Claude Code ~/.claude/.credentials.json Да (Антропный)
PKCE OAuth Гермес ~/.hermes/auth.json Да (Антропный)
Конфигурация пользовательской конечной точки model.api_key в config.yaml Да (пользовательские конечные точки)
Ручные записи Добавлены через hermes auth add Сохраняются в auth.json

Автозаполненные записи обновляются при каждом включении пула — если вы удалите переменную окружность, ее запись в пуле автоматически удаляется. Ручные записи (добавленные через hermes auth add) никогда не удаляются автоматически.

Делегирование и совместное использование с подагентами

Когда агент резервирует подагентов через delegate_task, пул учётных данных родителя автоматически передаётся дочерним агентам:

Это означает, что подагенты получают ту же устойчивость к ограничениям скорости, что и родитель, без дополнительных настроек. Аренда учётных данных для каждой задачи гарантирует, что дочерние агенты не будут конфликтовать друг с другом при одновременной ротации ключей.

Потокобезопасность

Пул учётных данных использует потоки блокировки для всех нарушений состояния (select(), mark_exhausted_and_rotate(), try_refresh_current(), mark_used()). Это обеспечивает безопасный конкурентный доступ, когда шлюз обрабатывает несколько сеансов чата одновременно.

Архитектура

Полную диаграмму потока данных см. в docs/credential-pool-flow.excalidraw в репозитории.

Пул учётных данных интегрируется на уровне разрешения провайдера:

  1. agent/credential_pool.py — Менеджер пула: хранение, выбор, ротация, тайм-ауты
  2. hermes_cli/auth_commands.py — Команды CLI и интерактивный мастер
  3. hermes_cli/runtime_provider.py — разрешение учётных данных с учётом пула.
  4. run_agent.py — Восстановление после ошибок: 429/402/401 → ротация пула → резервный провайдер

Хранение

Состояние пула хранится в ~/.hermes/auth.json под ключом credential_pool:

{
  "version": 1,
  "credential_pool": {
    "openrouter": [
      {
        "id": "abc123",
        "label": "OPENROUTER_API_KEY",
        "auth_type": "api_key",
        "priority": 0,
        "source": "env:OPENROUTER_API_KEY",
        "access_token": "sk-or-v1-...",
        "last_status": "ok",
        "request_count": 142
      }
    ]
  },
}

Стратегии хранения в config.yaml (не в auth.json):

credential_pool_strategies:
  openrouter: round_robin
  anthropic: least_used