H繁中版
文件開發者指南model provider plugin
<!-- Source: https://hermesbible.com/docs/developer-guide/model-provider-plugin -->

建立模型 Provider 外掛

模型 provider 外掛宣告一個推論後端 — 一個 OpenAI 相容的端點、一個 Anthropic Messages 伺服器、一個 Codex 風格的 Responses API,或一個 Bedrock 原生介面 — Hermes 可以透過它路由 AIAgent 呼叫。每個內建 provider(OpenRouter、Anthropic、GMI、DeepSeek、Nvidia……)都以外掛形式發佈。第三方可以透過在 $HERMES_HOME/plugins/model-providers/ 下放入一個目錄來新增自己的,無需對 repo 做任何修改。

提示

模型 provider 外掛是第三種 provider 外掛。其他兩種是 Memory Provider Plugins(跨 session 知識)和 Context Engine Plugins(上下文壓縮策略)。三者遵循相同的「放入目錄、宣告設定檔、不修改 repo」模式。

發現機制如何運作

providers/__init__.py._discover_providers() 在程式中首次呼叫 get_provider_profile()list_providers() 時延遲執行。發現順序:

  1. 內建外掛<repo>/plugins/model-providers/<name>/ — 隨 Hermes 一起發佈
  2. 使用者外掛$HERMES_HOME/plugins/model-providers/<name>/ — 放入任何目錄;後續 session 不需要重新啟動
  3. 舊式單檔案<repo>/providers/<name>.py — 為樹外可編輯安裝提供向後相容

使用者外掛會覆寫同名的內建外掛,因為 register_provider() 是後寫者優先的。放入一個 $HERMES_HOME/plugins/model-providers/gmi/ 目錄即可取代內建的 GMI 設定檔而無需修改 repo。

目錄結構

plugins/model-providers/my-provider/
├── __init__.py       # 在模組級別呼叫 register_provider(profile)
├── plugin.yaml       # kind: model-provider + 中繼資料(選用但建議)
└── README.md         # 設定說明(選用)

唯一必要的檔案是 __init__.pyplugin.yamlhermes plugins 用於自省,並由通用 PluginManager 用於將外掛路由到正確的載入器;沒有它時,通用載入器會回退到原始碼文字啟發式。

最小範例 — 簡單的 API key provider

# 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)
# 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.py從設定檔填充的 PROVIDER_REGISTRY["acme-inference"]
--provider CLI 旗標hermes_cli/main.py接受 acme-inference
hermes model 選擇器hermes_cli/models.py出現在 CANONICAL_PROVIDERS 中,模型列表從 {base_url}/models 取得
hermes doctorhermes_cli/doctor.pyACME_API_KEY 健康檢查 + {base_url}/models 探測
hermes setuphermes_cli/config.pyACME_API_KEY 出現在 OPTIONAL_ENV_VARS 和設定精靈中
URL 反向對應agent/model_metadata.py主機名 → provider 名稱用於自動偵測
輔助模型agent/auxiliary_client.py使用 default_aux_model 進行壓縮/摘要
執行階段解析hermes_cli/runtime_provider.py回傳正確的 base_urlapi_keyapi_mode
傳輸層agent/transports/chat_completions.py設定檔路徑透過 prepare_messages / build_extra_body / build_api_kwargs_extras 產生 kwargs

ProviderProfile 欄位

完整定義在 providers/base.py 中。最有用的欄位:

欄位類型用途
namestr規範 ID — 對應 config.yaml 中的 model.provider--provider 旗標
aliasestuple[str, ...]get_provider_profile() 解析的替代名稱(例如 grokxai
api_modestrchat_completions | codex_responses | anthropic_messages | bedrock_converse
display_namestrhermes model 選擇器中顯示的人類標籤
descriptionstr選擇器副標題
signup_urlstr首次設定時顯示(「在此取得 API key」)
env_varstuple[str, ...]按優先順序排列的 API key 環境變數;最後的 *_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_temperatureAnyNone = 使用呼叫者的值;OMIT_TEMPERATURE 哨兵 = 完全不發送 temperature(Kimi)
default_max_tokensint | NoneProvider 級別的 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 特定的訊息預處理。在 codex 清理後、
        開發者角色交換前執行。預設:直接通過。"""
        # 範例:Qwen 將純文字內容正規化為部分列表陣列
        # 並注入 cache_control;Kimi 重寫工具呼叫 JSON
        return messages

    def build_extra_body(self, *, session_id=None, **context) -> dict:
        """Provider 特定的 extra_body 欄位,合併到 API 呼叫中。
        上下文包含:session_id、provider_preferences、model、base_url、
        reasoning_config。預設:空字典。"""
        # 範例:OpenRouter 的 provider-preferences 區塊、
        # Gemini 的 thinking_config 翻譯。
        return {}

    def build_api_kwargs_extras(self, *, reasoning_config=None, **context):
        """回傳 (extra_body_additions, top_level_kwargs)。當某些
        欄位進入頂層(Kimi 的 reasoning_effort、OpenRouter 針對
        自適應 Anthropic 模型的 verbosity)而某些進入 extra_body
        (OpenRouter 的 reasoning 字典)時需要。預設:({}, {})。"""
        return {}, {}

    def fetch_models(self, *, api_key=None, timeout=8.0) -> list[str] | None:
        """即時目錄取得。預設使用 Bearer 認證命中
        {models_url 或 base_url}/models。需要以下情況時覆寫:自訂認證
        (Anthropic)、無 REST 端點(Bedrock → None)、或公開/無認證目錄
        (OpenRouter)。"""
        return super().fetch_models(api_key=api_key, timeout=timeout)

鉤子參考範例

參考這些內建外掛以了解慣用法:

外掛為什麼要看
plugins/model-providers/openrouter/帶有 provider 偏好設定的聚合器、公開模型目錄
plugins/model-providers/gemini/thinking_config 翻譯(原生 + OpenAI 相容嵌套格式)
plugins/model-providers/kimi-coding/OMIT_TEMPERATUREextra_body.thinking、頂層 reasoning_effort
plugins/model-providers/qwen-oauth/訊息正規化、cache_control 注入、VL 高解析度
plugins/model-providers/nous/歸屬標籤、「停用時省略推理」
plugins/model-providers/custom/Ollama num_ctx + think: false 特殊情況
plugins/model-providers/bedrock/api_mode="bedrock_converse"fetch_models 回傳 None(無 REST 端點)

使用者覆寫 — 無需修改 repo 即可取代內建

假設你想將 gmi 指向你的私有 staging 端點進行測試。建立 ~/.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",
))

下一個 session,get_provider_profile("gmi").base_url 會回傳 staging URL。無需 repo 修補,無需重建。因為使用者外掛在內建之後被發現,所以使用者的 register_provider() 呼叫會優先生效。

api_mode 選擇

識別四個值。Hermes 根據以下條件選擇:

  1. 使用者明確覆寫(設定時的 config.yaml model.api_mode
  2. OpenCode 的每模型分派(用於 Zen 和 Go 的 opencode_model_api_mode
  3. URL 自動偵測 — /anthropic 後綴 → anthropic_messagesapi.openai.comcodex_responsesapi.x.aicodex_responses、Kimi 域名上的 /codingchat_completions
  4. 設定檔 api_mode 作為 URL 偵測無結果時的後備
  5. 預設 chat_completions

設定 profile.api_mode 以匹配你的 provider 預設出貨的值 — 它作為提示。使用者 URL 覆寫仍然優先。

認證類型

auth_type意義使用者
api_key單一環境變數攜帶靜態 API key大多數 provider
oauth_device_code裝置碼 OAuth 流程
oauth_external使用者在其他地方登入,權杖進入 auth.jsonAnthropic OAuth、MiniMax OAuth、Gemini Cloud Code、Qwen Portal、Nous Portal
copilotGitHub Copilot 權杖刷新週期copilot 外掛
aws_sdkAWS SDK 認證鏈(IAM 角色、設定檔、環境變數)bedrock 外掛
external_process認證由代理程式產生的子程序處理copilot-acp 外掛

auth_type 門控哪些程式碼路徑將你的 provider 視為「簡單的 api-key provider」 — 如果不是 api_key,PluginManager 仍然會記錄 manifest,但 Hermes 的 CLI 級自動化(doctor 檢查、--provider 旗標、設定精靈委派)可能會跳過它。

發現時機

Provider 發現是延遲的 — 在程式中首次呼叫 get_provider_profile()list_providers() 時觸發。實際上這在啟動時很早發生(auth.py 模組載入會急切地擴展 PROVIDER_REGISTRY)。如果你需要驗證你的外掛已載入,執行:

hermes doctor

— 成功的 auth_type="api_key" 設定檔會出現在 Provider Connectivity 部分,帶有 /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 整合

通用 PluginManagerhermes plugins 操作的那個)會看到模型 provider 外掛但不會匯入它們 — providers/__init__.py 擁有它們的生命週期。管理器記錄 manifest 用於自省,並按 kind: model-provider 分類。當你將一個未標記的使用者外掛放入 $HERMES_HOME/plugins/ 且它恰好以 ProviderProfile 呼叫 register_provider 時,管理器會透過原始碼文字啟發式自動將其強制轉換為 kind: model-provider — 因此外掛即使沒有 plugin.yaml 也能正確路由。

透過 pip 分發

與任何 Hermes 外掛一樣,模型 provider 可以作為 pip 套件發佈。在你的 pyproject.toml 中新增一個入口點:

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

…其中 acme_hermes_plugin:register 是一個呼叫 register_provider(profile) 的函式。通用 PluginManager 在 discover_and_load() 期間取得入口點外掛。對於 kind: model-provider 的 pip 外掛,你仍然需要在 manifest 中宣告 kind(或依賴原始碼文字啟發式)。

完整入口點設定請見 Building a Hermes Plugin

相關頁面



Plugin LLM Access