Hermes 自定义 AI Provider 配置方法梳理
本文整理自社区实践与底层源码 review,旨在客观呈现 Hermes 中自定义 AI Provider 的安全配置路径,并标注用户经验与代码实现之间的差异和补充说明。
用户实践中的配置流程
以下步骤来源于 Herald 的实际操作经验,描述了他总结的“安全添加第三方自定义 AI Provider”的完整流程。
第一步:准备 Provider 基本信息
在开始前,需要确认以下信息:
- base url:API 端点地址
- api key:访问密钥
- model name:模型名称
第二步:交互式添加 custom provider
通过 hermes model 命令进入交互式向导:
- 填写 base url 和 模型名
- api key 留空(该字段为选填项)
- 上下文尺寸知道可填,不知道可留空
注意:根据底层代码(hermes_cli/main.py:_model_flow_custom),如果在此步骤中填写了 api key,该密钥会被同时写入~/.hermes/config.yaml的model.api_key字段以及custom_providers条目的api_key字段。因此,若追求密钥不留在配置文件中,此步骤不应填写 api key。
第三步:修改配置文件中的 provider 名称
交互添加后,默认会以 base url 命名 provider。用户可手动修改 ~/.hermes/config.yaml,将名称改为更具可读性的形式。例如:
model:
default: kimi-for-coding
provider: custom:kimi-plan
custom_providers:
- name: kimi-plan
base_url: https://api.kimi.com/coding/v1
model: kimi-for-coding
models:
kimi-for-coding:
context_length: 256000第四步:通过 credential pool 添加 api key
执行以下命令为自定义 provider 添加密钥:
hermes auth add kimi-plan --api-key <YOUR_API_KEY>底层实现中,该命令会将密钥写入独立的 credential pool 存储,而不会落入 config.yaml。这样可避免配置文件中的密钥明文泄漏风险。
第五步:重启 gateway
配置和密钥添加完成后,重启 gateway 即可生效。
底层源码视角的补充与修正
以下分析基于对 Hermes 底层代码的直接阅读,对前述流程进行验证和补充。
1. custom_providers 名称解析的灵活性
代码层面,model.provider 支持两种写法:
custom:kimi-plan:带custom:前缀的 slug,可直接定位custom_providers中的对应条目custom:传统写法,此时依赖base_url来匹配custom_providers
用户示例中的 provider: custom:kimi-plan 是完全符合底层预期的写法。底层在解析时大小写不敏感,且会自动将空格替换为 -,因此命名容错空间较大。
2. 上下文尺寸自动探测的完整链路
用户提到“不知道可以留空让程序自动探测”,这一点底层确实有完整支持,但探测逻辑有明确的优先级:
custom_providers中models.<model>.context_length的手写配置- 本地缓存
~/.hermes/context_length_cache.yaml - models.dev / OpenRouter 元数据缓存(当 base_url 属于已知 provider 时,如
api.kimi.com) - 直接探测端点
/models(对 local / ollama / vLLM / LM Studio 等特别有效) - 上下文递减探测(从 128K 逐步向下尝试,直到 API 不返回上下文超限错误)
- 最终 fallback 到 128K
因此,留空自动探测对标准 OpenAI-compatible 端点通常有效;若端点 /models 返回格式不标准或未包含 context_length,则可能退回到 128K 默认值。
3. hermes auth add 的密钥存储机制
底层代码路径为 agent/credential_pool.py 和 hermes_cli/auth_commands.py:
_normalize_provider("kimi-plan")发现匹配custom_providers中的名称后,将其规范化为custom:kimi-plan- 生成
PooledCredential条目,写入 credential pool 持久化存储 - 运行时,
runtime_provider.py的_try_resolve_from_custom_pool()会优先从 pool 读取密钥
这意味着:
- API key 不会进入 config.yaml
- 该机制天然支持多 key 轮询(
fill_first、round_robin、random等策略)
4. 关于“重启 gateway”的适用范围
需要区分运行模式:
- CLI 模式:改完配置、添加 auth 后,下一次调用即生效,无需重启
- Gateway 模式(作为后台服务接收 Telegram / Discord / Slack 消息):
model.provider和model.default在启动时加载并缓存,因此需要重启 gateway 才能感知变更
流程对照总结
| 用户描述 | 底层验证 | 说明 |
|---|---|---|
hermes model 交互添加,不填 api key |
正确 | _model_flow_custom 支持此操作 |
手动修改 custom_providers 的 name |
正确 | name 可自定义,slug 为 custom:<name> |
hermes auth add <provider> --api-key |
正确 | 写入 credential pool,避开 config.yaml |
| 留空 context_length 自动探测 | 部分正确 | 标准端点有效,非标准端点可能 fallback 128K |
| 重启 gateway 使用 | 基本正确 | CLI 无需重启,gateway 需要重启 |
额外建议
如果你已经通过 hermes auth add 将 key 存入了 credential pool,建议进一步检查 config.yaml 中是否残留有此前交互时意外写入的 api_key 字段,并予以清理,以确保配置文件中不存在任何密钥明文。
为 auxiliary 任务配置自定义 Provider 的注意事项
Hermes 的 auxiliary 系统(负责图片理解、上下文压缩、网页摘要等侧边任务)与主对话模型在读取 API Key 时的逻辑并不完全相同。
核心差异:当 auxiliary 任务使用 named custom provider 时,如果该 provider 没有显式指定 key_env,底层不会 fallback 到 OPENAI_API_KEY 或 OPENROUTER_API_KEY,而是直接发送 Bearer no-key-required,导致服务商返回 401 Unauthorized。更糟糕的是,部分 API 网关(如 SiliconFlow)在鉴权层拒绝请求之前,可能已经在网关接入层记录了输入 token 并产生计费。
因此,只要你的自定义 provider 需要 API Key 认证,就必须在 custom_providers 中显式设置 key_env,例如:
custom_providers:
- name: siliconflow
base_url: https://api.siliconflow.cn/v1
key_env: SILICONFLOW_API_KEY # 必须
models:
Qwen/Qwen3.5-27B:
context_length: 256000随后在 auxiliary 中直接引用该 provider 名称即可:
auxiliary:
vision:
provider: siliconflow
model: Qwen/Qwen3.5-27B
timeout: 30不需要在auxiliary.vision里重复写base_url或api_key。key_env只需写一次——放在custom_providers的入口里。
多模型配置建议
不要在 custom_providers 里为同一个 endpoint 创建多个 entry。Hermes 在解析 named custom provider 时只会命中列表里第一个匹配 name 的 entry,后续同名的 entry 会被忽略。
如果你需要为同一个 provider 配置多个模型的上下文长度,请使用 models 子字典:
custom_providers:
- name: siliconflow
base_url: https://api.siliconflow.cn/v1
key_env: SILICONFLOW_API_KEY
models:
Qwen/Qwen3.5-27B:
context_length: 256000
deepseek-ai/DeepSeek-V3:
context_length: 64000model 字段(与 models 同级)不是必须的。若省略,Hermes 会 fallback 到你在 model.default 中配置的主模型,或最终使用 gpt-4o-mini。
Member discussion