ByteNoteByteNote

字节笔记本

2026年6月21日

hermes教程-模型提供者插件

API中转
¥120

构建模型提供者插件

模型提供者插件声明一个推理后端——一个兼容 OpenAI 的端点、一个 Anthropic Messages 服务器、一个 Codex 风格的 Responses API,或一个 Bedrock 原生接口——Hermes 可以通过它路由 AIAgent 调用。每个内置提供者(OpenRouter、Anthropic、GMI、DeepSeek、Nvidia 等)都作为这些插件之一提供。第三方可以通过在 $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() 是最后写入者获胜。放置一个 $HERMES_HOME/plugins/model-providers/gmi/ 目录即可替换内置的 GMI 配置文件,无需触碰仓库。

目录结构

text
plugins/model-providers/my-provider/
├── __init__.py       # 在模块级别调用 register_provider(profile)
├── plugin.yaml       # kind: model-provider + 元数据(可选但推荐)
└── README.md         # 设置说明(可选)

唯一必需的文件是 __init__.pyplugin.yamlhermes plugins 用于内省,并被通用 PluginManager 用于将插件路由到正确的加载器;没有它,通用加载器会回退到源文本启发式方法。

最小示例——一个简单的 API 密钥提供者

python
## 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 的直接 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 的直接 API
author: Your Name

就是这样。放置这两个文件后,以下集成自动连接,无需其他编辑:

集成位置获取内容
凭据解析hermes_cli/auth.pyPROVIDER_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主机名 → 提供者名称,用于自动检测
辅助模型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规范标识符 — 匹配 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 密钥”)
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_temperatureAnyNone = 使用调用者的值;OMIT_TEMPERATURE 哨兵 = 不发送 temperature(Kimi)
default_max_tokensint | None提供者级别的 max_tokens 上限(Nvidia:16384)
default_aux_modelstr用于辅助任务(压缩、视觉、摘要)的廉价模型

可覆盖的钩子

子类化 ProviderProfile 以处理非平凡的特殊情况:

python
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]]:
        """提供者特定的消息预处理。在 codex 清理之后、开发者角色交换之前运行。默认:透传。"""
## 示例:Qwen 将纯文本内容规范化为部件数组并注入 cache_control;Kimi 重写工具调用 JSON
        return messages

    def build_extra_body(self, *, session_id=None, **context) -> dict:
        """提供者特定的 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 的 verbosity 用于自适应 Anthropic 模型)
        而某些放在 extra_body(OpenRouter 的 reasoning 字典)时使用。默认:({}, {})。"""
        return {}, {}

    def fetch_models(self, *, api_key=None, timeout=8.0) -> list[str] | None:
        """实时目录获取。默认使用 Bearer 认证访问 {models_url or base_url}/models。
        覆盖用于:自定义认证(Anthropic)、无 REST 端点(Bedrock → None)、
        或公共/未认证目录(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_TEMPERATUREextra_body.thinking、顶层 reasoning_effort
plugins/model-providers/qwen-oauth/消息规范化、cache_control 注入、VL 高分辨率
plugins/model-providers/nous/归属标签、“禁用时省略 reasoning”
plugins/model-providers/custom/Ollama 的 num_ctx + think: false 特殊处理
plugins/model-providers/bedrock/api_mode="bedrock_converse"fetch_models 返回 None(无 REST 端点)

用户覆盖——无需编辑仓库即可替换内置提供者

假设你想将 gmi 指向你的私有测试端点。创建 ~/.hermes/plugins/model-providers/gmi/__init__.py

python
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 选择

有四个可识别的值。Hermes 根据以下规则选择:

  1. 用户显式覆盖(config.yaml 中的 model.api_mode,如果设置)
  2. OpenCode 的按模型分发(opencode_model_api_mode 用于 Zen 和 Go)
  3. URL 自动检测 — /anthropic 后缀 → anthropic_messagesapi.openai.comcodex_responsesapi.x.aicodex_responses,Kimi 域上的 /codingchat_completions
  4. 配置文件 api_mode 作为 URL 检测未找到时的回退
  5. 默认 chat_completions

设置 profile.api_mode 以匹配你的提供者默认提供的模式——它作为一个提示。用户 URL 覆盖仍然优先。

认证类型

auth_type含义谁使用它
api_key单个环境变量携带静态 API 密钥大多数提供者
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 决定了哪些代码路径将你的提供者视为“简单的 API 密钥提供者”——如果不是 api_key,PluginManager 仍会记录清单,但 Hermes 的 CLI 级别自动化(doctor 检查、--provider 标志、设置向导委托)可能会跳过它。

发现时机

提供者发现是惰性的——由进程中第一次调用 get_provider_profile()list_providers() 触发。实际上,这发生在启动早期(auth.py 模块加载会急切地扩展 PROVIDER_REGISTRY)。如果你需要验证你的插件是否已加载,运行:

bash
hermes doctor

——一个成功的 auth_type="api_key" 配置文件将出现在“提供者连接”部分,并带有 /models 探测。

用于程序化检查:

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

测试你的插件

HERMES_HOME 指向一个临时目录,以免污染你的真实配置:

bash
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 操作的对象)能看到模型提供者插件,但不会导入它们——providers/__init__.py 负责它们的生命周期。管理器记录清单用于内省,并根据 kind: model-provider 进行分类。当你将一个未标记的用户插件放入 $HERMES_HOME/plugins/ 中,且该插件恰好调用了带有 ProviderProfileregister_provider 时,管理器会通过源文本启发式方法自动将其强制转换为 kind: model-provider——因此即使没有 plugin.yaml,插件也能正确路由。

通过 pip 分发

像任何 Hermes 插件一样,模型提供者可以作为 pip 包分发。在你的 pyproject.toml 中添加一个入口点:

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 插件,你仍然需要在清单中声明 kind(或依赖源文本启发式方法)。

有关完整的入口点设置,请参阅构建 Hermes 插件

相关页面

分享: