본문으로 건너뛰기

모델 제공자 플러그인 구축

모델 제공자 플러그인은 Hermes가 AIAgent 호출을 라우팅할 수 있는 추론 백엔드(OpenAI 호환 엔드포인트, Anthropic 메시지 서버, Codex 스타일 응답 API 또는 Bedrock 기본 표면)를 선언합니다. 모든 내장 제공자(OpenRouter, Anthropic, GMI, DeepSeek, Nvidia 등)는 이러한 플러그인 중 하나로 제공됩니다. 제3자는 저장소를 변경하지 않고 $HERMES_HOME/plugins/model-providers/ 아래에 디렉터리를 삭제하여 자신만의 디렉터리를 추가할 수 있습니다.

모델 제공자 플러그인은 제공자 플러그인의 세 번째 종류입니다. 다른 것들은 메모리 제공자 플러그인(교차 세션 지식) 및 컨텍스트 엔진 플러그인(컨텍스트 압축 전략)입니다. 세 가지 모두 동일한 "디렉토리 삭제, 프로필 선언, 저장소 편집 없음" 패턴을 따릅니다.

검색 작동 방식

providers/__init__.py._discover_providers()은 코드가 get_provider_profile() 또는 list_providers()을 처음 호출할 때 느리게 실행됩니다. 검색 순서:

  1. 번들 플러그인<repo>/plugins/model-providers/<name>/ — Hermes와 함께 제공
  2. 사용자 플러그인$HERMES_HOME/plugins/model-providers/<name>/ — 임의의 디렉토리에 놓습니다. 후속 세션에는 다시 시작할 필요가 없습니다.
  3. 레거시 단일 파일<repo>/providers/<name>.py — 트리 외부 편집 가능한 설치를 위한 하위 호환

사용자 플러그인은 동일한 이름의 번들 플러그인을 재정의합니다. register_provider()이 최종 작성자 승리이기 때문입니다. 저장소를 건드리지 않고 내장 GMI 프로필을 바꾸려면 $HERMES_HOME/plugins/model-providers/gmi/ 디렉터리를 삭제하세요.

디렉토리 구조

plugins/model-providers/my-provider/
├── __init__.py # Calls register_provider(profile) at module-level
├── plugin.yaml # kind: model-provider + metadata (optional but recommended)
└── README.md # Setup instructions (optional)

유일한 필수 파일은 __init__.py입니다. plugin.yamlhermes plugins에서 내부 검사를 위해 사용되며 일반 PluginManager에서는 플러그인을 올바른 로더로 라우팅하는 데 사용됩니다. 이것이 없으면 일반 로더는 소스 텍스트 경험적 방법으로 대체됩니다.

최소한의 예 - 간단한 API 키 제공자

# plugins/model-providers/acme-inference/__init__.py
from providers import register_provider
from providers.base import ProviderProfile

acme = ProviderProfile(
name="acme-inference",
aliases=("acme",),
display_name="Acme Inference",
description="Acme — OpenAI-compatible direct API",
signup_url="https://acme.example.com/keys",
env_vars=("ACME_API_KEY", "ACME_BASE_URL"),
base_url="https://api.acme.example.com/v1",
auth_type="api_key",
default_aux_model="acme-small-fast",
fallback_models=(
"acme-large-v3",
"acme-medium-v3",
"acme-small-fast",
),
)

register_provider(acme)
````yaml
# plugins/model-providers/acme-inference/plugin.yaml
name: acme-inference
kind: model-provider
version: 1.0.0
description: Acme Inference — OpenAI-compatible direct API
author: Your Name

그게 다야. 이 두 파일을 삭제한 후 다른 편집 없이 다음 자동 연결이 실행됩니다.

통합어디에그것이 얻는 것
자격 증명 확인hermes_cli/auth.pyPROVIDER_REGISTRY["acme-inference"] 프로필에서 채워짐
--provider CLI 플래그hermes_cli/main.pyacme-inference 허용
hermes model 선택기hermes_cli/models.pyCANONICAL_PROVIDERS에 표시되며, {base_url}/models에서 가져온 모델 목록입니다.
hermes doctorhermes_cli/doctor.pyACME_API_KEY + {base_url}/models 프로브에 대한 상태 확인
hermes setuphermes_cli/config.pyACME_API_KEYOPTIONAL_ENV_VARS에 표시되고 설정 마법사가 나타납니다.
URL 역매핑agent/model_metadata.py호스트 이름 → 자동 감지를 위한 공급자 이름
보조 모델agent/auxiliary_client.py압축/요약을 위해 default_aux_model을 사용합니다.
런타임 해상도hermes_cli/runtime_provider.py올바른 base_url, api_key, api_mode을 반환합니다.
운송agent/transports/chat_completions.py프로필 경로는 prepare_messages / build_extra_body / build_api_kwargs_extras을 통해 kwargs를 생성합니다.

