Hermes-agent

This commit is contained in:
Zakaria
2026-06-14 14:30:48 -04:00
commit dac4b88b94
5058 changed files with 1884848 additions and 0 deletions
@@ -0,0 +1,202 @@
---
sidebar_position: 4
title: "Provider 运行时解析"
description: "Hermes 如何在运行时解析 provider、凭据、API 模式及辅助模型"
---
# Provider 运行时解析
Hermes 拥有一个共享的 provider 运行时解析器,用于以下场景:
- CLI
- gateway
- cron 任务
- ACP
- 辅助模型调用
主要实现:
- `hermes_cli/runtime_provider.py` — 凭据解析,`_resolve_custom_runtime()`
- `hermes_cli/auth.py` — provider 注册表,`resolve_provider()`
- `hermes_cli/model_switch.py` — 共享 `/model` 切换流水线(CLI + gateway
- `agent/auxiliary_client.py` — 辅助模型路由
- `providers/` — ABC + 注册表入口点(`ProviderProfile``register_provider``get_provider_profile``list_providers`
- `plugins/model-providers/<name>/` — 每个 provider 的插件(内置),声明 `api_mode``base_url``env_vars``fallback_models` 并在首次访问时将自身注册到注册表。用户插件位于 `$HERMES_HOME/plugins/model-providers/<name>/`,会覆盖同名的内置插件。
`providers/` 中的 `get_provider_profile()` 为给定 provider 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` 自动识别它——无需在解析器本身中添加分支。
如果你想添加一个新的一等推理 provider,请结合本页阅读 [添加 Provider](./adding-providers.md) 和 [Model Provider 插件指南](./model-provider-plugin.md)。
## 解析优先级
从高层来看,provider 解析使用以下顺序:
1. 显式 CLI/运行时请求
2. `config.yaml` 中的模型/provider 配置
3. 环境变量
4. provider 特定的默认值或自动解析
该顺序很重要,因为 Hermes 将已保存的模型/provider 选择视为正常运行的真实来源。这可以防止过时的 shell 导出变量悄悄覆盖用户在 `hermes model` 中最后选择的端点。
## Provider
当前 provider 系列包括(完整内置集合见 `plugins/model-providers/`):
- OpenRouter
- Nous Portal
- OpenAI Codex
- Copilot / Copilot ACP
- Anthropic(原生)
- Google / Gemini`gemini``google-gemini-cli`
- Alibaba / DashScope`alibaba``alibaba-coding-plan`
- DeepSeek
- Z.AI
- Kimi / Moonshot`kimi-coding``kimi-coding-cn`
- MiniMax`minimax``minimax-cn``minimax-oauth`
- Kilo Code
- Hugging Face
- OpenCode Zen / OpenCode Go
- AWS Bedrock
- Azure Foundry
- NVIDIA NIM
- xAIGrok
- Arcee
- GMI Cloud
- StepFun
- Qwen OAuth
- Xiaomi
- Ollama Cloud
- LM Studio
- Tencent TokenHub
- Custom`provider: custom`)— 适用于任何 OpenAI 兼容端点的一等 provider
- 命名自定义 provider`config.yaml` 中的 `custom_providers` 列表)
## 运行时解析的输出
运行时解析器返回的数据包括:
- `provider`
- `api_mode`
- `base_url`
- `api_key`
- `source`
- provider 特定的元数据,如过期/刷新信息
## 为什么这很重要
该解析器是 Hermes 能够在以下场景之间共享认证/运行时逻辑的主要原因:
- `hermes chat`
- gateway 消息处理
- 在全新会话中运行的 cron 任务
- ACP 编辑器会话
- 辅助模型任务
## OpenRouter 与自定义 OpenAI 兼容 base URL
Hermes 包含相关逻辑,以避免在存在多个 provider 密钥时(例如同时存在 `OPENROUTER_API_KEY``OPENAI_API_KEY`)将错误的 API key 泄露给自定义端点。
每个 provider 的 API key 仅作用于其自身的 base URL
- `OPENROUTER_API_KEY` 仅发送至 `openrouter.ai` 端点
- `OPENAI_API_KEY` 用于自定义端点及作为回退
Hermes 还区分以下两种情况:
- 用户主动选择的真实自定义端点
- 未配置自定义端点时使用的 OpenRouter 回退路径
这种区分对以下场景尤为重要:
- 本地模型服务器
- 非 OpenRouter 的 OpenAI 兼容 API
- 无需重新运行 setup 即可切换 provider
- 通过 config 保存的自定义端点,即使当前 shell 中未导出 `OPENAI_BASE_URL` 也应正常工作
## 原生 Anthropic 路径
Anthropic 不再仅限于"通过 OpenRouter"访问。
当 provider 解析选择 `anthropic` 时,Hermes 使用:
- `api_mode = anthropic_messages`
- 原生 Anthropic Messages API
- `agent/anthropic_adapter.py` 进行转换
原生 Anthropic 的凭据解析现在在两者同时存在时,优先使用可刷新的 Claude Code 凭据,而非复制的环境变量 token。实际效果为:
- 包含可刷新认证的 Claude Code 凭据文件被视为首选来源
- 手动设置的 `ANTHROPIC_TOKEN` / `CLAUDE_CODE_OAUTH_TOKEN` 值仍可作为显式覆盖
- Hermes 在调用原生 Messages API 前会预检 Anthropic 凭据刷新
- Hermes 在重建 Anthropic 客户端后,仍会在收到 401 时重试一次,作为回退路径
## OpenAI Codex 路径
Codex 使用独立的 Responses API 路径:
- `api_mode = codex_responses`
- 专用的凭据解析和认证存储支持
## 辅助模型路由
辅助任务包括:
- 视觉
- 网页提取摘要
- 上下文压缩摘要
- skills hub 操作
- MCP 辅助操作
- 记忆刷新
这些任务可以使用各自独立的 provider/模型路由,而非主对话模型。
当辅助任务配置的 provider 为 `main` 时,Hermes 通过与普通对话相同的共享运行时路径进行解析。实际效果为:
- 环境变量驱动的自定义端点仍然有效
- 通过 `hermes model` / `config.yaml` 保存的自定义端点同样有效
- 辅助路由能够区分真实保存的自定义端点与 OpenRouter 回退
## 回退模型
Hermes 支持配置回退 provider 链——一个按顺序尝试的 `(provider, model)` 条目列表,当主模型遇到错误时依次尝试。旧版单对 `fallback_model` 字典仍被接受以保持向后兼容(并在首次写入时迁移)。
### 内部工作原理
1. **存储**`AIAgent.__init__` 存储 `fallback_model` 字典并将 `_fallback_activated` 设为 `False`
2. **触发点**`_try_activate_fallback()``run_agent.py` 主重试循环的三处被调用:
- 在无效 API 响应(None choices、缺少 content)达到最大重试次数后
- 在不可重试的客户端错误(HTTP 401、403、404)时
- 在瞬时错误(HTTP 429、500、502、503)达到最大重试次数后
3. **激活流程**`_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 兼容客户端
- 重新评估 prompt 缓存(对 OpenRouter 上的 Claude 模型启用)
-`_fallback_activated` 设为 `True`——防止再次触发
- 将重试计数重置为 0 并继续循环
4. **配置流程**
- CLI`cli.py` 读取 `CLI_CONFIG["fallback_model"]` → 传递给 `AIAgent(fallback_model=...)`
- Gateway`gateway/run.py._load_fallback_model()` 读取 `config.yaml` → 传递给 `AIAgent`
- 验证:`provider``model` 键均须非空,否则回退被禁用
### 不支持回退的场景
- **子代理委托**`tools/delegate_tool.py`):子代理继承父代理的 provider,但不继承回退配置
- **辅助任务**:使用各自独立的 provider 自动检测链(见上方辅助模型路由)
Cron 任务**支持**回退:`run_job()``config.yaml` 读取 `fallback_providers`(或旧版 `fallback_model`)并传递给 `AIAgent(fallback_model=...)`,与 gateway 的 `_load_fallback_model()` 模式一致。参见 [Cron 内部机制](./cron-internals.md)。
### 测试覆盖
参见 `tests/test_fallback_model.py`,其中包含覆盖所有支持 provider、单次触发语义及边界情况的完整测试。
## 相关文档
- [Agent 循环内部机制](./agent-loop.md)
- [ACP 内部机制](./acp-internals.md)
- [上下文压缩与 Prompt 缓存](./context-compression-and-caching.md)