首页 / Hermes Agent 教程 / 模型进阶:路由、Fallback 与凭据池

Hermes Agent 教程

模型进阶:路由、Fallback 与凭据池

本教程共 25 篇 · 第 6 篇 · 更新于 2026-07-26 · 约 16 分钟阅读

Hermes AgentHermes Agent 教程Provider RoutingFallbackCredential PoolsSubscription Proxy高可用

6. 模型进阶:路由、Fallback 与凭据池

本节目标:搞懂 Hermes Agent 的三层弹性机制—Provider Routing、Fallback Providers、Credential Pools,以及怎么用 Subscription Proxy 把你的订阅借给外部应用用。学完你能让智能体在一个 Provider 限流时自动切到另一个、让多个 API Key 轮换扛量、还能让 OpenViking 这类非 Hermes 工具复用你的 Nous Portal 订阅。

三层弹性机制全景

上一章讲的是「怎么配一个模型」。但生产环境里,单个 Provider 早晚会出问题—限流、宕机、欠费、网络抖动。Hermes Agent 设计了三层弹性机制,从内到外依次兜底:

  1. Credential Pools(凭据池):同一个 Provider 下挂多个 API Key,一个 Key 限流了自动换下一个。最先尝试。
  2. Fallback Providers(故障转移):主模型整个 Provider 挂了,自动切到另一个 Provider 的另一个模型。
  3. Auxiliary Task Fallback(辅助任务回退):辅助任务有自己独立的 Provider 解析链,跟主模型的弹性互不干扰。

打个比方,凭据池是你钱包里好几张同一家银行的卡,一张刷不过换另一张;Fallback 是这家银行系统崩了,你掏出另一家银行的卡接着刷。两者独立工作,凭据池先试,全挂了再 Fallback。

Note

这三层都是可选的,不配也能跑。但只要你的智能体要长期跑网关、跑定时任务,配一层 Fallback 几乎是必须的—不然凌晨三点 Provider 限流,你的机器人就哑巴了。

Provider Routing:聚合器内部路由

当你的 Provider 是 OpenRouter 或 Nous Portal 这种聚合器时,背后其实有好多家子 Provider(Anthropic、Google、AWS Bedrock、Together AI 等)。Provider Routing 让你控制请求走哪几家子 Provider、按什么优先级排。

Note

Provider Routing 只在使用 OpenRouter 或 Nous Portal 时生效。直连某个 Provider(比如直连 Anthropic API)时无效—你都直连了,没有子 Provider 可选。

配置

~/.hermes/config.yaml 加一个 provider_routing 段:

provider_routing:
  sort: "price"              # 怎么排序子 Provider
  only: []                   # 白名单:只用这些
  ignore: []                 # 黑名单:绝不用这些
  order: []                  # 显式优先级顺序
  require_parameters: false  # 只用支持全部参数的子 Provider
  data_collection: null      # 控制数据收集("allow" 或 "deny")

五个选项详解

sort 控制排序方式:

含义
"price"最便宜的子 Provider 优先
"throughput"每秒 token 数最高的优先
"latency"首 token 延迟最低的优先

only 是白名单,设了就只用这几家,其他全排除:

provider_routing:
  only:
    - "anthropic"
    - "google"

ignore 是黑名单,这几家永远不用,哪怕它们最便宜最快:

provider_routing:
  ignore:
    - "together"
    - "deepinfra"

order 是显式优先级,列前面的优先,没列的当 fallback:

provider_routing:
  order:
    - "anthropic"
    - "google"
    - "amazon-bedrock"

require_parameterstrue 时,OpenRouter 只把请求路由到支持你所有参数(temperaturetop_ptools 等)的子 Provider。避免参数被静默丢弃。

data_collection 控制子 Provider 能不能拿你的 prompt 训练,"allow""deny"

推荐配方

# 省钱党:最便宜优先,但排除几家不信任的,禁止数据收集
provider_routing:
  sort: "price"
  ignore: ["together"]
  require_parameters: true
  data_collection: "deny"
# 交互党:低延迟优先
provider_routing:
  sort: "latency"
