Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


同时运行多个网关

你可以在同一台机器上将多个配置文件作为托管服务来运行——每个配置文件都拥有独立的机器人令牌、会话及内存。本页面将介绍相关操作注意事项:如何同时启动所有配置文件、查看跨配置文件的日志、防止主机进入睡眠状态,以及如何解决launchd/systemd系统常见的异常问题。

如果你仅运行一个Hermes代理,则无需阅读本页面——基础内容可参考配置文件。如果你的实例分布在不同的机器上,而某个桌面应用需要同时与这些实例建立连接,请参阅将桌面应用连接到多个Hermes实例。

何时使用此方法

当你需要同时让两个或更多Hermes代理保持在线状态时,可采用此设置。常见应用场景包括:

  • 在一个Telegram机器人上使用个人助手功能,在另一个机器人上使用编程辅助功能
  • 每位家庭成员或每个Slack工作区对应一个代理
  • 配置相同的测试环境实例与生产环境实例
  • 研究辅助代理、写作辅助代理以及定时任务驱动的机器人——它们各自拥有独立的内存和技能

每个配置文件本身就已拥有对应的平台专用LaunchAgent(ai.hermes.gateway-<name>.plist)或systemd用户服务(hermes-gateway-<name>.service)。本指南旨在提供集中管理这些服务的通用方法。

快速入门

# Create profiles (once)
hermes profile create coder
hermes profile create personal-bot
hermes profile create research

# Configure each
coder setup
personal-bot setup
research setup

# Install each gateway as a managed service
coder gateway install
personal-bot gateway install
research gateway install

# Start them all
coder gateway start
personal-bot gateway start
research gateway start

就这样——三个独立的代理,每个都在独立的进程中运行,一旦崩溃或用户登录时会自动重启。

备选方案:为所有配置文件使用一个网关(多路复用)

上述方式是为每个配置文件运行一个进程。这是默认设置,也适用于大多数场景。但在拥有大量配置文件的服务器上——或者是在按配置文件单独运行进程会带来较高运营成本的容器部署环境中——你可以选择运行一个单一的多路复用网关:默认配置文件的网关将成为唯一的入口进程,负责处理该系统中所有配置文件的消息。

此功能为可选启用,默认处于关闭状态。当它处于关闭状态时,本页面的内容不会发生任何变化——以下的所有功能都将处于无效状态。

何时选择多路复用模式

  • 在容器/VPS部署环境中,N个监控单元、N个端口以及N个PID文件会带来沉重负担。
  • 存在许多流量较低的配置文件,且每个文件都不值得单独运行一个完整进程。
  • 你希望由单个组件来负责启动、监控及重启所有配置文件。

如果你需要实现配置文件之间的严格进程级隔离(如独立的内存占用、独立的崩溃域,以及能够重启某个配置文件而不影响其他配置文件),则应继续使用“每个配置文件一个进程”的模式。

如何启用该功能

在默认配置文件上设置相关标志(该配置文件负责管理多路复用器),然后重启其网关即可:

hermes config set gateway.multiplex_profiles true
hermes gateway restart

或者,在默认配置文件的 ~/.hermes/config.yaml 中也可实现:

gateway:
  multiplex_profiles: true

(为方便起见,该标志也可作为顶层参数 multiplex_profiles: true 使用。)在下次启动时,默认网关会枚举所有配置文件,使用每个配置文件自身的凭据来加载该文件下启用的平台,并将每条传入的消息路由到其所属的配置文件。每次处理都会加载该路由目标配置文件的配置、技能、内存、SOUL以及提供商密钥——各配置文件之间的凭据绝不会被共享。

对于这些辅助配置文件,您无需手动运行 hermes gateway start 命令——默认网关会负责为它们提供服务。具体变更内容请参见下方说明。

启用多路复用功能后会发生哪些变化?

启用该标志会改变部分功能的运作方式。一旦关闭该标志,所有这些变化都会恢复原状。

1. 辅助配置文件不得自行启动网关

在多路复用器运行期间,尝试对特定配置文件执行 hermes gateway start / run 命令将导致严重错误,系统会提示您转而使用多路复用器。

The default gateway is running as a profile multiplexer and already serves
profile 'coder'. ...

