群晖 NAS 上的 Hermes 部署实录

技术专业 · 昨天

昨天在vps将Hermes走通,今天使用了一下,总体感觉比openclaw要好,信息比较简洁,配置文件也很清晰。
考虑将其作为我的内网的服务,希望逐步将其作为投资平台、家庭日记等核心内容与外部交互的AI能力通道,因此决定将 Hermes 从 VPS 迁移到了群晖 NAS上,顺便把模型路由策略彻底重新设计了一遍。

记录一下整个过程,包括踩过的坑。


为什么迁移到 NAS

迁移到 NAS 之后,Hermes 通过docker仍然限定在我的家庭网络中,但是可以通过逐步的授权逐渐接触我的家庭日志、投资记录等信息,成为对内的AI能力中枢。
最终形成,外呼信息抓取以openclaw为主的vps架构,内容信息及投资关联通过内部的docker上的hermes,这样架构更清晰,VPS 上的 Hermes 直接停掉并禁用。


部署过程

DS218plus 上用 Docker Compose 部署,配置非常简洁:

yaml

version: "3.8"
services:
  hermes:
    image: nousresearch/hermes-agent:latest
    container_name: hermes-agent
    restart: unless-stopped
    volumes:
      - .:/opt/data
    ports:
      - "8642:8642"
    command: gateway run
    environment:
      - API_SERVER_ENABLED=true
      - API_SERVER_KEY=sk-w-xxxx

挂载当前目录到 /opt/data,所有配置文件、日志、memory 都持久化在 /volume1/docker/hermes/ 下,重建容器不会丢失数据。

部署完成后在 Telegram 发一条消息验证连通性,返回正常即部署成功。


默认模型配置

Hermes 通过 我前面建立的LiteLLM 网关访问所有模型,配置指向统一入口,核心一个还是以最低的token支出成本:

yaml

model:
  default: gemini-flash
  provider: custom
  base_url: https://ai.xxx.com/v1
  api_key: sk-w-xxxx

选 Gemini Flash 作为默认主力,原因是速度快、支持多模态(可以发图片分析),而且 Google 免费额度充足。


尝试短消息智能分流

配置好主模型之后,想进一步优化成本——短消息没必要调用主模型,用便宜的模型就够了。Hermes 提供了 smart_model_routing 功能,理论上可以按消息长度自动路由:

yaml

smart_model_routing:
  enabled: true
  max_simple_chars: 160
  max_simple_words: 28
  cheap_model:
    provider: custom
    model: minimax
    base_url: https://ai.xxx.com/v1
    api_key: sk-w-xxxx

设计意图是:短于 160 字符的消息走 MiniMax,长消息走 Gemini Flash。


分流失败的原因

实际测试发现分流效果不理想。

发"今天是星期日"这样的中文短句,返回的仍然是 Gemini Flash。发"hi"这样的英文极短消息,才真正触发了 MiniMax。查看日志后发现:

inbound message: msg='hi'
Auxiliary auto-detect: using main provider custom (minimax)

"hi"确实走了 MiniMax,但中文短句没有。

原因有两个:第一,Hermes 对中文字符的计数方式可能按字节而非字符,一个汉字占 3 字节,导致中文短句实际"字符数"远超阈值;第二,涉及 memory 上下文的对话(比如问候语),Hermes 会判断为需要个性化回复的复杂任务,直接走主模型。

调低阈值到 50 字符后中文短句仍然走主模型,说明触发条件不只是字符数,还有语义判断。


放弃分流,转向 Fallback 体系

既然 smart routing 对中文场景基本无效,而且强制路由到便宜模型可能影响回复质量,最终决定放弃分流,改为建立完整的 fallback 链路。

思路转变为:不主动降级,而是在主模型失败时自动切换。

最终 Hermes 的 fallback 配置:

yaml

model:
  default: gemini-flash
  provider: custom
  base_url: https://ai.xxx.com/v1
  api_key: sk-walker2026-xxxx

fallback_providers:
  - provider: custom
    model: minimax
    base_url: https://ai.xxx.com/v1
    api_key: sk-walker2026-xxxx
  - provider: custom
    model: deepseek
    base_url: https://ai.xxx.com/v1
    api_key: sk-walker2026-xxxx
  - provider: custom
    model: llama-3.3
    base_url: https://ai.xxx.com/v1
    api_key: sk-walker2026-xxxx
  - provider: custom
    model: openrouter-free
    base_url: https://ai.xxx.com/v1
    api_key: sk-walker2026-xxxx

完整的模型链路:

普通消息  → gemini-flash(主力)
失败时    → minimax → deepseek → llama-3.3 → openrouter-free
顶级任务  → 手动指定 sonnet

配置中遇到的一个隐藏问题

config.yaml 里出现了两个 smart_model_routing——顶部是手动添加的(enabled: true),中间是模板默认的(enabled: false)。YAML 解析时后面的覆盖了前面的,导致 smart routing 实际处于关闭状态,排查了很久才发现。

教训:修改 Hermes 配置时要检查整个文件是否有重复的顶级 key。


最终状态

NAS 上的 Hermes 稳定运行,VPS 上的实例已停止并禁用开机自启。模型体系以 Gemini Flash 为主力,多层 fallback 保证稳定性,Sonnet 4.6 作为顶级推理的按需选项。

日常使用基本零成本,只有调用 Sonnet 时才产生少量费用。整套系统的维护入口统一在 NAS 的 /volume1/docker/hermes/ 目录下,管理方便。

Theme Jasmine by Kent Liao