# 一致性党:锁死一家
provider_routing:
  only: ["anthropic"]
Tip

Portal 订阅用户走 Nous Portal 时,同样的 provider_routing 偏好也生效,而且 Portal 订阅用户在按量计费的子 Provider 上还能再打 9 折。

Note

Provider Routing 控制的是聚合器内部的子 Provider。如果你要的是「主 Provider 整个挂了切到另一个 Provider」,那不是 Routing 的事,是下面要讲的 Fallback。

Fallback Providers:跨 Provider 故障转移

当主模型所在的 Provider 出错—限流、过载、鉴权失败、连接中断—Hermes 可以在会话中途自动切到一个备用的 provider:model 组合,对话不丢。

配置

最省心的方式是交互式管理器:

hermes fallback

hermes fallback 复用 hermes model 的选择器,子命令有 addlist(别名 ls)、remove(别名 rm)、clear。改动持久化到 config.yaml 顶层的 fallback_providers: 列表。

或者直接编辑 ~/.hermes/config.yaml

fallback_providers:
  - provider: openrouter
    model: anthropic/claude-sonnet-4

每个条目必须同时有 providermodel,缺一个会被忽略。

Note

fallback_providers(复数,列表)是当前配置形态,支持多个 fallback 按顺序试。fallback_model(单数)是旧版单 fallback 键,Hermes 仍兼容它,但 hermes fallback 写的是新的 fallback_providers 键,并在写入时迁移旧配置。两者同时存在时,fallback_providers 优先。

支持的 Provider

Fallback 支持的 Provider 非常多,下面是主流的:

Provider凭据要求
OpenRouteropenrouterOPENROUTER_API_KEY
Nous Portalnoushermes setup --portalhermes auth add nous
OpenAI Codexopenai-codexhermes model 走 ChatGPT OAuth
GitHub CopilotcopilotCOPILOT_GITHUB_TOKEN / GH_TOKEN / GITHUB_TOKEN
AnthropicanthropicANTHROPIC_API_KEY 或 Claude Code 凭据
Google AI StudiogeminiGOOGLE_API_KEY
xAI (Grok)xaiXAI_API_KEY
AWS Bedrockbedrockboto3 标准鉴权
DeepSeekdeepseekDEEPSEEK_API_KEY
Alibaba / DashScopealibabaDASHSCOPE_API_KEY
Ollama Cloudollama-cloudOLLAMA_API_KEY
LM Studio(本地)lmstudioLM_API_KEY + LM_BASE_URL
Custom endpointcustombase_url + key_env

Custom Endpoint Fallback

自定义 OpenAI 兼容端点也能当 fallback,加 base_url 和可选的 key_env

fallback_providers:
  - provider: custom
    model: my-local-model
    base_url: http://localhost:8000/v1
    key_env: MY_LOCAL_KEY            # 存 API Key 的环境变量名

什么时候触发

Fallback 在主模型遇到这些错误时自动激活:

  • 限流(HTTP 429):重试耗尽后
  • 服务器错误(HTTP 500/502/503):重试耗尽后
  • 鉴权失败(HTTP 401/403):立即(不用重试)
  • 未找到(HTTP 404):立即
  • 无效响应:API 反复返回畸形或空响应时

触发时 Hermes 会:

  1. 解析 fallback Provider 的凭据
  2. 构建新的 API 客户端
  3. 原地替换 model、provider、client
  4. 重置重试计数,继续对话

切换是无缝的—对话历史、工具调用、上下文都保留,智能体从断点继续,只是换了个模型。

关键特性:每回合作用域

Note

Fallback 是回合级的,不是会话级。每条新用户消息开始时,主模型都会被还原。如果主模型在回合中失败,Fallback 只为这个回合激活。下一条消息,Hermes 又试主模型。单个回合内 Fallback 最多激活一次—如果 fallback 也失败,就走正常错误处理。这既防止回合内的级联故障循环,又给主模型每回合一次新机会。

Fallback 在哪些场景生效