多路复用器是一个独立的入口进程;若再创建第二个配置文件网关,将会使该配置文件对应的所有平台陷入双重绑定状态。仅当您确实需要为该配置文件单独设置一个进程时才使用 --force 参数(在多路复用器正在运行期间不建议这样做)。因此,在多路复用模式下不会使用本页前面提到的跨配置文件生命周期封装脚本——您只需管理默认网关即可。

2. HTTP 入站平台通过 /p/<profile>/ 的 URL 前缀访问

次要配置文件的 Webhook(及其他 HTTP 入站)流量会通过配置文件前缀发送到默认监听器,而非使用第二个端口。

# default profile
POST http://host:8644/webhooks/<route>
# the "coder" profile, same listener
POST http://host:8644/p/coder/webhooks/<route>

前缀中存在未知或未配置的配置文件时,系统会返回 404 错误。由于共享的监听器已以此方式为所有配置文件提供服务,辅助配置文件本身不得启用端口绑定功能——若这样做会导致配置错误,从而使整个辅助配置文件被跳过,而默认配置文件及其他正常运行的配置文件仍可继续工作。该警告会明确指出被跳过的配置文件以及所有存在冲突的端口绑定平台。

Skipping secondary profile 'coder' due to port-binding config error: Profile
'coder' enables port-binding platform(s) webhook, but gateway.multiplex_profiles
is on. ... Remove these platform entries from profile 'coder's config.yaml or
configure them only on the default profile.

本规则所覆盖的端口绑定平台包括:webhook、api_server、msgraph_webhook、feishu、wecom_callback、bluebubbles、sms、whatsapp_cloud、line、teams。这些平台的配置仅可在默认配置文件中进行;每个配置文件均可通过其 /p/<profile>/ 前缀访问。

身份验证将依据 URL 中指定的配置文件来进行。未添加前缀的端点将继续使用默认监听器的现有凭证。

  • 以 /p/coder/... 格式发起的 API-server 请求必须使用 ~/.hermes/profiles/coder/.env 文件中的 API_SERVER_KEY;默认监听器的密钥将被拒绝。
  • 针对 coder 的 webhook 路由,必须在默认配置文件的 config.yaml 中,在原有的路由专用 secret 之外再声明 profile: coder。该密钥仅能在 /p/coder/webhooks/<route> 地址下被识别,而在其他任何配置文件前缀下都会被拒绝。
  • 未指定 profile 的 webhook 路由仍属于默认配置文件下的路由,无法通过特定的配置文件前缀访问。

请在次要配置文件中保持端口绑定平台处于禁用状态。共享监听器及其路由定义仍保留在默认配置文件中;配置文件绑定功能则用于控制每个已通过身份验证的 webhook 路由应运行于哪个配置文件下。如果目标配置文件中不存在 API_SERVER_KEY,对应的命名 API 请求将会直接被拒绝。

只有共享监听器冲突会导致配置文件被跳过,而安全配置错误依然会引发严重后果:例如,若在未设置 GATEWAY_ALLOW_ALL_USERS 或相应的平台特定全允许选项的情况下启用“开放”型自定义策略,系统仍会立即终止网关启动,而不会默默忽略该不安全的配置文件。

3. 每个凭据对应的平台仍需为每个配置文件单独配置令牌

轮询/连接型平台(如 Telegram、Discord、Slack、Matrix、Signal 等)支持多路复用运行,但每个启用此类功能的配置文件都必须提供独立的机器人令牌——同一个令牌无法被两个配置文件同时使用。如果两个配置文件使用了相同的 (平台, 令牌) 组合,系统会在启动时立即报错并指出这两个配置文件(详见令牌冲突处理机制——规则本身并未改变,只是现在在同一进程内进行管控)。

4. 会话键以配置文件为单位进行命名空间隔离

每个配置文件的会话都存储在 agent:<profile>:… 这样的命名空间下,因此同一平台/聊天窗口中的两个配置文件的会话不会在共享的会话存储中发生冲突。默认配置文件会原封不动地保留原有的 agent:main:… 命名空间,因此现有基于默认配置文件的会话不会受到影响——无需进行迁移,也不会留下孤立的旧会话记录。

5. 单一进程标识/锁机制及统一状态展示界面

整个系统仅存在一个进程级的 PID 与锁机制(即位于默认配置目录下的多路复用器)。hermes status 命令会显示该多路复用器及其所服务的配置文件;而 hermes status -p <name> 则可查看指定的单个配置文件。尽管如此,每个配置文件仍会在自身的配置目录下生成独立的 runtime_status.json 文件,因此原有的针对单个配置文件的读取工具依然可以正常使用。

