Ubuntu 26 升级踩坑实录:hermes-agent venv 重建全过程

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 之后发生了什么:

  1. apt 把系统的 /usr/bin/python3 从 Python 3.12.3 → 3.14.4 覆盖
  2. venv 里的软链接 venv/bin/python3 -> /usr/bin/python3 自动指向了新版本
  3. 但 venv 的 site-packages/ 路径名没变 ------还是 venv/lib/python3.12/site-packages/
  4. 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 inherited UV_PYTHON env 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 的真实操作日志。

相关推荐
新时代牛马1 小时前
Linux PREEMPT_RT 详解(5.10.268-rt164)
linux·运维·服务器
眼不痛请看我1 小时前
Ubuntu_22.04_LTS虚拟机安装指南
linux·数据库·ubuntu
哎呦,帅小伙哦1 小时前
查看网卡配置连接工具组合——nmcli + nmtui
linux
xiaoye-duck1 小时前
《Linux 网络编程》从 0 手写 Reactor 反应堆(上):拆解 Reactor 架构 —— 连接抽象、Poller 封装与事件派发核心
linux·网络
脚踏实地,坚持不懈!1 小时前
Android 电池健康度检测全流程(驱动 → 内核 → HAL → Framework)
android·linux
IT技术分享社区1 小时前
在 Windows 上跑未改动的 Linux 程序:微软 LiteBox v0.1 把这件事变简单了
linux·运维·windows·microsoft·开源
范中勤2 小时前
Agent IDE 双层异步调用机制:前端流式与后端多分支调度,到底各自解决什么问题
llm·agent·claude code·subagent·异步架构
JackLam2 小时前
mobile-use 使用与接入第三方 LLM 网关完整指南OC
android·ai·mobile use