提供商运行时解析
Hermes 拥有一套共享的提供商运行时解析器,适用于以下所有场景:
- CLI
- 网关
- 定时任务
- ACP
- 辅助模型调用
主要实现文件:
hermes_cli/runtime_provider.py— 凭证解析、_resolve_custom_runtime()hermes_cli/auth.py— 提供商注册表、resolve_provider()hermes_cli/model_switch.py— 共享的/model切换管道(CLI + 网关)agent/auxiliary_client.py— 辅助模型路由providers/— ABC + 注册表入口(ProviderProfile、register_provider、get_provider_profile、list_providers)plugins/model-providers/<name>/— 每个提供商的插件(内置),声明api_mode、base_url、env_vars、fallback_models并在首次访问时注册到注册表中。$HERMES_HOME/plugins/model-providers/<name>/下的用户插件会覆盖同名内置插件。
providers/ 中的 get_provider_profile() 为给定提供商 ID 返回一个 ProviderProfile。runtime_provider.py 在解析时调用此函数,以获取规范的 base_url、env_vars 优先级列表、api_mode 和 fallback_models,无需在多个文件中重复这些数据。在 plugins/model-providers/<your-provider>/(或 $HERMES_HOME/plugins/model-providers/<your-provider>/)下新增调用 register_provider() 的插件,即可被 runtime_provider.py 自动识别——无需在解析器中添加额外的分支判断。
如果您想添加一个新的一流推理提供商,请同时阅读添加提供商和模型提供商插件指南。
解析优先级
从高层来看,提供商解析遵循以下顺序:
- 显式的 CLI/运行时请求
config.yaml中的模型/提供商配置- 环境变量
- 提供商特定的默认值或自动解析
此顺序至关重要,因为 Hermes 将已保存的模型/提供商选择视为正常运行时的真实来源。这可以防止过时的 shell 环境变量悄悄覆盖用户在 hermes model 中最后选择的端点。
提供商列表
当前支持的提供商家族包括:
- AI Gateway(Vercel)
- OpenRouter
- Nous Portal
- OpenAI Codex
- Copilot / Copilot ACP
- Anthropic(原生)
- Google / Gemini
- Alibaba / DashScope
- DeepSeek
- Z.AI
- Kimi / Moonshot
- MiniMax
- MiniMax China
- Kilo Code
- Hugging Face
- OpenCode Zen / OpenCode Go
- Custom(
provider: custom)— 适用于任何 OpenAI 兼容端点的一流提供商 - 命名自定义提供商(
config.yaml中的custom_providers列表)
运行时解析的输出
运行时解析器返回的数据包括:
providerapi_modebase_urlapi_keysource- 提供商特定的元数据,如过期/刷新信息
为何重要
正是这个解析器,使 Hermes 可以在以下场景之间共享认证/运行时逻辑:
hermes chat- 网关消息处理
- 在全新会话中运行的定时任务
- ACP 编辑器会话
- 辅助模型任务
AI Gateway
在 ~/.hermes/.env 中设置 AI_GATEWAY_API_KEY,使用 --provider ai-gateway 运行。Hermes 从网关的 /models 端点获取可用模型,并过滤出支持工具调用的语言模型。
OpenRouter、AI Gateway 与自定义 OpenAI 兼容 base URL
当同时存在多个提供商密钥时(例如 OPENROUTER_API_KEY、AI_GATEWAY_API_KEY 和 OPENAI_API_KEY),Hermes 包含避免将错误 API 密钥泄露给自定义端点的逻辑。
每个提供商的 API 密钥都限定于其自身的 base URL:
OPENROUTER_API_KEY只会发送给openrouter.ai端点AI_GATEWAY_API_KEY只会发送给ai-gateway.vercel.sh端点OPENAI_API_KEY用于自定义端点,并作为回退
Hermes 还区分:
- 用户主动选择的真实自定义端点
- 未配置自定义端点时使用的 OpenRouter 回退路径
这种区分对以下场景尤为重要:
- 本地模型服务器
- 非 OpenRouter/非 AI Gateway 的 OpenAI 兼容 API
- 无需重新运行设置即可切换提供商
- 通过配置保存的自定义端点(即使当前 shell 中未导出
OPENAI_BASE_URL,也应正常工作)
原生 Anthropic 路径
Anthropic 不再仅限于"通过 OpenRouter"使用了。
当提供商解析选择 anthropic 时,Hermes 使用:
api_mode = anthropic_messages- 原生 Anthropic Messages API
agent/anthropic_adapter.py进行翻译适配
原生 Anthropic 的凭证解析现在优先使用可刷新的 Claude Code 凭证,而非复制的环境变量令牌(当两者同时存在时)。实际上这意味着:
- 包含可刷新认证的 Claude Code 凭证文件被视为首选来源
- 手动设置的
ANTHROPIC_TOKEN/CLAUDE_CODE_OAUTH_TOKEN仍可作为显式覆盖使用 - Hermes 在发起原生 Messages API 调用前会预检 Anthropic 凭证的刷新状态
- 作为回退路径,Hermes 在重建 Anthropic 客户端后遇到 401 错误时仍会重试一次
OpenAI Codex 路径
Codex 使用独立的 Responses API 路径:
api_mode = codex_responses- 专用的凭证解析和认证存储支持
辅助模型路由
以下辅助任务:
- 视觉(Vision)
- 网页提取摘要
- 上下文压缩摘要
- 会话搜索摘要
- 技能中心操作
- MCP 辅助操作
- 记忆刷新
可以使用独立于主对话模型的提供商/模型路由。
当辅助任务配置的提供商为 main 时,Hermes 通过与普通对话相同的共享运行时路径进行解析。这意味着:
- 环境变量驱动的自定义端点仍可正常工作
- 通过
hermes model/config.yaml保存的自定义端点也可正常工作 - 辅助路由能够区分真实保存的自定义端点与 OpenRouter 回退路径
回退模型
Hermes 支持配置回退模型/提供商对,当主模型遇到错误时可在运行时进行故障转移。
内部工作原理
-
存储:
AIAgent.__init__存储fallback_model字典,并将_fallback_activated设为False。 -
触发点:
_try_activate_fallback()在run_agent.py主重试循环的三个位置被调用:- 在 API 响应无效(choices 为 None、内容缺失)达到最大重试次数后
- 出现不可重试的客户端错误时(HTTP 401、403、404)
- 在瞬时错误(HTTP 429、500、502、503)达到最大重试次数后
-
激活流程(
_try_activate_fallback):- 若已激活或未配置,立即返回
False - 调用
auxiliary_client.py中的resolve_provider_client()以使用正确的认证信息构建新客户端 - 确定
api_mode:openai-codex 对应codex_responses,anthropic 对应anthropic_messages,其他所有情况对应chat_completions - 原地替换:
self.model、self.provider、self.base_url、self.api_mode、self.client、self._client_kwargs - 对于 anthropic 回退:构建原生 Anthropic 客户端而非 OpenAI 兼容客户端
- 重新评估提示词缓存(在 OpenRouter 上对 Claude 模型启用)
- 将
_fallback_activated设为True— 防止再次触发 - 将重试计数重置为 0 并继续循环
- 若已激活或未配置,立即返回
-
配置流程:
- CLI:
cli.py读取CLI_CONFIG["fallback_model"]→ 传递给AIAgent(fallback_model=...) - 网关:
gateway/run.py._load_fallback_model()读取config.yaml→ 传递给AIAgent - 验证:
provider和model键均不得为空,否则禁用回退
- CLI:
不支持回退的场景
- 子 Agent 委托(
tools/delegate_tool.py):子 Agent 继承父级的提供商,但不继承回退配置 - 辅助任务:使用各自独立的提供商自动检测链(见上方辅助模型路由)
定时任务支持回退:run_job() 从 config.yaml 读取 fallback_providers(或旧版 fallback_model),并将其传递给 AIAgent(fallback_model=...),与网关的 _load_fallback_model() 模式保持一致。详见定时任务内部机制。
测试覆盖
参见 tests/test_fallback_model.py 获取涵盖所有支持提供商、单次激活语义和边界情况的完整测试。