保持不变的部分

针对每个配置文件的 .env 文件中的凭证隔离机制依然有效,甚至更为严格:每个配置文件中的键值只会在其自身作用域内解析,绝不会被合并到共享环境中(这也意味着 MCP 服务器和 Kanban 工作进程之类的子进程只能访问其所在配置文件中的机密信息)。终端相关设置(如 terminal.backend、terminal.cwd、terminal.docker_volumes、terminal.docker_shared_container_key、SSH 连接目标等)同样会在每次请求处理时根据对应配置文件进行解析:若某个配置文件未指定某项终端设置,则会使用文档中规定的默认值,而绝不会采用启动配置文件的值;此外,如果某个配置文件的 config.yaml/.env 文件无法被解析,系统会拒绝其终端执行,而不会强制其在其他配置文件的沙箱策略下运行。Kanban 功能、基于配置文件的技能/内存/SOUL 管理以及模型路由功能,其行为方式都与使用独立网关时完全一致。

提供选定的配置文件服务

默认情况下,gateway.multiplex_profiles: true 会为主机上所有有效的命名配置文件提供服务。若希望安装不相关的配置文件而不必启动其对应的适配器或定时任务,可设置 gateway.multiplex_profile_allowlist 参数来实现该需求:

gateway:
  multiplex_profiles: true
  multiplex_profile_allowlist:
    - worker
    - guest

默认配置文件始终会被提供,无需单独列出。若未设置允许列表,则会保持原有的“全部提供”行为;而空列表则仅提供默认配置文件。所有配置名称都会经过标准化处理并去重。对于无效的列表项或未安装的配置名称,系统会发出警告并跳过处理。若输入的是格式错误的非列表值,系统则会安全地切换为仅提供默认配置文件的模式。

最终确定的提供配置集还会影响 /p/<profile>/ API及Webhook前缀、运行时状态、配置文件路由的适用性,以及进程内定时调度器会轮询哪些配置文件。即使不在允许列表中的命名配置文件,仍可运行其独立的网关。

将共享机器人的聊天消息路由至不同配置文件(profile_routes)

多路复用机制可根据凭证(即每个配置文件对应的独立机器人令牌)或URL前缀(HTTP平台中使用 /p/<profile>/)来选择相应的配置文件。当多个社区共享同一个机器人令牌时——例如一个Discord机器人为多个群组提供服务——可通过 gateway.profile_routes 将特定的群组/频道/帖子路由至不同的配置文件。

gateway:
  multiplex_profiles: true
  profile_routes:
    # An entire Discord server → one profile
    - name: acme-server
      platform: discord
      guild_id: "1234567890"
      profile: acme

    # One channel in that server → a different profile
    - name: acme-support
      platform: discord
      guild_id: "1234567890"
      chat_id: "9876543210"
      profile: acme-support

    # A Telegram group (no guild concept — chat_id only)
    - name: tg-group
      platform: telegram
      chat_id: "-1001234567890"
      profile: tg-profile

    # A WhatsApp DM — write the phone number; JID and LID forms also match
    - name: owner-whatsapp
      platform: whatsapp
      chat_id: "15551234567"
      profile: owner

路由匹配遵循最具体优先的原则(thread_id > chat_id > guild_id),所有声明的字段都必须同时满足条件。以频道为键的路由还会匹配那些父频道相同的主题帖或论坛帖子。无法匹配到任何路由的消息将留在默认/活动配置文件中。而经过路由分配的配置文件则能享有上文所述的完全独立性(包括配置、技能、内存、凭证及会话命名空间)。此路由功能适用于所有平台适配器,而不仅限于 Discord。

在 WhatsApp 和 WhatsApp Cloud 中,chat_id 路由可跨不同用户身份形式进行匹配:一旦桥接组件完成了关联,纯电话号码(15551234567)、JID(15551234567@s.whatsapp.net)以及 LID(…@lid)都指向同一个人(因为它们使用的是相同的规范化会话密钥和适配器允许列表)。您可以将电话号码放入 profile_routes 中,这样无论 WhatsApp 传递的是 JID 还是 LID,进来的私信依然能够匹配。在尚未建立 LID 映射关系时,电话号码形式仍可匹配 JID(此时会去掉后缀),但无法解析未知的 LID——这类消息将会流转到默认配置文件,直到映射关系建立为止。群聊地址(…@g.us)虽不属于发送者身份标识,但仍能实现精确匹配。Telegram 的数字 ID 则保持不变。

