Nanobot & Hermes Agent 升级全记录
日期: 2026-06-10 ~ 2026-06-13
作者: 雨轩
标签: 升级, nanobot, hermes, systemd, 运维
一、背景
1.1 系统现状
Nanobot 是广山哥的个人 AI 助手系统,运行在一台 Ubuntu R86S 小主机上。整个系统由多个服务组件构成:
| 组件 | 版本 | 用途 |
|---|---|---|
| nanobot-ai | 0.1.5 | 主框架(消息路由、渠道接入、Agent 调度) |
| Hermes Agent | v0.13.0 (2026.5.7) | 独立的 AI Agent 框架(对话、网关、ACP) |
| 自定义管理面板 | — | 广山哥自建的 Web 管理后台(端口 9100) |
| Weclaw | — | 另一个 AI 服务(独立仓库) |
除了软件包本身,还有一系列外围服务:
- nanobot-gateway — systemd 服务,消息路由主网关
- file-server — 文件浏览器(端口 5000)
- dingtalk-image-bridge — 钉钉图片桥接(端口 5002)
- wechat-image-bridge — 微信图片桥接(端口 5003)
- management-api — Nanobot 管理 API(端口 18800)
这些服务通过 restart_services.sh 统一管理,一个脚本依次停止、清理、重启全部服务。
1.2 升级动机
本次升级有两个主要驱动因素:
nanobot-ai 版本落后:当前运行的是 0.1.5,而 PyPI 上最新版本已经是 0.2.1,中间跨了 0.1.5.post1~post3、0.2.0 等多个大版本。新版本带来了 boto3 S3 集成、openpyxl Excel 处理、pypdf PDF 解析、python-pptx PowerPoint 支持等新能力。
Hermes Agent 版本落后:Hermes 虽然显示 "Up to date",但实际上广山哥维护的 fork 版本(v0.13.0)与上游 NousResearch 的最新版(v0.16.0)之间存在巨大差距。上游已发布多个新版本,包含大量架构重构和安全加固。
二、升级策略
2.1 核心原则
升级方案遵循三条原则:
- 先备份,再升级 — 任何修改前必须创建可回退的完整备份
- 可回退 — 如果升级后服务不可用,能在 5 分钟内恢复到升级前状态
- 分步验证 — 升级 nanobot → 升级 hermes → 重启服务,每一步都验证
2.2 风险识别
升级前识别的风险点:
| 风险 | 等级 | 缓解措施 |
|---|---|---|
| nanobot 0.1.5 → 0.2.1 API 不兼容 | 中 | .venv 全量备份,可 pip install 回退 |
| Hermes 用户 fork 与 upstream 分叉 | 高 | 完整 git 目录备份,记录 HEAD commit |
| 依赖冲突 | 中 | pip freeze 保存依赖快照 |
| 服务启停顺序错误 | 低 | 使用成熟的 restart_services.sh |
2.3 备份方案
备份采用三层策略:
- git commit — 代码版本控制,所有变更提交到本地 git 仓库并推送到 NAS
- pip freeze — 精确保存当前 Python 依赖版本列表
- 全量 tar — 虚拟环境和 hermes 目录打包到 NAS,确保能完整恢复运行环境
三、备份执行
3.1 Git 快照
# nanobot 主仓库
git -C /home/nanobot/.nanobot add -A
git -C /home/nanobot/.nanobot commit -m "backup: pre-upgrade snapshot"
当前 HEAD:db0a728b,远程仓库同时推送至 GitHub 和 NAS 本地仓库。
3.2 依赖快照
通过 pip freeze 将当前 165 个 Python 包的精确版本写入 config/requirements-backup-20260610.txt,包含 wxwatcher、anthropic、openai、litellm、mcp 等核心依赖。
3.3 虚拟环境全量备份
Nanobot 的 .venv 目录 595MB,通过 tar 压缩后 159MB:
tar -czf /mnt/nas/backups/nanobot-upgrade-20260610/nanobot-venv-20260610.tar.gz \
-C /home/nanobot/.nanobot .venv
3.4 Hermes 全量备份
Hermes Agent 的安装目录 /root/.hermes/hermes-agent/ 体积较大(1.8GB),包含完整的 Python 虚拟环境、Node 依赖、构建产物。压缩后 610MB:
tar -czf /mnt/nas/backups/nanobot-upgrade-20260610/hermes-agent-20260610.tar.gz \
-C /root/.hermes hermes-agent
同时记录当前 git HEAD 用于精确回退:
# hermes HEAD: a40e67712
# Message: fix(kanban/dashboard): fix aria-label for column select-all checkbox; add v2 dist bundle
备份后的 NAS 目录结构:
/mnt/nas/backups/nanobot-upgrade-20260610/
├── nanobot-venv-20260610.tar.gz (159M)
├── hermes-agent-20260610.tar.gz (610M)
└── hermes-pre-upgrade-commit.txt (HEAD 记录)
3.5 备份验证
每个备份文件创建后都验证了存在性和大小。pip freeze 确认 166 行(含注释头),tar 文件确认无报错退出。
四、Nanobot 升级
4.1 升级过程
Nanobot 的升级最简单直接——它是通过 PyPI 发布的纯 Python 包:
/home/nanobot/.nanobot/.venv/bin/pip install --upgrade nanobot-ai
4.2 版本变化
| 项目 | 升级前 | 升级后 |
|---|---|---|
| nanobot-ai | 0.1.5 | 0.2.1 |
| 安装方式 | PyPI | PyPI |
4.3 新增依赖
0.2.1 版本新增了大量依赖,主要涉及 Office 文档处理和 AWS 集成:
| 包 | 用途 |
|---|---|
| boto3 1.43.29 | AWS S3 SDK(R2 对象存储对接) |
| botocore 1.43.29 | boto3 底层核心 |
| s3transfer 0.18.0 | S3 传输管理 |
| openpyxl 3.1.5 | Excel .xlsx 读写 |
| pypdf 5.9.0 | PDF 解析 |
| python-pptx 1.0.2 | PowerPoint 处理 |
| python-docx 1.2.0 | Word 文档处理 |
| XlsxWriter 3.2.9 | Excel 写入优化 |
| et-xmlfile 2.0.0 | XML 文件处理 |
| tornado 6.5.7 | Web 服务(Telegram webhooks) |
4.4 依赖升级
同时,多个已有依赖也被升级到兼容版本:
| 包 | 旧版 | 新版 |
|---|---|---|
| botocore | 1.42.68 | 1.43.29 |
4.5 验证
升级完成后通过 pip show nanobot-ai 确认版本号,不再需要其他额外操作,因为 nanobot 的核心代码通过 pip install 直接替换。
五、Hermes Agent 升级
5.1 版本检测
升级前首先检测版本和远程仓库状态:
Hermes Agent v0.13.0 (2026.5.7)
Up to date # hermes 自身的版本检查
# 远程仓库
origin → git@github.com:yuanguangshan/hermes-agent.git(用户 fork)
upstream → https://github.com/NousResearch/hermes-agent.git(官方源)
5.2 获取更新
首次尝试 git fetch upstream 因为仓库历史庞大而超时。改用浅层拉取成功:
git -C /root/.hermes/hermes-agent fetch --depth=1 upstream main
发现 upstream 有 1 个新 commit(2a5dc0ef3),修复了 Slack 视频附件问题。
5.3 合并冲突
尝试 cherry-pick 新 commit 时,发现用户 fork 与上游已严重分叉——500+ 文件全部出现 add/add 冲突。这是因为用户 fork 是在早期版本从上游分离后独立发展的,两个仓库的历史完全不相关。
cherry-pick --abort # 回滚,放弃合并
5.4 依赖更新
代码虽然无法直接合并,但子依赖可以通过 uv sync 更新:
uv sync --directory /root/.hermes/hermes-agent
更新了 pydantic-core、pyjwt、yarl 等 15+ 个子依赖。
5.5 广山哥的远程更新
随后广山哥更新了远程 fork 仓库(force push),将 upstream 的最新代码合并到了自己的仓库。此时:
git -C /root/.hermes/hermes-agent fetch origin main
# + a40e67712...2a5dc0ef3 main -> origin/main (forced update)
git -C /root/.hermes/hermes-agent reset --hard origin/main
成功将 Hermes 从 v0.13.0 升级到 v0.16.0。
5.6 版本差异
新旧版本之间的差异巨大——3619 个文件被修改,+694K / -105K 行代码:
| 维度 | v0.13.0(旧) | v0.16.0(新) |
|---|---|---|
| 版本号 | 0.13.0 | 0.16.0 |
| Python 版本上限 | >=3.11 |
>=3.11,<3.14 |
| 依赖策略 | 范围锁定 | 精确锁定(供应链安全) |
| 修改文件 | — | 3619 个 |
| 新增/删除行 | — | +694K / -105K |
核心架构变化包括:
- Agent 引擎重构:旧的
run_agentmonolith 拆分为conversation_loop.py、tool_executor.py、turn_context.py、turn_finalizer.py、turn_retry_state.py等 7+ 独立模块 - Provider 抽象:browser、image_gen、transcription、TTS、video_gen、web_search 全部转为 Provider + Registry 可插拔模式
- LSP 集成:全新
agent/lsp/模块,agent 可感知编辑器诊断 - Codex Runtime:新增 HTTP/WebSocket 服务器模式的 agent 运行方式
- 插件系统成熟化:plugins/ 目录大幅扩充,支持热插拔
- 依赖安全加固:所有直接依赖改为精确版本锁定,注释明确说明是响应 mistralai 投毒事件的供应链安全加固
六、服务重启与验证
6.1 重启过程
升级后执行 restart_services.sh,脚本依次:
- 停止所有 5 个系统服务
- 清理残留进程(pkill)
- 释放端口(5000、5002、5003、18800)
- 重置 Telegram polling 状态
- 按序启动:gateway → dingtalk bridge → wechat bridge → file server → management API
- 等待 Gateway API 可用(最多 15 秒)
- 验证所有端口绑定
6.2 验证结果
全部 5 个服务正常启动,4 个端口全部监听:
| 服务 | PID | 状态 |
|---|---|---|
| nanobot-gateway.service | 974852 | 😊 在岗 |
| dingtalk-image-bridge.service | 974863 | 😊 在岗 |
| wechat-image-bridge.service | 974865 | 😊 在岗 |
| nanobot-file-server.service | 974867 | 😊 在岗 |
| nanobot-management-api.service | 974869 | 😊 在岗 |
不需要回退。
七、自定义管理面板的发现
7.1 广山哥的反馈
升级完成后,广山哥提到他访问 hms.want.biz 时看到的界面与自己维护的 Hermes 管理面板不同:
📊 状态总览
💬 会话记录
🧠 记忆系统
🌡️ 雨轩状态
📦 技能列表
⚙️ 配置查看
📋 运行日志
🎨 主题:暗色 / 亮色 / 午夜 / 森林 / 日落 / 北欧
7.2 溯源
调查发现,这个界面并非来自 Hermes 官方 Dashboard(端口 9119),也非来自 Nanobot 的 Management API(端口 18800),而是一个 完全独立的 FastAPI 服务,藏在 /root/.hermes/web-panel/ 目录下:
/root/.hermes/web-panel/
├── server.py # FastAPI 后端,342 行
└── static/
├── index.html # 单页前端,522 行
└── albums/ # 相册目录
该服务:
- 运行在端口 9100
- 由广山哥手动启动(
python3 web-panel/server.py),从 6 月 7 日运行至今 - 通过 Cloudflare Access 保护(
hms.want.biz→ Cloudflare 邮箱登录 → 本地 9100) - 不依赖 Hermes API,而是直接读取 Hermes 的本地数据文件
- 有自己的 Token 认证机制(首次启动生成
.token文件)
7.3 数据来源分析
这个面板的后端(server.py)不走任何官方 API,所有数据全部直读磁盘:
| 功能 | 数据源 |
|---|---|
| 状态总览 | ~/.hermes/config.yaml + ~/.hermes/state.db(SQLite) |
| 会话记录 | state.db 的 sessions/messages 表 |
| 记忆系统 | ~/.hermes/memories/MEMORY.md 和 USER.md |
| 雨轩状态 | ~/.hermes/data/context/daily_state.yaml |
| 技能列表 | 遍历 ~/.hermes/skills/ 目录 |
| 配置查看/编辑 | 直接读写 ~/.hermes/config.yaml |
| 运行日志 | journalctl -u hermes-gateway |
| 重启操作 | systemctl restart |
八、Systemd 服务归组
8.1 发现的问题
在排查过程中,发现 Hermes 生态中有三个进程是手动启动的,没有注册为 systemd 服务:
| 进程 | 启动方式 | 启动时间 | 问题 |
|---|---|---|---|
| hermes dashboard (9119) | 手动 python hermes dashboard ... |
Jun 7 | 重启不自动恢复 |
| acp-adapter | 手动 python -m acp_adapter.entry |
Jun 12 | 重启不自动恢复 |
| web-panel (9100) | 手动 python3 server.py |
Jun 7 | 重启不自动恢复 |
8.2 设计方案
采用 systemd target 机制将所有服务归组管理:
hermes.target
├── hermes-gateway.service — 消息网关(已有)
├── hermes-dashboard.service — Web UI(新建)
├── hermes-acp-adapter.service — ACP 适配器(新建)
└── hermes-web-panel.service — 管理面板(新建/改造)
设计要点:
- PartOf=hermes.target — 所有服务声明自己属于该 target
- BindsTo=hermes-gateway.service — web-panel 与 gateway 绑定,gateway 退出时 web-panel 自动停止
- After=hermes-gateway.service — dashboard 和 acp-adapter 在 gateway 之后启动
- Restart=on-failure — 任何服务崩溃后自动重启
- WantedBy=multi-user.target — hermes.target 随系统开机自启
8.3 创建服务文件
hermes-dashboard.service:
[Unit]
Description=Hermes Agent Dashboard (Web UI - Port 9119)
After=network-online.target hermes-gateway.service
PartOf=hermes.target
[Service]
Type=simple
User=root
ExecStart=/root/.hermes/hermes-agent/.venv/bin/hermes dashboard \
--port 9119 --host 0.0.0.0 --no-open --insecure
Restart=on-failure
RestartSec=5
WorkingDirectory=/root/.hermes/hermes-agent
[Install]
WantedBy=hermes.target
hermes-acp-adapter.service:
[Unit]
Description=Hermes Agent ACP Adapter
After=network-online.target hermes-gateway.service
PartOf=hermes.target
[Service]
Type=simple
ExecStart=/root/.hermes/hermes-agent/.venv/bin/hermes acp
Restart=on-failure
RestartSec=5
WorkingDirectory=/root/.hermes/hermes-agent
[Install]
WantedBy=hermes.target
hermes.target:
[Unit]
Description=Hermes Agent — All Services
Requires=hermes-gateway.service
Wants=hermes-dashboard.service hermes-acp-adapter.service hermes-web-panel.service
After=network-online.target
[Install]
WantedBy=multi-user.target
8.4 ACP 依赖修复
首次启动 acp-adapter 时失败,日志显示:
ACP dependencies not installed.
Install them with: pip install -e '.[acp]'
原因是新版本将 ACP 依赖从核心依赖移到了 extras。通过重新安装解决:
pip install -e /root/.hermes/hermes-agent'[acp]'
8.5 Dashboard 首次构建
Dashboard 首次通过 systemd 启动时,需要构建前端(npm ci + tsc -b + vite build),耗时约 40 秒。完成后端口 9119 正常监听。
8.6 最终状态
hermes.target active
├── hermes-gateway.service active (systemd)
├── hermes-dashboard.service active (systemd, 端口 9119)
├── hermes-acp-adapter.service active (systemd)
└── hermes-web-panel.service active (systemd, 端口 9100)
使用方式:
# 一条命令管理全部
systemctl start/stop/restart/status hermes.target
# 或单独操作某个服务
systemctl restart hermes-web-panel.service
九、升级前后对比
9.1 版本变化
| 组件 | 升级前 | 升级后 |
|---|---|---|
| nanobot-ai | 0.1.5 | 0.2.1 |
| Hermes Agent | v0.13.0 (2026.5.7) | v0.16.0 (2026.6.5) |
| 新增依赖 | — | boto3、openpyxl、pypdf、python-pptx 等 10 个 |
| Python | 3.12.3 | 3.12.3(不变) |
9.2 服务管理变化
| 维度 | 升级前 | 升级后 |
|---|---|---|
| gateway | systemd | systemd(归组到 target) |
| dashboard | 手动启动 | systemd,自动恢复 |
| acp-adapter | 手动启动 | systemd,自动恢复 |
| web-panel | 手动启动 | systemd,自动恢复 |
| 开机自启 | ❌ 部分服务 | ✅ 全部自启 |
| 崩溃恢复 | ❌ 手动进程不会恢复 | ✅ Restart=on-failure |
9.3 备份体积
| 备份 | 原体积 | 压缩后 |
|---|---|---|
| .venv | 595 MB | 159 MB |
| hermes-agent | 1.8 GB | 610 MB |
| 合计 | ~2.4 GB | ~769 MB |
十、回退方案
如果升级后需要回退,按以下步骤操作:
10.1 Nanobot 回退
# 恢复 .venv
tar -xzf /mnt/nas/backups/nanobot-upgrade-20260610/nanobot-venv-20260610.tar.gz \
-C /home/nanobot/.nanobot/
# 降级 nanobot
/home/nanobot/.nanobot/.venv/bin/pip install nanobot-ai==0.1.5
10.2 Hermes 回退
# 方式一:从 tar 完整恢复
systemctl stop hermes.target
rm -rf /root/.hermes/hermes-agent
tar -xzf /mnt/nas/backups/nanobot-upgrade-20260610/hermes-agent-20260610.tar.gz \
-C /root/.hermes/
# 方式二:git reset(需重新 uv sync)
git -C /root/.hermes/hermes-agent reset --hard a40e67712
cd /root/.hermes/hermes-agent && rm -rf .venv && uv sync
10.3 回退后重启
/home/nanobot/.nanobot/scripts/deploy/restart_services.sh
systemctl restart hermes.target
十一、经验与教训
11.1 备份先行
本次升级最大的安全保障是升级前的全量备份。如果没有 .venv 和 hermes-agent 的 tar 备份,一旦升级后出现不兼容问题,恢复将非常困难。备份不只是心理安慰,而是真正的保险丝。
11.2 不要假定用户的 fork 与 upstream 可合并
Hermes 的升级过程遇到的最大问题是用户 fork 与 upstream 历史分叉。这是一个常见场景——用户 fork 了开源项目后长期自己维护,再去合并上游时发现已经无法自动合并。对于这种情况,更好的策略是:
- 先尝试 cherry-pick 具体需要的 commit,而不是尝试完整合并
- 如果分叉太严重,考虑重新基于 upstream rebase,或者接受 fork 独立发展的现实
11.3 系统化管理的价值
将手动启动的进程转为 systemd 服务后,带来的实际收益:
- 服务器重启后所有服务自动恢复(之前需要手动逐个启动)
- 进程崩溃后自动重启(之前需要手动发现和恢复)
- 统一的管理接口(一条命令 vs 多个 tmux 窗口)
- 更清晰的依赖关系(启动顺序、绑定关系)
11.4 独立服务 vs "隐藏"服务
广山哥的自定义管理面板是一个典型的技术债案例:功能完善、运行稳定,但因为没有纳入系统化管理,"寄生"在系统中间。类似的情况在很多长期运行的系统上都会出现——一个"临时"的手动启动脚本变成了运行半年的关键服务。解决方案就是亡羊补牢:发现了就立即转为 systemd 服务。
11.5 关于大版本跳越
nanobot-ai 从 0.1.5 到 0.2.1 的升级相对平稳,因为 Python 包的向后兼容性较好。但 Hermes 从 v0.13.0 到 v0.16.0 的跨版本升级涉及大量架构变动(agent 引擎重构、插件系统、Provider 抽象),虽然目前看起来正常,但建议后续观察一段时间,留意是否有功能异常。
十二、后续建议
12.1 短期
- 观察 nanobot 和 Hermes 的渠道消息收发是否正常(Telegram、钉钉、企业微信)
- 检查自定义管理面板的"雨轩状态"和"记忆系统"页面数据是否更新正常
- 确认
hms.want.biz的 Cloudflare Access 访问正常
12.2 长期
- 定期执行
pip list --outdated检查 nanobot 依赖是否有安全更新 - Hermes 的上游更新建议定期 fetch 评估,避免再次出现大面积分叉
- 考虑将 Weclaw 等其他服务也纳入 systemd 管理
- 管理面板的 Token 认证可以增强为 session 机制
雨轩于听雨轩 🌧️🏠
*本文档记录了一次完整的软件包升级过程,从备份到升级再到服务归组,涵盖 4 个 systemd 服务的创建/改造、2 个软件包的主版本升级、以及一个隐藏管理面板的发现和系统化管理。总耗时约 3 天的断续运维。