场景Fallback 支持
CLI 会话
消息网关(Telegram/Discord 等)
子智能体委托是(子智能体继承父级的 fallback 链)
定时任务是(cron 智能体继承配置的 fallback)
辅助任务(provider: auto是(先试任务级 fallback,再试主 fallback 链)
Tip

主 fallback 链没有环境变量配置,只能通过 config.yamlhermes fallback 配。这是故意的—fallback 配置是个慎重决定,不该被一个过期的 shell export 覆盖。

推荐配方

# Anthropic 原生为主,OpenRouter 兜底
model:
  provider: anthropic
  default: claude-sonnet-4-6

fallback_providers:
  - provider: openrouter
    model: anthropic/claude-sonnet-4
# 本地模型为主,云端兜底(本地跑 90%,硬题打云端)
model:
  default: "gemma4:31b"
  provider: "custom"
  base_url: "http://localhost:11434/v1"

fallback_providers:
  - provider: openrouter
    model: anthropic/claude-sonnet-4
# OpenRouter 为主,Codex OAuth 兜底
fallback_providers:
  - provider: openai-codex
    model: gpt-5.3-codex
Warning

Fallback 会重置提示词缓存。提示词缓存按模型(多数 Provider 还按账号)绑定。Fallback 触发时,新 provider:model 对你的对话没有缓存前缀,下一条请求按全价输入 token 重读整个历史,而不是 75-90% 折扣的缓存价。回合结束主模型还原时,第一条回主模型的请求也是全价重读(除非主模型的缓存 TTL 还没过)。这是熬过故障的代价—长会话在 Provider 之间来回弹跳,成本会明显高于一直待在一个 Provider。

Credential Pools:同 Provider 多 Key 轮换

凭据池让你给同一个 Provider 注册多个 API Key 或 OAuth token。一个 Key 限流或欠费了,Hermes 自动轮换到下一个健康 Key—不用切 Provider,会话继续。

这跟 Fallback 不一样:Fallback 是切到另一个 Provider,凭据池是同 Provider 内换 Key。凭据池先试,全挂了才轮到 Fallback。

Tip

凭据池主要给 API Key 类 Provider 用(OpenRouter、Anthropic)。一个 Nous Portal OAuth 就覆盖 300+ 模型,Portal 用户基本不需要配池子。

工作流程

你的请求
  -> 从池里选 Key(round_robin / least_used / fill_first / random)
  -> 发给 Provider
  -> 429 限流?
      -> 是套餐/用量上限(如 ChatGPT/Codex "usage limit reached")?
          -> 立即轮换到下一个池 Key(不重试,上限不会因重试而清)
      -> 普通/瞬时 429?
          -> 同一个 Key 重试一次(瞬时抖动)
          -> 第二次 429 -> 轮换到下一个池 Key
      -> 所有 Key 耗尽 -> fallback_model(换 Provider)
  -> 402 计费错误?
      -> 立即轮换到下一个池 Key(24 小时冷却)
  -> 401 鉴权过期?
      -> 先试刷新 token(OAuth)
      -> 刷新失败 -> 轮换到下一个池 Key
  -> 成功 -> 正常继续

快速上手

如果你已经在 .env 里设了 API Key,Hermes 会自动把它发现成一个 1 Key 的池。要享受池化,加更多 Key:

# 加第二个 OpenRouter Key
hermes auth add openrouter --api-key sk-or-v1-your-second-key

# 加第二个 Anthropic Key
hermes auth add anthropic --type api-key --api-key sk-ant-api03-your-second-key

# 加 Anthropic OAuth 凭据(需要 Claude Max 套餐 + 额外用量额度)
hermes auth add anthropic --type oauth
# 会打开浏览器做 OAuth

查看池子:

hermes auth list

输出长这样:

openrouter (2 credentials):
  #1  OPENROUTER_API_KEY   api_key env:OPENROUTER_API_KEY ←
  #2  backup-key           api_key manual

anthropic (3 credentials):
  #1  hermes_pkce          oauth   hermes_pkce ←
  #2  claude_code          oauth   claude_code
  #3  ANTHROPIC_API_KEY    api_key env:ANTHROPIC_API_KEY

标记当前选中的凭据。

轮换策略

通过 hermes auth -> “Set rotation strategy” 或 config.yaml 配:

credential_pool_strategies:
  openrouter: round_robin
  anthropic: least_used
策略行为
fill_first(默认)用第一个健康 Key 直到耗尽,再换下一个
round_robin均匀循环,每次选完后轮换
least_used总是选请求计数最低的 Key
random在健康 Key 里随机选

错误恢复

池子对不同错误处理方式不同:

错误行为冷却
429 限流同 Key 重试一次(瞬时)。连续第二次 429 轮换1 小时
402 计费/配额立即轮换24 小时
401 鉴权过期先试刷新 OAuth token。刷新失败才轮换-
所有 Key 耗尽透传到 fallback_model(换 Provider)-

has_retried_429 标志在每次成功 API 调用时重置,所以单次瞬时 429 不会触发轮换。

自动发现

Hermes 启动时从多个来源自动发现凭据并填充池子:

来源示例自动入池
环境变量OPENROUTER_API_KEYANTHROPIC_API_KEY
OAuth token(auth.json)Codex 设备码、Nous 设备码
Claude Code 凭据~/.claude/.credentials.json是(Anthropic)
Hermes PKCE OAuth~/.hermes/auth.json是(Anthropic)
自定义端点配置config.yaml 里的 model.api_key是(自定义端点)
手动添加hermes auth add持久化到 auth.json

自动入池的条目每次加载池时更新—删了环境变量,对应的池条目自动修剪。手动添加的条目不会被自动修剪。

委托与子智能体共享

智能体通过 delegate_task 派生子智能体时,父级的凭据池自动共享给子级:

  • 同 Provider:子级继承父级完整池子,限流时能轮换 Key
  • 不同 Provider:子级加载该 Provider 自己的池子(如果配了)
  • 没配池子:子级回退到继承的单个 API Key

子智能体不用额外配置就能享受跟父级一样的限流韧性。按任务租借凭据,保证子级并发轮换 Key 时不互相冲突。

Warning

Key 轮换会重置提示词缓存。Provider 侧的提示词缓存(Anthropic、OpenAI、OpenRouter)按发起请求的账号/API Key 作用域。会话中途池子轮换到另一个 Key 时,新 Key 对你的对话没有缓存前缀,下一条请求按全价重读整个历史,轮换回去时又是一次全价重读(除非前一个 Key 的缓存 TTL 还活着)。轮换保住了会话不中断,但长对话里每次轮换都是一次全价过上下文。

Auxiliary Task Fallback:辅助任务的独立链

辅助任务(视觉、压缩、网页抽取、技能搜索等)有自己独立的 Provider 解析链,跟主模型的弹性互不干扰。

自动检测链

当任务的 provider 设为 "auto"(默认)时,Hermes 先试主 Provider + 主模型。如果该路由不可用或之后遇到容量级错误,Hermes 按这个顺序兜底:

主 Provider + 主模型 -> auxiliary.<task>.fallback_chain ->
fallback_providers / fallback_model -> 内置辅助发现链

任务级链最精确,有就先用。顶层 fallback_providers 链跟主智能体用的一样,所以免费或同 Provider 的 fallback 规则也作用于 auto 的辅助任务。

内置文本发现链(压缩、网页抽取、标题生成等):

OpenRouter -> Nous Portal -> Custom endpoint -> Codex OAuth ->
API-key providers(z.ai、Kimi、MiniMax、Xiaomi MiMo、Hugging Face、Anthropic)-> 放弃

内置视觉发现链

主 Provider(如果支持视觉)-> OpenRouter -> Nous Portal ->
Codex OAuth -> Anthropic -> Custom endpoint -> 放弃

这些内置链是给没声明任务级或主 fallback 策略的用户的便利兜底。

配置辅助任务

每个任务可以独立配:

auxiliary:
  vision:
    provider: "auto"              # auto | openrouter | nous | codex | main | anthropic
    model: ""                     # 如 "openai/gpt-4o"
    base_url: ""                  # 直连端点(优先于 provider)
    api_key: ""                   # base_url 的 API Key

  compression:
    provider: "auto"
    model: ""
    fallback_chain:               # 可选,任务级 fallback 策略
      - provider: openrouter
        model: inclusionai/ring-2.6-1t:free

省略 fallback_chain 时,provider: auto 会先走顶层 fallback_providers 链,再走内置辅助发现链。

任务级 fallback_chain

想要跟「主智能体模型优先」不同的顺序,就显式配 fallback_chain

auxiliary:
  vision:
    provider: glm
    model: glm-4v-flash
    fallback_chain:
      - provider: openrouter
        model: google/gemini-3-flash-preview
      - provider: nous
        model: anthropic/claude-sonnet-4

  compression:
    provider: openrouter
    fallback_chain:
      - provider: openai
        model: gpt-4o-mini
        timeout: 240            # 可选,这个候选自己的超时(秒)

每个 fallback_chain 条目还能声明自己的 timeout。不声明就继承任务级超时—而任务级超时可能是为主 Provider 调的。声明 per-entry timeout 能让一个慢但可靠的 fallback(比如大上下文摘要器)拿到它真正需要的预算。

Note

不配 fallback_chain 也有 fallback—主智能体模型的安全网无论如何都会跑。fallback_chain 只在你想要跟默认不同的顺序时才配。

容量错误回退

当你显式设了辅助 Provider(比如 auxiliary.vision.provider: glm),Hermes 把它当首选。但如果该 Provider 因为容量错误(HTTP 402 欠费、HTTP 429 日配额耗尽、连接失败)实在没法服务请求,Hermes 走分层链兜底,而不是静默失败:

  1. 主辅助 Provider—你配的那个(总是先试)
  2. auxiliary.<task>.fallback_chain—你写的 per-task 覆盖列表
  3. 主智能体 Provider + 模型—最后的安全网(总会试,即使你没写链)
  4. 警告 + 重抛—全挂了就记 Auxiliary <task>: ... all fallbacks exhausted 警告,重抛原始错误

瞬时 HTTP 429 限流(Retry-After: ...)被当作请求约束,不是容量问题—它们尊重你显式选的 Provider,不触发 fallback 阶梯。只有日/月配额耗尽、计费错误、连接失败才绕过显式 Provider 门槛。

Tip

Hermes 识别这些短语为容量等效于 402 信用耗尽(不是瞬时限流):Bedrock/LiteLLM 的 Too many tokens per daydaily limit;Vertex AI/GCP 的 quota exceededresource exhaustedRESOURCE_EXHAUSTED;通用的 daily quotaquota_exceeded。如果你的 Provider 返回了不同的配额耗尽措辞而 Hermes 没触发 fallback,那是 bug—带完整错误字符串提 issue。

Subscription Proxy:把订阅给外部应用用

Subscription Proxy 是一个本地 HTTP 服务器,让外部应用—OpenViking、Karakeep、Open WebUI,任何会讲 OpenAI 兼容 chat completions 的应用—把你 Hermes 管理的 Provider 订阅当它们的 LLM 端点用。Proxy 自动挂上正确的凭据(自动刷新),应用永远不需要静态 API Key。

这跟 API Server 不一样:

API ServerSubscription Proxy
服务什么你的智能体(完整工具集、记忆、技能)裸模型推理
用例「把 Hermes 当聊天后端」「让别的应用用我的 Portal 订阅」
鉴权你的 API_SERVER_KEY任意 bearer(proxy 挂真凭据)
工具调用是—智能体跑工具否—纯透传

智能体当后端用 API Server。只要模型走你的订阅用 Subscription Proxy。

快速上手

  1. 登录 Provider(一次性):
hermes portal

浏览器走 Nous Portal OAuth,refresh token 存 ~/.hermes/auth.json

  1. 启动 proxy:
hermes proxy start

输出:

Starting Hermes proxy for Nous Portal
  Listening on:  http://127.0.0.1:8645/v1
  Forwarding to: (resolved per-request from your subscription)
  Use any bearer token in the client - the proxy attaches your real credential.
  1. 把应用指向它。任何 OpenAI 兼容应用配置三件套:
Base URL:   http://127.0.0.1:8645/v1
API key:    anything (e.g. "sk-unused")
Model:      Hermes-4-70B    # 或 Hermes-4.3-36B, Hermes-4-405B

Proxy 忽略应用发的 Authorization 头,挂上你真实的 Portal 凭据发上游。bearer 快过期时自动刷新。

支持的 Provider

hermes proxy providers

目前内置 nous(Nous Portal)和 xai(xAI / Grok)。更多 OAuth Provider 可以通过实现 hermes_cli/proxy/adapters/ 里的 UpstreamAdapter 接口加。

允许的路径

Proxy 只转发上游真正服务的路径。Nous Portal 的:

路径用途
/v1/chat/completions聊天补全(流式 + 非流式)
/v1/completions旧版文本补全
/v1/embeddings嵌入
/v1/models模型列表

其他路径(/v1/images/generations/v1/audio/speech 等)返回 404 带清晰错误,指向允许的路径。防止乱七八糟的客户端往上游漏奇怪请求。

配 Karakeep 之类应用

Karakeep 接受 OpenAI 兼容 API 做书签摘要。在它的 .env 里:

OPENAI_API_BASE_URL=http://127.0.0.1:8645/v1
OPENAI_API_KEY=any-non-empty-string
INFERENCE_TEXT_MODEL=Hermes-4-70B

同样的模式适用于 Open WebUI、LobeChat、NextChat 或任何其他 OpenAI 兼容客户端。

Warning

Proxy 默认绑 127.0.0.1(仅本机)。要让局域网其他机器用:

hermes proxy start --host 0.0.0.0 --port 8645

注意:网络上任何人都能用你的 Portal 订阅。Proxy 自己没鉴权—它接受任何 bearer。暴露到可信网络之外时,用防火墙、VPN 或带正确鉴权的反向代理。

多 Profile 网关路由

结合第 04 章的 Profile 体系,你可以给不同 Profile 配不同的主模型 + Fallback 链,再让网关按用户/频道路由到对应 Profile。这是多团队、多场景共享一个 Hermes 实例的标准玩法。

典型场景:一台服务器跑一个 Hermes 网关,给三个团队用—A 团队走便宜模型省钱,B 团队走 Opus 拼质量,C 团队走本地 Ollama 零成本。每个团队一个 Profile,各自配自己的 modelfallback_providers,网关层按 Telegram 群组或 Discord 频道路由。

Note

Nous Portal 的 refresh token 在所有 Profile 之间通过共享 token store 自动共享。在任一 Profile 登录一次,其他 Profile 自动拿到。多用户共享一台机器时,每个用户有自己的 Portal 账号 -> 每个家目录有自己的 ~/.hermes/auth.json -> 用户之间不共享 token。这是正确的边界。

委托的 Provider 覆盖

delegate_task 派生的子智能体继承父级的 fallback 链。但你也可以给所有子智能体统一指定一个不同的主 provider:model,做成本优化:

delegation:
  provider: "openrouter"                      # 覆盖所有子智能体的 Provider
  model: "google/gemini-3-flash-preview"      # 覆盖模型
  # base_url: "http://localhost:1234/v1"      # 或用直连端点
  # api_key: "local-key"

主智能体用 Opus 思考,子任务用 Flash 跑—这是常见的省钱姿势。

定时任务的 Provider 覆盖

定时任务创建智能体时继承你配的 fallback_providers 链。要给某个 cron 任务用不同的主 Provider,在任务上配 providermodel 覆盖:

cronjob(
    action="create",
    schedule="every 2h",
    prompt="Check server status",
    provider="openrouter",
    model="google/gemini-3-flash-preview"
)

这一章讲的是「怎么让多个 Provider 协同、扛住故障」。下一章我们钻进 Hermes Agent 的内核—Agent 循环(Agent Loop),看一条用户消息是怎么在模型、工具、记忆之间流转的,以及 iteration-budget、bounded-response 这些机制怎么防止智能体跑飞。