看不见的第二个模型:Hermes 的后台调用链该怎么配、怎么查


某个周一早上,你打开会话列表,发现昨天那场重要对话的标题是 {"title": "修复 CI 里...——一大串被截断的 JSON。另一次,你把主模型换成便宜的快速模型之后,命令审批开始变得不像话:明明无害的命令被拦、明显危险的却放行。还有人在本地跑 llama.cpp 时抱怨“压缩一次要等好几分钟”。这三件事看起来毫无关系,但它们的根往往是同一条你看不见的调用链——auxiliary(辅助)任务。

你每天在用、却从没配过的那条调用链

Hermes 的主模型并不是什么活都自己干。除了你看到的对话,它还会在后台发起一批小请求:

  • 每个会话开始时起标题;
  • 上下文快满时做总结压缩;
  • 一条命令要不要拦下来问你,由一个小模型先分类;
  • 你把截图丢给一个纯文本模型时,是另一个视觉模型在描述图片;
  • 技能库检索、记忆检索的查询改写、看板任务拆解、/goal 是否达成的判定、邮箱打分,以及每轮结束后那个自我复盘(存记忆 / 给技能打补丁)。

这些任务在代码里有明确的名字。截至 main,内置 13 个:

任务 key 显示名 干什么
vision Vision 图片/截图分析(纯文本主模型的描述器)
compression Compression 上下文摘要
approval Approval 智能命令审批分类
mcp MCP MCP 工具相关推理
title_generation Title generation 会话标题
review Review /review 评审子代理
memory_query_rewrite Memory query rewrite 记忆检索的查询改写
tts_audio_tags TTS audio tags Gemini TTS 的标签插入
skills_hub Skills hub 技能搜索与安装
triage_specifier Triage specifier 看板 Triage 便签扩写成规格
kanban_decomposer Kanban decomposer 任务拆解成子任务图
profile_describer Profile describer Profile 自动描述
curator Curator 技能使用情况的复盘审视

另有 goal_judge(/goal 判定)、monitor(重要邮件打分)、background_review(回合后的自我改进分支)以及 MoA 的 moa_reference / moa_aggregator 两个槽位。它们默认继承你的主模型,所以你很可能一直是“一个模型扛下所有”,从未察觉这条链路的存在——直到它出问题。

配置结构:一个键决定它跑在哪个模型上

每个任务的配置块形状是一样的:

auxiliary:
  # 全局旋钮
  transient_retries: 2          # 同 provider 内的瞬时重试(超时/5xx/408),clamp 0..6
  free_only: false              # true = 后台流量绝不走付费的 OpenRouter 通道
  openrouter_model: ""          # 覆盖自动链上的 OpenRouter 模型
  stream_only_base_urls: []     # 只接受流式请求的端点(HTTP 400 那类)

  # 每个任务一个块,形状相同
  title_generation:
    enabled: true               # 关掉就完全不起标题
    model_upgrade_enabled: true # false = 永远保留即时推导出的标题,不调模型
    provider: auto              # auto = 继承主模型
    model: ""                   # 留空 = 跟随 provider
    prefer_fast_model: false    # true = 用 provider 的快速档
    language: ""                # 标题用哪种语言
    timeout: 30
  approval:
    provider: auto
    model: ""                   # 建议指一个又快又便宜的模型
    timeout: 30
  curator:
    timeout: 600                # 技能审视在推理模型上可能要跑几分钟

三个容易踩的点:

  • provider: auto 是“继承主模型”的写法,不是一个真实 provider 名。要钉死某个便宜模型,就同时写 provider 和 model。
  • 超时值不是随便填的:审批分类默认 30 秒(要快),kanban_decomposer 180 秒、curator 600 秒(要够)。给本地模型配压缩时,120 秒往往不够——这正是“本地模型压缩慢”最常见的抱怨来源。
  • background_review 有个额外的 max_input_tokens: 600000,用来给自我复盘重放的输入总量封顶;如果你把复盘路由到别的模型上,它改走“紧凑摘要”而不是完整对话重放,大概便宜 3~5 倍。

改配置最省事的入口是模型菜单底部那一项:

hermes model          # 菜单里选 “Configure auxiliary models...”
hermes config get auxiliary.title_generation   # 看当前生效的值

插件也能注册自己的辅助任务,注册完会出现在同一个菜单里。配置前先 hermes config get <键> 看一眼——这些键仍在变动:本机上 v0.21.0 的 CLI 输出里,title_generation 还没有 model_upgrade_enabled 这一项,而 main 上已经有了。

9 月 17 日的一批修复:静默失败的十种长相

2026 年 9 月 17 日,仓库里合并了一整组针对这条链路的修复。它们的共同点是:失败不会弹错误,只会让你看到奇怪的症状。

你看到的现象 真正的原因 PR
标题偶尔是一段 JSON 碎片 标题生成把 reasoning_content 当正文,或存了被截断的 JSON #113960
标题一直生成不出来,重试不停 参数被一层层拒绝后没有恢复路径 #113958
关掉模型升级后标题反而变空 应保留“即时推导”的标题,却被模型调用覆盖 #113955
某个端点挂掉导致后台卡很久 自动标题该在一个超时窗口后放弃,并指明是哪个 endpoint 超时 #113968
主模型配额用尽后整个后台链停摆 fallback_providers 走查没有跳过配额受限的候选 #113965
DeepSeek 上结构化输出报 400,随后 fallback 全废 400 不该杀掉 fallback 候选,也不该先付出一次注定失败的请求 #113966
xAI 的 OAuth 令牌过期后后台全挂 辅助调用应自动恢复,而不是直接失败 #113964
自定义 provider 报静默 401 key_cmd 是个可调用对象,在五个解析分支里被 .strip() 或把 repr 当 bearer token 发了出去 #114333
ollama 的本地 base_url 不生效 该分支没有解析本地地址、也没真的调到本地服务 #113961
/goal 判定失败,只给一句含糊的 judge error 应该直接指出是 Nous 认证失败 #113963

举个最有代表性的例子:自定义 provider 用 key_cmd 从密钥管理工具里动态取令牌(这是令牌会过期的场景下唯一正确的做法)。主链路一直把返回的可调用对象原样传下去,而辅助链路的五个分支假设“凭证一定是个字符串”,于是要么崩溃,要么把 <CommandTokenSource object at 0x…> 这个对象地址当成 bearer token 发给服务端——后者更糟,因为它不报错,只是安静地 401。

为什么这类 bug 特别难查

因为它们走的是“辅助”路径,设计上就允许降级:标题生成失败不该影响你聊天,审批分类超时应该放行或升级,压缩失败要有兜底。降级是正确设计,代价是失败被吞掉。你看到的是症状——标题奇怪、审批不智能、压缩慢——而不是一条错误信息。

所以有一条很实用的建议:给每个辅助任务单独钉一个又快又便宜的模型(尤其 approval 和 title_generation)。这样你换主模型、把主模型降级、或者主模型临时不可用时,这些后台行为保持稳定,排错时也能一眼分辨“是我的主模型变了,还是后台链路换了”。

版本状态

上面这些修复都是 2026 年 9 月 17 日合并进 main 的,目前最新的正式发布 v0.21.3(tag v2026.9.14,9 月 14 日)不包含它们。先看看你的版本:

hermes --version
hermes config get auxiliary.title_generation

如果你正在被其中某一条折磨(尤其是标题碎片和自定义 provider 的静默 401),hermes update 之后等下一个 tag 落地,或者先在本地跟 main 走。

延伸阅读:想让辅助调用少烧钱,先看推理强度(reasoning effort)怎么配;压缩频繁触发也是同类问题,见压缩与精简尾部;本地模型做辅助任务时的超时与端口细节在本地 llama.cpp 指南里;而新 provider 接入讲的是把 aux 任务挂到新供应商上时要注意的事。

小结

  • Hermes 有一条后台调用链(auxiliary),包含 13 个内置任务加 MoA/复盘等槽位,默认全部继承主模型。
  • 每个任务一个同形状的配置块:provider / model / base_url / api_key / timeout / extra_body / reasoning_effort;provider: auto 就是“跟随主模型”。
  • 想省钱又稳定:给 approval、title_generation 这类高频小任务钉便宜模型;给本地模型的 compression 调高 timeout。
  • 9 月 17 日合并的一批修复解决了十种“静默失败”(标题碎片、配额 fallback 卡住、自定义 provider 静默 401 等),尚未进入任何正式发布。