공급자 프로필 필드

providers/base.py의 전체 정의입니다. 가장 유용한 것:

필드유형목적
namestr정식 ID — --provider 선택 항목 및 HERMES_INFERENCE_PROVIDER과 일치합니다.
aliasestuple[str,...]get_provider_profile()에 의해 확인된 대체 이름(예: grokxai)
api_modestrchat_completions | codex_responses | anthropic_messages | bedrock_converse
display_namestrhermes model 선택기에 표시된 휴먼 라벨
descriptionstr선택기 자막
signup_urlstr첫 실행 설정 중에 표시됨("여기서 API 키 가져오기")
env_varstuple[str,...]우선순위에 따른 API 키 환경 변수. 최종 *_BASE_URL 항목은 사용자 기본 URL 재정의로 사용됩니다.
base_urlstr기본 추론 엔드포인트
models_urlstr명시적 카탈로그 URL({base_url}/models으로 대체)
auth_typestrapi_key | oauth_device_code | oauth_external | copilot | aws_sdk | external_process
fallback_modelstuple[str,...]라이브 카탈로그 가져오기에 실패하면 선별된 목록이 표시됩니다.
default_headersdict[str, str]모든 요청에 대해 전송됩니다(예: Copilot의 Editor-Version)
fixed_temperature모두None = 호출자의 값을 사용합니다. OMIT_TEMPERATURE sentinel = 체온을 전혀 보내지 않습니다 (키미)
default_max_tokensint | 없음공급자 수준 max_tokens 한도(Nvidia: 16384)
default_aux_modelstr보조 작업(압축, 비전, 요약)을 위한 저렴한 모델

재정의 가능한 후크

사소한 문제에 대한 하위 클래스 ProviderProfile:

from typing import Any
from providers.base import ProviderProfile