profile_routes 功能需要开启 gateway.multiplex_profiles: true;若关闭该功能,则这些路由将被忽略。如果存在匹配的显式路由,但其目标配置文件未安装或不在 multiplex_profile_allowlist 列表中,网关将会拒绝该接入请求,并记录下该路由及其目标信息。此时不会使用默认配置文件。对于没有匹配到任何路由的流量,则会沿用原有的默认配置文件处理方式。

由路由配置文件管理的定时任务也会通过共享机器人发送,但仅限于那些目标为已启用路由且其 chat_id/thread_id 与对应配置文件相匹配的聊天窗口——路由配置文件管理的任务若针对未设置路由的聊天窗口(或被路由到其他配置文件的聊天窗口),则绝不会通过共享机器人发送。仅限群组使用的路由无法作为定时任务的发送目标;需为该发送渠道添加对应的 chat_id 路由。

同时启动、停止或重启所有网关

CLI 工具提供了针对单配置文件的生命周期管理命令。若需对所有配置文件执行相应操作,可将其包裹在 Shell 循环中。请将以下代码片段保存到 ~/.local/bin/hermes-gateways 文件中,并为其添加执行权限 chmod +x:

#!/bin/sh
set -eu

# Add or remove profile names here as you create / delete profiles.
profiles="default coder personal-bot research"

usage() {
  echo "Usage: hermes-gateways {start|stop|restart|status|list}"
}

run_for_profile() {
  profile="$1"
  action="$2"
  if [ "$profile" = "default" ]; then
    hermes gateway "$action"
  else
    hermes -p "$profile" gateway "$action"
  fi
}

action="${1:-}"
case "$action" in
  start|stop|restart|status)
    for profile in $profiles; do
      echo "==> $action $profile"
      run_for_profile "$profile" "$action"
    done
    ;;
  list)
    hermes gateway list
    ;;
  *)
    usage
    exit 2
    ;;
esac

接着:

hermes-gateways start      # start every configured profile
hermes-gateways stop       # stop every configured profile
hermes-gateways restart    # restart all
hermes-gateways status     # status across all
hermes-gateways list       # delegates to `hermes gateway list`
:::提示 使用 hermes gateway <action>(不带 -p 参数)即可调用 default 配置文件,而非 hermes -p default gateway <action>。上述封装脚本可兼容这两种调用方式。
::

管理单个配置文件

每个配置文件都会自动安装的快捷命令:

coder gateway run        # foreground (Ctrl-C to stop)
coder gateway start      # start the managed service
coder gateway stop       # stop the managed service
coder gateway restart    # restart
coder gateway status     # status
coder gateway install    # create the LaunchAgent / systemd unit
coder gateway uninstall  # remove the service file

这些命令等同于 hermes -p coder gateway <action> —— 当配置文件别名不在 PATH 环境变量中,或需要通过脚本动态指定配置文件时,使用这些命令会非常方便。

服务文件

每个配置文件都会安装一个具有唯一名称的服务,因此不同配置文件的安装不会发生冲突:

平台路径
macOS~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist
Linux~/.config/systemd/user/hermes-gateway-<profile>.service

默认配置文件会沿用旧有的名称:ai.hermes.gateway.plist / hermes-gateway.service。

查看日志

每个配置文件都会将自己的日志写入独立的日志文件中:

# Default profile
tail -f ~/.hermes/logs/gateway.log
tail -f ~/.hermes/logs/gateway.error.log

# Named profile
tail -f ~/.hermes/profiles/<name>/logs/gateway.log
tail -f ~/.hermes/profiles/<name>/logs/gateway.error.log

同时流式传输每个配置文件的日志:

tail -f ~/.hermes/logs/gateway.log ~/.hermes/profiles/*/logs/gateway.log

该命令行工具还配备了结构化的日志查看器:

hermes logs -f                  # follow default profile
hermes -p coder logs -f         # follow one profile
hermes logs --help              # filters, levels, JSON output

查明实际正在运行的进程

hermes profile list             # profiles + model + gateway state
hermes-gateways status          # full status across every profile
launchctl list | grep hermes    # macOS — PIDs and labels
systemctl --user list-units 'hermes-gateway-*'   # Linux — units

配置编辑

每个配置文件都会将其配置保存在独立的目录中:

~/.hermes/profiles/<name>/
├── .env              # API keys, bot tokens (chmod 600)
├── config.yaml       # model, provider, toolsets, gateway settings
└── SOUL.md           # personality / system prompt

默认配置文件直接使用~/.hermes/目录下的这三份文件。

您可以使用任何编辑器或通过CLI来修改这些文件:

hermes config set model.model anthropic/claude-sonnet-4    # default profile
coder config set model.model openai/gpt-5                  # named profile

编辑完 .env 或 config.yaml 文件后,请重启受影响的网关:

coder gateway restart
# or, for everything:
hermes-gateways restart

保持主机处于唤醒状态

网关进程可以全天运行,但操作系统在空闲时仍会尝试进入睡眠状态。为此有两种解决方案:

macOS — caffeinate 命令

caffeinate 是 macOS 内置的功能,可在其运行期间阻止系统进入睡眠状态,无需额外安装。

caffeinate -dis                    # block display, idle, and system sleep
caffeinate -dis -t 28800           # same, auto-exit after 8 hours
caffeinate -i -w $(cat ~/.hermes/gateway.pid) &   # awake while default gateway runs

# Persistent: run in background and forget
nohup caffeinate -dis >/dev/null 2>&1 &
disown

# Inspect / stop
pmset -g assertions | grep -iE 'caffeinate|prevent|user is active'
pkill caffeinate
标志效果
-d禁止显示器进入睡眠状态
-i禁止系统空闲时进入睡眠状态(默认值)
-m禁止磁盘进入睡眠状态
-s禁止系统进入睡眠状态(仅适用于交流供电的 Mac)
-u模拟用户操作活动(防止屏幕锁屏)
-t N运行 N 秒后自动退出
-w P当 PID 为 P 的进程退出时立即退出
:::warning 合上屏幕仍会导致 Mac 进入睡眠状态 caffeinate 工具无法强制覆盖 MacBook 上由硬件控制的合盖睡眠功能。 如需在合上屏幕时保持设备唤醒,需调整“节能设置”/“电池设置”,或使用第三方工具。
::

Linux — systemd-inhibit 或 loginctl

# Inhibit suspend while a command runs
systemd-inhibit --what=idle:sleep --who=hermes --why="gateways running" \
  sleep infinity &

# Allow user services to keep running after logout (recommended)
sudo loginctl enable-linger "$USER"

启用“持久运行”功能后,您的 systemd 用户单元(包括 hermes-gateway-<profile>.service)即便在 SSH 连接中断或系统重启的情况下仍会继续运行。

令牌冲突防护机制

每个配置文件必须为不同的平台使用唯一的机器人令牌。如果两个配置文件使用了相同的 Telegram、Discord、Slack、WhatsApp 或 Signal 令牌,第二个网关将拒绝启动,并会显示指出冲突配置文件的错误信息。

用于审计:

grep -H 'TELEGRAM_BOT_TOKEN\|DISCORD_BOT_TOKEN' \
     ~/.hermes/.env ~/.hermes/profiles/*/.env

更新代码

hermes update 会一次性获取最新代码,并将新打包的技能同步到每个配置文件中:

hermes update
hermes-gateways restart

用户自定义的技能永远不会被覆盖。

故障排除

“在域中找不到用户界面对应的服务:501 错误”

您在先执行了 hermes gateway stop 后又运行了 hermes gateway start。CLI 的 stop 命令会执行完整的 launchctl unload 操作,从而将该服务从 launchd 的注册表中移除。CLI 在执行 start 命令时会检测到这一特定错误,并自动重新加载 plist 文件(提示:↻ launchd 任务已被卸载;正在重新加载服务定义)。这样服务就能正常启动,无需进行任何修复。

程序崩溃后的无效 PID

如果某个配置文件的网关显示为“未运行”,但实际上仍有进程在运行:

ps -ef | grep "hermes_cli.*-p <profile>"
cat ~/.hermes/profiles/<profile>/gateway.pid
kill -TERM <pid>          # graceful
kill -KILL <pid>          # if that fails after a few seconds
<profile> gateway start

强制对某个服务进行硬重置

# macOS
launchctl unload ~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist
launchctl load   ~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist

# Linux
systemctl --user restart hermes-gateway-<profile>.service

健康检查

hermes doctor                  # default profile
hermes -p <profile> doctor     # one profile