Hermes Agent 实战 14|跨 Profile 消息路由与自托管服务巡检:两个被忽略的边界原创
# 跨 Profile 消息路由与自托管服务巡检:两个被忽略的边界
系列第 14 篇。这篇从两个真实的日常操作切入:一是让
superdbaProfile 给<INTERNAL_BRAND>发消息时踩到的「Bot vs Profile」概念坑;二是对 RSSHub 和 wg-easy 做健康巡检时遇到的「429 误报」和「流量统计误解」。两个问题看似不相关,但核心都是边界认知偏差——对架构分层理解不清,导致排查路径错误。
# 1. 事件一:跨 Profile 发消息的「身份 confusion」
# 1.1 场景与操作
我想让 superdba Profile(一个专注 DBA 场景的 Hermes Profile)给同事 <USER> 发一条 Telegram 测试消息,验证跨 Profile 的消息路由是否通畅。
第一步:定位目标。通过检索 supermemory_search 和配置文件读取,定位到 channel_directory.json,提取出目标用户的 Telegram chat_id(已脱敏处理)。
第二步:确认身份状态。检查 gateway_state.json,确认 superdba 的 Telegram 网关状态为 connected。
第三步:发送。执行:
hermes send -t telegram:CHAT_ID_PLACEHOLDER
消息成功送达。但过程中我踩了一个概念坑。
# 1.2 踩坑:Bot vs Profile,我混淆了分层
症状:我最初以为需要找一个叫 <INTERNAL_BRAND> 的独立实体,甚至去翻有没有独立的 bot 配置。
原因:对 Hermes 的架构分层理解偏差。在 Hermes 中,Profile 本身就是身份的载体——superdba 这个 Profile 已经在其配置中绑定了 Telegram Bot Token,它就是那个 Bot。不存在一个独立的、与 Profile 平行的「Bot 对象」。
解药:
Profile = 身份 + 配置 + 网关的集合体。当你听到某个 Profile 名时,就应该意识到它已经包含了该身份的所有通信能力。
这种混淆在 multi-tenant 架构里很常见:用户习惯了「账号 → 多个 Bot」的模型,但 Hermes 是「Profile → 自带所有配置」的一体式设计。
# 1.3 另一个坑:Gateway vs Skill 的边界
这次我只用了 hermes send 这条 CLI 命令,它走的是 Gateway 层(系统级消息路由)。但 superdba 其实还有一个专属的 Skill(<SKILL_NAME>),用于格式化 DBA 日报、处理群组广播等业务逻辑。
两者的区别:
| 层级 | 用途 | 调用方式 | 特点 |
|---|---|---|---|
| Gateway | 系统通知、私聊测试、基础路由 | hermes send | 简单、直接、无业务逻辑 |
| Skill | 业务报告、格式化输出、群组管理 | skill_invoke / prompt 调用 | 可复用、带模板、可组合 |
可复用要点:
普通私聊测试用 Gateway;正式业务通知(如 DBA 日报、告警广播)必须调用专属 Skill。不要把「能发消息」当成「正确地发了消息」。
# 2. 事件二:RSSHub 与 wg-easy 的健康巡检
# 2.1 场景
对自托管的 RSSHub(RSS 聚合服务)和 wg-easy(WireGuard 管理面板)进行定期健康巡检,排查潜在问题。
# 2.2 RSSHub 巡检实战
容器状态:rsshup 和 rsshup-browserless 均处于 Up 24h (healthy)。
核心指标验证:
# 健康端点检查
curl -s -o /dev/null -w "%{http_code}" http://localhost:1200/health
# 预期输出: 200
# Redis 缓存状态
redis-cli info keyspace
dbsize
# 预期输出: db0:keys=262,expires=262,avg_ttl=8280000 (约 2.3 小时)
2
3
4
5
6
7
8
性能测试:
time curl -s http://localhost:1200/cryptoslate > /dev/null
# 预期输出: 0.05s - 0.1s (缓存命中)
2
日志分析:观察到 JavBus 路由出现 429 Rate Limit 警告:
[2026-06-26T08:31:42] WARN: JavBus route returned 429, retrying (1/3)...
[2026-06-26T08:31:45] INFO: Retry successful, returning 200
2
这是一个典型的**「警告≠故障」**场景。RSSHub 内置了自动重试机制,429 触发重试后最终返回 200,用户侧无感知失败。
# 2.2 wg-easy 巡检实战
服务状态:容器运行 4 周,内存占用 32.71 MB,UDP 51820 端口正常。
客户端监控:列出所有客户端状态:
docker exec wg-easy wg show
# 预期输出(示例):
# peer: xxx...
# endpoint: x.x.x.x:port
# allowed ips: 10.x.x.x/32
# latest handshake: 1 minute, 36 seconds ago
# transfer: 12.45 MiB received, 244.32 GiB sent
2
3
4
5
6
7
这里遇到了两个认知坑。
# 2.3 踩坑:429 误报恐慌 & 流量统计误解
坑 1:429 警告引发的不必要恐慌
症状:日志中出现 429 Rate Limit,第一反应是「服务出问题了」。
原因:目标源(JavBus)触发了频率限制,但 RSSHub 的重试机制已覆盖此场景。
解药:
健康检查不能只看「有没有警告」,要看「最终是否成功」以及「缓存是否生效」。
坑 2:244GB 流量被误以为近期突发
症状:看到某个客户端 transfer: 244.32 GiB sent,以为是短时间内的大量上传。
原因:wg-easy 默认显示的是客户端创建以来的累计流量,不是实时速率,也不是近期统计。
解药:
WireGuard 统计口径 = 累计值(持久化到接口重启)。如需监控实时速率,需自行计算差分(如 Prometheus + node_exporter),或定期清零(重建客户端或重启 WG 接口)。
坑 3:握手延迟 ≠ 离线
症状:某客户端显示 latest handshake: 1 minute, 36 seconds ago,担心它已离线。
原因:WireGuard 协议的 Keepalive 间隔较长,3 分钟内无数据交互仍视为在线。
解药:
离线判定要结合「状态」字段和实际业务逻辑,不能仅看握手时间戳。
# 3. 可复用要点
# 3.1 Profile 与 Gateway 的分层心智模型
┌─────────────────────────────────────────┐
│ Skill 层 │ ← 业务逻辑、格式化、模板
│ (<INTERNAL_BRAND> Skill) │
├─────────────────────────────────────────┤
│ Gateway 层 │ ← 系统路由、基础消息
│ (hermes send, telegram) │
├─────────────────────────────────────────┤
│ Profile 层 │ ← 身份 + 配置 + Token
│ (superdba: token + gateway_state) │
└─────────────────────────────────────────┘
2
3
4
5
6
7
8
9
10
Profile 不是「使用 Bot」,Profile 就是 Bot。
# 3.2 自托管服务巡检清单
RSSHub 巡检维度:
- 容器状态(Up/Down/Healthy)
- 健康端点(HTTP 200)
- Redis 缓存:key 数量 + TTL 分布(理想:所有 key 带 TTL)
- 关键路由响应时间(<100ms 为优)
- 日志警告:429/500 等是否被重试机制覆盖
wg-easy 巡检维度:
- 容器资源占用(内存、CPU)
- 端口监听(UDP 51820)
- 客户端列表:在线/离线状态
- 握手时间(<3min 视为在线)
- 累计流量(识别异常高流量设备)
# 3.3 无人值守巡检的「沉默即异常」原则
如前一篇文章所述,任何无人值守任务都应发送心跳,即使一切正常:
✅ rsshup-health clean (24h uptime, 262 cached keys, p99 51ms)
⚠️ wg-easy: <DEVICE> accumulated 244GB traffic, review needed
2
让「群里没消息」本身成为可检测的异常信号。
# 4. Agent 可直接解析的元数据块
{
"_meta": {
"doc_version": "2026-06-27",
"article_id": "hermes-14-routing-inspection",
"profile_context": "any",
"estimated_setup_time": "20min"
},
"quick_start": {
"step_1": "检查 Profile 网关状态: cat ~/.hermes/profiles/<name>/gateway_state.json",
"step_2": "发送测试消息: hermes send -t telegram:<chat_id>",
"step_3": "RSSHub 健康检查: curl -s http://localhost:1200/health",
"step_4": "wg-easy 客户端状态: docker exec wg-easy wg show"
},
"safety_rules": [
"区分 Gateway 层(系统路由)与 Skill 层(业务逻辑),正式通知走 Skill",
"RSSHub 429 警告≠故障,需确认重试机制和缓存状态",
"wg-easy 流量统计为累计值,非实时速率",
"WireGuard 离线判定阈值为 3 分钟无握手"
],
"verification": {
"profile_connected": "cat ~/.hermes/profiles/<name>/gateway_state.json | grep connected",
"rsshub_healthy": "curl -s -o /dev/null -w '%{http_code}' http://localhost:1200/health",
"wg_clients": "docker exec wg-easy wg show | grep -c 'peer:'",
"redis_cache": "redis-cli dbsize"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
AI Agent 使用指南:
- 当用户说「让 X Profile 给某用户发消息」→ 执行
quick_start.step_1确认网关状态,然后quick_start.step_2(替换 chat_id) - 当用户说「巡检 RSSHub」→ 执行
quick_start.step_3+verification.rsshub_healthy,配合verification.redis_cache - 当用户说「检查 WireGuard 客户端」→ 执行
quick_start.step_4,注意对照safety_rules[2]和safety_rules[3]解释统计值
下一篇:实战旗舰:XX