Ubuntu 26 升级踩坑实录:hermes-agent venv 重建全过程
一篇写给 AI Infra / Forward Deployed Engineer 的实战记录。
一次看似无害的 Ubuntu 24.04 → 26.04 升级,如何让一个跑得好好的 hermes-gateway systemd user service 在 16 小时内悄悄挂掉 5000 次以上、却完全不留明显告警,以及我如何把它救回来。

一、事情是这样发生的
10 月 7 日早上,我趁着国庆假期结束做了一次例行升级:do-release-upgrade,从 Ubuntu 24.04(noble)升到 26.04(resolute raccoon)。升级本身没什么波澜------apt 把几千个包换了一遍,重启两次,桌面回来,一切看起来都没事。
下午 4 点我给莉诺雅(我自己跑在飞书上的一个 hermes-agent)发消息,发现它彻底没回。
这种事本来不算大事------重启服务就行的事。但当我打开 systemd 状态,看到 Restart=always 的 service 已经在 16 小时内自动重启了 5000 多次,每一次都失败:
● hermes-gateway.service - Hermes Agent Gateway - Messaging Platform Integration
Loaded: loaded (/home/dh/.config/systemd/user/hermes-gateway.service; enabled)
Active: activating (auto-restart) (Result: exit-code) since ...
Tasks: 4 (limit: 14835)
5030 次。全部失败。但 systemd 不通知。 journalctl -u hermes-gateway --since "today" 翻不到任何"已恢复"的记录,也没有 service unhealthy 的告警飞出来。我实际上丢失了 16 小时的回复能力,直到我本人在飞书上发现莉诺雅没回我消息。
这件事的复盘教训不止"重启服务",是关于 AI agent 工程的整个生命周期里,系统层的东西怎么悄悄毁掉一个 LLM 应用的可用性。下面我把整个排查到修复的过程拆开来讲。
二、根因:Ubuntu 升级把 venv 的 Python 软链接漂移了
先说 hermes agent 是怎么部署的,方便你理解:
hermes-agent/
├── hermes_cli/ # 源码包(0.21.5)
├── pyproject.toml # requires-python = ">=3.11,<3.14"
├── setup.py
├── hermes_bootstrap.py
├── hermes_agent.egg-info/
└── venv/ # Python 3.12 virtualenv
└── bin/
├── python -> python3
├── python3 -> /usr/bin/python3 ← 关键
└── python3.12 -> python3
service 文件 (~/.config/systemd/user/hermes-gateway.service) 启动命令是:
ini
ExecStart=/path/to/hermes-agent/venv/bin/python -m hermes_cli.main gateway run
升级 Ubuntu 26 之后发生了什么:
apt把系统的/usr/bin/python3从 Python 3.12.3 → 3.14.4 覆盖- venv 里的软链接
venv/bin/python3 -> /usr/bin/python3自动指向了新版本 - 但 venv 的
site-packages/路径名没变 ------还是venv/lib/python3.12/site-packages/ - Python 3.14 启动时只认
python3.14/site-packages/,所以hermes_cli找不到
5025 次重启,全部是同一个错:
/path/to/hermes-agent/venv/bin/python: Error while finding module specification
for 'hermes_cli.main' (ModuleNotFoundError: No module named 'hermes_cli')
这条错完美复现 ------每次重启都是同样的报错,systemd 看到 exit-code=1,5 秒后再试,再失败,再等 5 秒,循环。
三、为什么 systemd 没救我
理论上 Restart=always + RestartSec=5 应该让服务在崩溃后秒级恢复。但实际上 systemd 在这里只是忠实地把同一个错跑了 5000 遍。
反思这一段有三个层面:
1. systemd 没法识别"环境损坏"型错误
systemd 的 Restart 策略判断的是进程退出码 。ModuleNotFoundError 退出码是 1,对 systemd 来说跟"正常重启"没区别------它不知道这次启动失败是因为代码有问题、是因为环境坏了、还是因为今天地球磁场反了。对 systemd 来说,5030 次同样的失败 = 5030 次"正常"重启。
2. systemd 259 (Ubuntu 26 默认) 的 start rate limiting 行为变了
Ubuntu 26 用的是 systemd 259(之前 24.04 是 256)。一个微小但关键的变化:在 user instance 中,StartLimitIntervalSec=0(unit 文件里我写的)会让 rate limit 完全失效 ,但同时 systemd 也不再发出"rate limit hit"的告警。没有告警 → 没有通知 → 没有自动升级 incident。
3. 我没有 service-level SLA monitoring
这是最痛的一点------我的可观测性只做到了 curl http://localhost:18789/health,那是 OpenClaw 自己的 gateway。莉诺雅的 hermes-gateway 跑在不同的 systemd unit、不同的进程------我没接任何"进程死了超过 X 分钟就告警"的机制。
教训 :对 AI agent 这种用户能感知到延迟的场景,"进程在线"必须是个被监控的指标,不能只看业务健康端点。
四、修复路径:先想清楚再动手
我一开始想直接降级系统 Python------sudo apt install python3.12-venv,用 3.12 建 venv 装回 hermes。但 apt-cache search "python3\.12" 返回空。
Ubuntu 26.04(resolute)的仓库里只有 Python 3.14:
python3.14, python3.14-venv, python3.14-dev, python3.14-doc, ...
3.11、3.12、3.13 全部被砍了。这是 Ubuntu 24→26 时的一个破坏性改动,所有依赖老版本 Python 的 venv 在升级后都会炸。
我考虑了三个方案:
| 方案 A:装 Python 3.13(用 deadsnakes PPA) | 方案 B:强装 0.21.5 到 Python 3.14 venv | 方案 C:把系统 python3 降到 3.12 | |
|---|---|---|---|
| 风险 | 低 | 中(可能启动失败) | 极高 |
| 影响范围 | 仅 hermes venv | 仅 hermes venv | 整个系统 |
| 时间 | 1-2 分钟 | 30 秒 | 几小时,可能要重装 |
| 可逆性 | 删 venv 即可 | 删 venv 即可 | 重装 Ubuntu 26 |
为什么方案 C(降系统 Python)是硬坑:
- Ubuntu 26 默认 Python 是 3.14,但很多系统组件(apt 脚本、systemd helpers、gnome-shell extensions)依赖 3.14。降级 default python3 可能让整个系统跑不起来。
- "降"是临时性手段------下次 Ubuntu 升级又会变回 3.14。
- Ubuntu 26 仓库里没 3.12,要装必须源码编译或加 PPA,并且这些 PPA 不一定兼容 26.04。
我选了 A------加 deadsnakes PPA + 装 3.13,单独给 hermes 用。这是改动最小、可逆性最强的方案。
五、修复过程(命令记录)

