Hermes Agent я использую как основной «агентный комбайн». Долгое время он крутился на DeepSeek, но захотелось экспериментов с LLM - первое за что взялся GigaChat от Сбера: русский язык, российская юрисдикция и огромное количество токенов "за красивые глаза". Казалось бы, делов-то - подставить ключ в конфиг. Но не тут-то было.

Под капотом вылезло три нюанса, из-за которых «просто подставить ключ» не работает:

- OAuth2 вместо API-ключа. У GigaChat нет статического ключа в стиле DeepSeek/OpenAI. Есть «ключ авторизации» (по сути client_id:client_secret в base64), который нужно обменивать на короткоживущий access_token (живёт ~30 минут) и периодически обновлять.

- Это не drop-in OpenAI. Формат tools/function-calling, streaming-события и список моделей у GigaChat отличаются, поэтому «направить SDK в его endpoint» напрямую не выйдет — посыплются ошибки на мелочах.

- Сертификаты Минцифры. Эндпоинты GigaChat (api.giga.chat, а также OAuth ngw.devices.sberbank.ru:9443) подписаны «Русским доверенным УЦ» (Минцифры), которого нет в стандартном CA-bundle (certifi) внутри контейнера. Любой запрос с включённой проверкой TLS падает с self-signed certificate / unable to get local issuer certificate.

Вывод напрашивается сам собой: между Hermes и GigaChat нужен свой прокси, который возьмёт на себя OAuth-обмен, трансляцию OpenAI-протокола и работу с сертификатами.

Этап 1. Берём готовый шлюз gpt2giga

Писать трансляцию OpenAI → GigaChat с нуля — так себе идея: слишком много подводных камней в маппинге tools, streaming и списка моделей. К счастью, у ai-forever есть зрелый проект gpt2giga - FastAPI-прокси, который:

- принимает OpenAI-совместимые (а также Anthropic/Gemini) запросы и переводит их в GigaChat;

- сам делает OAuth-обмен и обновляет токен по истечении;

- фильтрует транспортные заголовки и отделяет API-ключ прокси от учёток GigaChat;

- отдаёт /models, /chat/completions, /embeddings в OpenAI-виде.

Этап 2. Модели

Актуальный список моделей смотрим через сам прокси (после первого пробного запуска):

curl -s http://127.0.0.1:8090/v1/models -H "Authorization: Bearer $GPT2GIGA_API_KEY"

На момент написания это: GigaChat-2, GigaChat-2-Max, GigaChat-2-Pro, GigaChat-3-Lightning, GigaChat-3-Pro, GigaChat-3-Ultra (+ эмбеддинги EmbeddingsGigaR и др.).

Этап 3. Сертификаты Минцифры (та самая особенность)

Дефолтный certifi внутри python:*-slim-образа gpt2giga не знает про корневой сертификат Минцифры. Первый же запрос в GigaChat с GIGACHAT_VERIFY_SSL_CERTS=True умирает:

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain

Самый простой «костыль» — поставить GIGACHAT_VERIFY_SSL_CERTS=False. Но это отключает проверку TLS целиком: между вашим сервером и Сбером появляется возможность MITM. Для LLM-прокси, через который идут мои данные, так делать не хочется.

Решение — подложить нужные сертификаты:

  1. Качаем корневой и промежуточные сертификаты с Госуслуг

  2. Кладём их в crt/ рядом с compose-файлом.

  3. Собираем из них единый CA-bundle (они в PEM, так что это просто конкатенация):

    cat Russian_Trusted_Root_CA.cer Russian_Trusted_Sub_CA.cer Russian_Trusted_Sub_CA_2024.cer > gigachat-ca-bundle.pem

  4. Монтируем в контейнер (./crt:/certs:ro в compose) и указываем bundle в .env (уже сделано выше):

GIGACHAT_VERIFY_SSL_CERTS=True
GIGACHAT_CA_BUNDLE_FILE=/certs/gigachat-ca-bundle.pem

Этап 4. Подключаем Hermes

Hermes подключается к прокси как к custom-провайдеру. Две вещи:

1. В hermes.env кладём ключ прокси:

GIGACHAT_PROXY_API_KEY='<тот_самый_GPT2GIGA_API_KEY>'

2. В config.yaml Hermes (HERMES_HOME=/opt/data в контейнере) прописываем провайдера и модели:

Скрытый текст
providers:
  gigachat:
    api: http://gigachat-proxy:8090/v1     # alias контейнера в сети nginx
    key_env: GIGACHAT_PROXY_API_KEY
    transport: chat_completions
    default_model: GigaChat-3-Lightning
    context_length: 131072
model:
  provider: custom:gigachat
  default: GigaChat-3-Lightning
# Дополнительные модели для переключения командой /model <alias>
model_aliases:
  max:   { model: GigaChat-2-Max,   provider: custom:gigachat }
  pro:   { model: GigaChat-3-Pro,   provider: custom:gigachat }
  ultra: { model: GigaChat-3-Ultra, provider: custom:gigachat }
# Если GigaChat недоступен — откат на DeepSeek
fallback_providers:
  - { provider: deepseek, model: deepseek-chat }

Небольшое наблюдение: в WebUI Hermes для custom-провайдера выпадающий список моделей показывает только модель по умолчанию — это особенность веб-интерфейса, а не конфига. Переключение на max/pro/ultra при этом работает командой в чате /model max и т.д. (алиасы подхватываются корректно).

Что в итоге

1. Поднят gigachat-proxy на базе gpt2giga — OAuth-обмен, трансляция OpenAI→GigaChat и модели под капотом.

2. Решена особенность с сертификатами: собран CA-bundle из корневого и промежуточных сертификатов Минцифры, проверка TLS осталась включённой (verify_ssl_certs=True + ca_bundle_file).

3. Hermes переведён на GigaChat (GigaChat-3-Lightning по умолчанию) с откатом на DeepSeek и переключением моделей через /model.

Бонус: тот же gigachat-proxy можно подставить в любой другой OpenAI-совместимый инструмент (OpenCode, openclaw и т.п.) — он выглядит как обычный OpenAI-эндпоинт с обычным статическим Bearer-ключом.

На всякий случай проект полностью готовый к экспуатации