class AcmeProfile(ProviderProfile):
def prepare_messages(self, messages: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""Provider-specific message preprocessing. Runs after codex
sanitization, before developer-role swap. Default: pass-through."""
# Example: Qwen normalizes plain-text content to a list-of-parts
# array and injects cache_control; Kimi rewrites tool-call JSON
return messages

def build_extra_body(self, *, session_id=None, **컨텍스트) -> dict:
"""Provider-specific extra_body fields merged into the API call.
컨텍스트 includes: session_id, provider_preferences, model, base_url,
reasoning_config. Default: empty dict."""
# Example: OpenRouter's provider-preferences block,
# Gemini's thinking_config translation.
return {}

def build_api_kwargs_extras(self, *, reasoning_config=None, **컨텍스트):
"""Returns (extra_body_additions, top_level_kwargs). Needed when some
fields go top-level (Kimi's reasoning_effort) and some go in extra_body
(OpenRouter's reasoning dict). Default: ({}, {})."""
return {}, {}

def fetch_models(self, *, api_key=None, timeout=8.0) -> list[str] | None:
"""Live catalog fetch. Default hits {models_url or base_url}/models with
Bearer auth. Override for: custom auth (Anthropic), no REST endpoint
(Bedrock → None), or public/unauthenticated catalogs (OpenRouter)."""
return super().fetch_models(api_key=api_key, timeout=timeout)

후크 참조 예

관용구에 대한 번들 플러그인을 살펴보세요:

플러그인왜 봐?
plugins/model-providers/openrouter/공급자 기본 설정, 공개 모델 카탈로그가 있는 수집기
plugins/model-providers/gemini/thinking_config 번역(네이티브 + OpenAI 호환 중첩 양식)
plugins/model-providers/kimi-coding/OMIT_TEMPERATURE, extra_body.thinking, 최상위 reasoning_effort
plugins/model-providers/qwen-oauth/메시지 정규화, cache_control 주입, VL 고해상도
plugins/model-providers/nous/속성 태그, "비활성화 시 추론 생략"
plugins/model-providers/custom/올라마 num_ctx + think: false 단점
plugins/model-providers/bedrock/api_mode="bedrock_converse", fetch_models은 없음(REST 끝점 없음)을 반환합니다.

사용자 재정의 - 저장소를 편집하지 않고 내장 교체

테스트를 위해 프라이빗 스테이징 엔드포인트에서 gmi을 가리키고 싶다고 가정해 보겠습니다. ~/.hermes/plugins/model-providers/gmi/__init__.py 생성:

from providers import register_provider
from providers.base import ProviderProfile

register_provider(ProviderProfile(
name="gmi",
aliases=("gmi-cloud", "gmicloud"),
env_vars=("GMI_API_KEY",),
base_url="https://gmi-staging.internal.example.com/v1",
auth_type="api_key",
default_aux_model="google/gemini-3.1-flash-lite-preview",
))

다음 세션에서는 get_provider_profile("gmi").base_url이 스테이징 URL을 반환합니다. 리포지토리 패치도 없고 재구축도 없습니다. 사용자 플러그인은 번들 플러그인 이후에 발견되므로 사용자 register_provider() 호출이 승리합니다.

api_mode 선택

4가지 값이 인식됩니다. Hermes는 다음을 기준으로 하나를 선택합니다.

  1. 사용자 명시적 재정의(설정 시 config.yamlmodel.api_mode)
  2. OpenCode의 모델별 디스패치(Zen 및 Go의 경우 opencode_model_api_mode)
  3. URL 자동 감지 — /anthropic 접미사 → anthropic_messages, api.openai.comcodex_responses, api.x.aicodex_responses, Kimi 도메인의 /codingchat_completions
  4. URL 감지에서 아무것도 찾지 못할 경우 대체용으로 api_mode 프로필을 작성하세요.
  5. 기본값 chat_completions

공급자가 제공하는 기본값과 일치하도록 profile.api_mode을 설정합니다. 이는 힌트 역할을 합니다. 사용자 URL 재정의가 여전히 유효합니다.

인증 유형

auth_type의미누가 그것을 사용합니까?
api_key단일 환경 변수는 정적 API 키를 전달합니다.대부분의 제공자
oauth_device_code장치 코드 OAuth 흐름
oauth_external사용자가 다른 곳에 로그인하면 토큰은 auth.json에 저장됩니다.Anthropic OAuth, MiniMax OAuth, Gemini Cloud Code, Qwen Portal, Nous Portal
copilotGitHub Copilot 토큰 새로 고침 주기copilot 플러그인 전용
aws_sdkAWS SDK 자격 증명 체인(IAM 역할, 프로필, 환경)bedrock 플러그인 전용
external_process에이전트가 생성하는 하위 프로세스에 의해 처리되는 인증copilot-acp 플러그인 전용

auth_type 게이트는 코드 경로가 공급자를 "간단한 API 키 공급자"로 처리합니다. api_key이 아닌 경우 PluginManager는 여전히 매니페스트를 기록하지만 Hermes의 CLI 수준 자동화(의사 확인, --provider 플래그, 설정 마법사 위임)는 이를 건너뛸 수 있습니다.

발견 시기

공급자 검색은 지연입니다. 프로세스의 첫 번째 get_provider_profile() 또는 list_providers() 호출에 의해 트리거됩니다. 실제로 이는 시작 초기에 발생합니다(auth.py 모듈 로드는 PROVIDER_REGISTRY을 열심히 확장합니다). 플러그인이 로드되었는지 확인해야 하는 경우 다음을 실행하세요.

hermes doctor

— 성공적인 auth_type="api_key" 프로필은 /models 프로브가 있는 공급자 연결 섹션 아래에 나타납니다.

프로그래밍 방식 검사의 경우:

from providers import list_providers
for p in list_providers():
print(p.name, p.base_url, p.api_mode)

플러그인 테스트

실제 구성을 오염시키지 않도록 임시 디렉토리에서 HERMES_HOME을 지정하세요.

export HERMES_HOME=/tmp/hermes-plugin-test
mkdir -p $HERMES_HOME/plugins/model-providers/my-provider
cat > $HERMES_HOME/plugins/model-providers/my-provider/__init__.py <<'EOF'
from providers import register_provider
from providers.base import ProviderProfile
register_provider(ProviderProfile(
name="my-provider",
env_vars=("MY_API_KEY",),
base_url="https://api.my-provider.example.com/v1",
auth_type="api_key",
))
EOF

export MY_API_KEY=your-test-key
hermes -z "hello" --provider my-provider -m some-model

일반 PluginManager 통합

일반 PluginManager(hermes plugins이 작동하는 것)은 모델 제공자 플러그인을 보지만 가져오지는 않습니다. — providers/__init__.py이 수명 주기를 소유합니다. 관리자는 점검을 위해 매니페스트를 기록하고 kind: model-provider별로 분류합니다. ProviderProfile을 사용하여 register_provider을 호출하는 레이블이 없는 사용자 플러그인을 $HERMES_HOME/plugins/에 놓으면 관리자는 소스 텍스트 경험적 방법을 통해 해당 플러그인을 kind: model-provider로 자동 강제 변환합니다. plugin.yaml.

pip를 통해 배포

Hermes 플러그인과 마찬가지로 모델 공급자는 pip 패키지로 제공될 수 있습니다. pyproject.toml에 진입점을 추가하세요.

[project.entry-points."hermes.plugins"]
acme-inference = "acme_hermes_plugin:register"

전체 진입점 설정은 Hermes 플러그인 빌드를 참조하세요.