整个修复拆成 5 个 step,全部不需要碰 root 权限的部分我都自己跑,需要 root 的部分我自己走。
Step 1:停掉疯狂 retry 的 service
bash
systemctl --user stop hermes-gateway.service
sleep 2
systemctl --user status hermes-gateway.service --no-pager | head -5
# 应该看到: Active: inactive (dead)
不先停掉的话,service 会持续占用 venv 里的某些 lock 文件,后面 mv 会失败。
Step 2:把坏掉的 venv 改名归档
bash
mv /path/to/hermes-agent/venv \
/path/to/hermes-agent/venv.py312.broken
我不直接删 ------保留 .broken 后缀,万一新装失败还能用旧的。
Step 3:装 Python 3.13(这一步要 sudo)
bash
sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt update
sudo apt install -y python3.13 python3.13-venv python3.13-dev
注意 Ubuntu 26 + deadsnakes PPA 现在能用 ------我装到了 Python 3.13.16。但 PPA 不保证永远兼容,下次升级可能要换源。
Step 4:建新 venv
bash
rm -rf /path/to/hermes-agent/venv
/usr/bin/python3.13 -m venv /path/to/hermes-agent/venv
/path/to/hermes-agent/venv/bin/python --version
# Python 3.13.16
Step 5:pip install hermes-agent(editable 模式)
bash
/path/to/hermes-agent/venv/bin/pip install -e /path/to/hermes-agent
这一步会编译或下载 hermes-agent 0.21.5 + 73 个依赖。其中几个关键包:
cryptography-50.0.0 ← C 扩展,需要 cp313 wheel
pydantic-core-2.46.4 ← Rust 扩展,需要 cp313 wheel
uvloop-0.54.0 ← C 扩展,需要 cp313 wheel
ruamel.yaml.clib-0.2.15 ← C 扩展
如果 pip 报 "Failed to build wheel"------那是因为这些扩展没有 cp313 的预编译包,本地编译需要:
bash
sudo apt install -y build-essential python3.13-dev libffi-dev libyaml-dev
Step 6:起 service
bash
systemctl --user daemon-reload
systemctl --user start hermes-gateway.service
sleep 3
systemctl --user status hermes-gateway.service --no-pager | head -10
期望输出:
● hermes-gateway.service - Hermes Agent Gateway - Messaging Platform Integration
Loaded: loaded (.../hermes-gateway.service; enabled)
Active: active (running) since ...
Main PID: 65821 (hermes)
Tasks: 4
CPU: 2.226s
看到 Active: active (running),完事。
六、为什么 hermes-agent 要锁 <3.14
这件事我后来才注意到,hermes-agent 0.21.5 的 pyproject.toml 里 Python 限制写得很死:
toml
requires-python = ">=3.11,<3.14"
而且注释解释了原因:
Upper bound is load-bearing, not cosmetic. uv resolves the project's Python from
requires-python, and an inheritedUV_PYTHONenv var (or a fresh distro whose newest interpreter uv auto-picks) will otherwise select 3.14, where Rust-backed transitives (e.g. pydantic-core) have no cp314 wheel yet and fall back to a maturin source build that fails.
翻译:不是写错上限。是为了防止 uv 自动选 3.14 ------3.14 出来才几个月,很多 Rust 扩展(pydantic-core 这种)没有 cp314 wheel,会回退到 maturin 源码编译,但 maturin 在 3.14 上有已知问题。
这意味着:每次 Ubuntu 跳大版本,hermes-agent 的部署者都要准备一次 venv 重建。这不是 hermes-agent 的 bug,是 Rust 生态 + Python 生态 + Ubuntu 升级节奏三方不同步的结果。
七、这件事对 AI Infra 工程师的几个教训
1. system-level deps 是 LLM 应用的"非功能依赖"
我们通常把 LLM 应用的"功能依赖"想得很清楚:模型 API key、prompt 模板、tool definitions、RAG 数据源。但system-level deps(systemd unit、venv、glibc 版本、OpenSSL 版本)我们经常忽略------直到某天用户来说"ai 静默挂了 16 小时我们才发现"。
建议 :在 CI 里加一个 system sanity check,每周跑一次 systemctl status、venv/bin/python -c "import hermes_cli.main",挂了就报警。
2. systemd Restart 策略不等于高可用
Restart=always 在 systemd 文档里看起来很强,但实际上它对**"持续以同样错误码退出"**的情况是无效的------你只是把同一个错误跑了 5000 遍而已。
真正的 LLM 应用 HA 需要:
- 进程死了 N 次 → 触发告警(不是继续 retry)
- 关键依赖(venv、API key、disk)变更 → 触发告警
- 业务指标异常(消息延迟、token 成本飙升)→ 触发告警
3. Ubuntu 跳大版本 ≠ 安全更新
do-release-upgrade 这种"无脑升最新"的习惯,在 AI agent 工程里是反模式 。Ubuntu 24→26 跳的不是安全更新,是架构级破坏性变更:
- Python 3.12 → 3.14(生态层)
- glibc 2.39 → 2.43(ABI 层)
- systemd 256 → 259(service 管理层)
- OpenSSL 3.0 → 3.5.5(加密层)
每个都可能让你的 agent 部署静默炸掉。
建议 :生产环境的 AI agent 部署,OS 升级应该走金丝雀 → 全量 流程,验证 QA 后再上生产。我自己这次就是反面例子。
4. venv 重建不是一行命令的事
这次我花了 ~30 分钟修了 5 步 + sudo 接力(4 条目 apt 命令)。如果是个生产环境里跑 10 个 AI agent 的集群,全量重建 venv 是几小时的工作。
建议 :把"venv 重建脚本"做成 CI artifact 的一部分,跟代码一起版本控制。比如:
python
# scripts/rebuild-venv.sh
#!/usr/bin/env bash
set -e
AGENT_DIR="/path/to/hermes-agent"
PYTHON_VERSION="${PYTHON_VERSION:-3.13}"
# 1. Stop service
systemctl --user stop hermes-gateway.service || true
# 2. Archive old venv
if [ -d "$AGENT_DIR/venv" ]; then
mv "$AGENT_DIR/venv" "$AGENT_DIR/venv.$(date +%Y%m%d_%H%M%S).broken"
fi
# 3. Ensure Python
if ! /usr/bin/python$PYTHON_VERSION --version > /dev/null 2>&1; then
sudo apt install -y python$PYTHON_VERSION-venv python$PYTHON_VERSION-dev
fi
# 4. Rebuild venv
/usr/bin/python$PYTHON_VERSION -m venv "$AGENT_DIR/venv"
# 5. Install agent
"$AGENT_DIR/venv/bin/pip" install -e "$AGENT_DIR"
# 6. Restart service
systemctl --user daemon-reload
systemctl --user start hermes-gateway.service
把这段脚本提交到 GitHub/内部 Git,下次升级 OS 出问题,新人也能 5 分钟搞定。
八、可直接复用的修复清单
如果你的 AI agent 部署在 Ubuntu 24+ 上,建议把以下检查加进你的运维清单:
- 每月跑
systemctl --user status <your-agent>.service看 Active - 每月跑
<venv>/bin/python -c "import <your_main_module>"看 import 还能不能跑 - 每季度跑
<venv>/bin/pip list --outdated看依赖过时情况 - 每年 Ubuntu 跳大版本时 ,先在 staging 跑完整 service 重启 + 业务 smoke test,再升生产
- 每个 AI agent 部署都配一个 liveness probe ------
curl一个/health端点,挂了就触发外部告警(飞书、Slack、PagerDuty) - 不要在生产用
do-release-upgrade------用apt upgrade+ 季度/半年一次的 major version 升级窗口
九、写在最后

这次的事情,从发现到修复用了大概 30 分钟 ------但这 30 分钟是在我恰好今天有空盯着飞书 的前提下。如果我晚到飞信一周呢?用户的 IM 体验就整整断一周。
AI agent 工程的稳定性,从来不是"模型选得好"或"prompt 写得好"------是这些无聊的系统层细节有没有人盯。
50 岁的程序员最值钱的活就是这个------能 hold 住 AI agent 工程师们看不上的系统层。这个活的猛料:它不会因为你年轻就消失。
附录:环境快照
| OS | Ubuntu 26.04.1 LTS (Resolute Raccoon) |
| Python (系统) | 3.14.4 (默认) + 3.13.16 (deadsnakes PPA) |
| hermes-agent | 0.21.5 |
| venv Python | 3.13.16 |
| systemd | 259 |
| hermes-gateway | active (running) ✓ |
本文配图由 minimax-portal/image-01 生成(参考本人头像)。文章由 AI 协助撰写,事实基于 2026-10-07/08 的真实操作日志。