把 Hermes Agent 装进 Android 手机:Termux 源码编译全记录
继上次把 DeepSeek Harness (dsh) 跑进手机之后,这次轮到了 Hermes Agent——Nous Research 出品的 CLI 智能体框架。
不同的是,Hermes 是 Python 项目,要在手机上从源码编译 80 多个依赖(含 Rust/C 扩展),坑比 dsh 多了一倍不止。
本文记录完整过程:5 个大坑 + 5 个解法,全部实测可复现。
一、为什么在手机上跑 Hermes
Hermes Agent 是 Nous Research 开源的 Agent 运行时——命令行智能体,支持 MCP、定时任务(cron)、Telegram 网关、记忆(Honcho)、后台任务等,本地运行,数据不出设备。
PC 上安装有官方脚本,但手机上没有官方 App。唯一路径同样是 Termux:Android 上的终端模拟器,本质是一个独立的 Linux 用户态环境。
本文设备:一加 12(PJX110),Android 16(API 36),KernelSU root,Termux 环境,git / python 3.14.6 / clang 21.1.8 / rustc 1.97.1 / cargo 1.97.1 / make / pkg-config / libffi / openssl / ffmpeg 全套工具链。
前置要求:手机必须 Root,能通过
adb连接电脑。Hermes 的 Termux 路径是官方文档标注的 Tier 2 支持(best-effort)。
二、第一步就撞墙:Python 版本不匹配
Hermes 的 pyproject.toml 写着:
requires-python = ">=3.11,<3.14"
而 Termux 只有 Python 3.14.6(Termux 仓库不维护多版本 Python)。
试过几条路:
uv python install 3.13→ 失败:No download found for cpython-3.13-linux-aarch64-none。uv 在 Android 上找不到 3.13 构建,因为 python-build-standalone 新版发布物里已经移除了 Android 资产。- 换老版本 python-build-standalone → 逐个探测 2023~2026 的 release,Android aarch64 构建早已下架。
解法:直接用 3.14 + --ignore-requires-python。
关键判断:pyproject 注释里写着”pydantic-core 从 2.12.5 升到 2.13.4 就是为了带 cp314 支持”——说明 pin 的 Rust 依赖版本已经支持 Python 3.14。2026 年了,主流包的 cp314 wheel / 源码构建早已就绪,<3.14 的限制是过时的。
venv/bin/python -m pip install -e '.[termux]' -c constraints-termux.txt --ignore-requires-python
三、Termux 的网络怪圈:用户没网,root 有网
这是整个安装过程中最绕的一环,dsh 安装时就踩过,Hermes 又踩了一遍:
| 身份 | 网络 | 包管理器 |
|---|---|---|
| Termux 应用 uid(10493) | ❌ DNS 解析失败(ENOTFOUND) | ✅ pkg/apt 可用 |
| root | ✅ 一切正常 | ❌ 被永久禁用(”disabled permanently for safety”) |
结果就是:装包(pkg)要切 Termux uid,但切过去没网;root 有网但 pkg 不让用。
解法(装小工具时很实用):root 直接下载 .deb 再用 dpkg -i 安装——dpkg 没有 root 限制。比如装 uv:
curl -fsSL -o uv.deb "https://packages.termux.dev/apt/termux-main/pool/main/u/uv/uv_0.12.5_aarch64.deb"
dpkg -i uv.deb
大项目的依赖安装(pip)则全程以 root 执行——反正 Termux uid 也没网。
四、PyPI 直连超时:pip 卡死一整晚
第一次跑 pip install,8 分钟零输出,进程活着但什么都不干。排查:
curl -4 https://pypi.org→ 12.7 秒(慢到 read timeout)curl -6 https://pypi.org→ 1.1 秒(IPv6 反而快)
pip 默认走 IPv4,每次 metadata 请求都撞 60 秒 read timeout,然后重试,整个解析过程卡死。
解法:换国内镜像。清华源 0.2 秒响应,下载速度 19~38 MB/s:
export PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
效果立竿见影——之前 8 分钟无进展,换源后依赖解析秒过。
五、cargo 卡死:crates.io 也是慢性子
pip 换源后顺利推进,直到 jiter(openai SDK 的 Rust 依赖)开始编译——Preparing metadata 卡了 7 分钟不动。
原因一样:maturin 准备 metadata 时要跑 cargo metadata 拉 crates.io,而 crates.io 直连 13 秒/请求(静态文件 CDN 被限速)。
解法:配置 rsproxy 稀疏镜像(0.14 秒响应):
# ~/.cargo/config.toml
[source.crates-io]
replace-with = "rsproxy-sparse"
[source.rsproxy-sparse]
registry = "sparse+https://rsproxy.cn/index/"
[registries.rsproxy]
index = "https://rsproxy.cn/crates.io-index"
[net]
git-fetch-with-cli = true
配置后 cargo 立即起飞,rustc 4~8 核并行编译。
六、psutil 拒绝 Android:platform android is not supported
编译队列走到 psutil 时直接报错:
Getting requirements to build wheel did not run successfully.
platform android is not supported
psutil 的源码包在 Android 上直接拒绝构建。但查一下发现——Termux 官方已经预编译了 psutil(python-psutil 7.2.2,系统 Python 自带),而且版本和 Hermes pin 的 psutil==7.2.2 完全一致!
解法:重建 venv 并复用系统包:
python3 -m venv --system-site-packages venv
加 --system-site-packages 后,pip 解析到 psutil 时发现系统里已有 7.2.2,直接跳过编译复用。这一个参数省掉了 psutil 的编译,也避免了这个无解的 android 平台报错。
七、编译进行时:13 个原生包在手机上”出锅”
镜像配置齐了之后,剩下的就是等。手机上 80+ 个依赖陆续安装,其中 13 个没有 Android wheel 的包全部在手机上源码编译:
| 包 | 类型 | 耗时参考 |
|---|---|---|
| cryptography 50.0.0 | Rust + C | ~5 min |
| pydantic-core 2.46.4 | Rust (maturin) | ~8 min |
| Pillow 12.3.0 | C | ~4 min |
| uvloop 0.22.1 | Cython | ~4 min |
| watchfiles / rpds-py / jiter | Rust | 各 1~3 min |
| pyyaml / cffi / httptools / MarkupSafe / tornado / ruamel.yaml.clib | C | 各 1~2 min |
生成的 wheel tag 长这样:cryptography-50.0.0-cp314-abi3-android_36_arm64_v8a.whl——Termux 的 Python 正确识别了 Android 平台。
监控技巧:
# 后台跑安装,日志落盘
su -c 'nohup ./install.sh > /data/local/tmp/pip.log 2>&1 &'
# 看是不是真在编译(rustc/cargo 存在且高 CPU 就是)
ps -A -o PID,STAT,%CPU,CMD | grep -E "rustc|cargo|clang"
一加 12 的 8 核压满了 rustc,总编译时间约 40 分钟。
八、收尾与验证
ln -sf "$PWD/venv/bin/hermes" "$PREFIX/bin/hermes" # 进 PATH
hermes version # → Hermes Agent v0.20.3
hermes doctor
doctor 核心检查全绿:Python 3.14.6 ✓、SQLite ✓、SSL 证书 ✓、OpenAI SDK/Rich/PyYAML/HTTPX/croniter/python-telegram-bot 全部就绪 ✓。browser / vision / tts 等可选插件在 Termux 上不在官方 tested path,doctor 给出 ⚠ 属正常。
九、遗留事项(照做即可)
- 配置模型 key:
~/.hermes/.env缺失,跑hermes setup按向导填 API key 才能对话 - 必须 root 启动:和 dsh 一样,Termux uid 没有网络,
su -c 'export PATH=$PREFIX/bin:$PATH; hermes'才通 - 后台常驻是 best-effort:Android 可能挂起 Termux 后台任务,网关类服务建议保活或接受间歇性掉线
- dsh 与 Hermes 共存无冲突:一个 Node 栈(Web 面板 + QQ Bot),一个 Python 栈(CLI Agent),互不干扰
十、总结:Termux 装 Python 大项目速查表
| 症状 | 解药 |
|---|---|
requires-python 版本被拒 |
确认 Rust 依赖已支持新版后 --ignore-requires-python |
| pip 卡死无输出 | PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple |
| cargo/maturin 卡住 | 配 ~/.cargo/config.toml rsproxy 镜像 |
platform android is not supported |
venv 加 --system-site-packages 复用 Termux 预装包 |
| pkg 拒绝 root / 用户没网 | root 下载 .deb + dpkg -i,pip 全以 root 跑 |
| 服务连不上 | root 启动(Termux uid 入站被 BPF 过滤) |
手机跑 Agent 的意义,不只是”图一乐”——Termux + Root 让 Android 变成一台随身 Linux 工作站,dsh、Hermes、未来的各种 Agent 都能在本地跑,数据不出设备。下一个想装什么?评论区告诉我。
十一、从装好到跑起来:启动实录与开机自启
上一篇停在「装好了,但遗留事项还有三条」。这篇把后续补完:Hermes 第一次真正跑起来(QQ Bot Gateway),以及把「必须 root 启动、后台常驻 best-effort」这两个遗留问题,一次性解决到位。
1. 第一个坑:su 长命令直接翻车
手机连上 adb 后,习惯性地敲了一条带环境变量的长命令:
adb shell su -c 'export PATH=/data/data/com.termux/files/usr/bin:$PATH; hermes --help'
error: service name too long
KernelSU 的 su 对超长命令直接拒绝,连执行的机会都不给。解法很简单——把命令写进脚本文件,push 到 /data/local/tmp/ 再执行:
adb push start_hermes.sh /data/local/tmp/
adb shell su -c 'sh /data/local/tmp/start_hermes.sh'
2. 第二个坑:nohup 启动的进程说没就没
第一次后台启动,日志文件 0 字节,进程 5 秒后消失:
# 错误示范:进程随 su 会话结束被回收
nohup hermes gateway run --replace & # PID 还在,人没了
# 正确姿势:setsid 完全脱离会话,由 init 收养
setsid nohup hermes gateway run --replace > ~/hermes-gw.log 2>&1 < /dev/null &
关键点:adb shell su -c 的会话结束时,Android 会清理会话内的子进程,只有 setsid 脱离之后进程才能存活。
3. QQBot 首连超时?别慌,是重连机制在跑
gateway 起来后第一眼看到的是:
✗ qqbot error: qqbot connect timed out after 30s
Gateway started with no connected platforms — 1 platform(s) queued for retry
别急着重装——这是 Hermes 的正常重试机制。约 40 秒后日志里就会出现:
[QQBot:1903600262] WebSocket connected to wss://api.sgroup.qq.com/websocket
[QQBot:1903600262] Ready, session_id=xxxx
✓ qqbot reconnected successfully
之后就能正常收发 QQ 消息了。顺便一提,日志里还有一条 wecom-platform 插件加载失败 的警告,那是 cryptography 库在 Android 上的符号问题,不影响 QQBot,可以无视。
4. 开机自启:设备上其实藏着 3 份互相打架的脚本
KernelSU 支持 Magisk 兼容的 /data/adb/service.d/ 开机脚本目录。检查之后发现,手机里早就有了 3 份 Hermes 自启脚本,各有各的问题:
| 脚本位置 | 问题 |
|---|---|
/data/adb/service.d/99-hermes.sh |
用 su 切到 Termux uid 启动 → QQBot 无网络(Termux uid 的网络问题) |
/data/adb/service.d/99-hermes-gw.sh |
没加 setsid,进程易随会话退出 |
| WorkSettingPro 模块 service.d 里的副本 | 模块的 service.sh 每次开机都会遍历执行,与上面两份重复启动 |
方案:只留一份健壮脚本(/data/adb/service.d/99-hermes-gw.sh),删除 su 切换版,把模块副本同步成同样内容,靠「防重复检查」兜底:
#!/system/bin/sh
# Hermes Gateway 开机自启(root 启动,含 QQbot)
# 1. 等待系统完成启动
until [ "$(getprop sys.boot_completed)" = "1" ]; do sleep 3; done
# 2. 等待用户解锁(FBE 加密存储就绪)
until [ "$(getprop sys.user.0.ce_available)" = "true" ]; do sleep 3; done
# 3. 等待网络就绪
while [ "$(getprop init.svc.netd)" != "running" ]; do sleep 2; done
sleep 10
# 4. 防重复启动
pgrep -f "hermes gateway run" >/dev/null 2>&1 && exit 0
# 5. 设置 Termux 环境变量
export PREFIX=/data/data/com.termux/files/usr
export PATH="$PREFIX/bin:$PATH"
export HOME=/data/data/com.termux/files/home
export LD_LIBRARY_PATH="$PREFIX/lib"
# 6. setsid 后台启动
cd "$HOME" || exit 0
setsid "$PREFIX/bin/nohup" "$PREFIX/bin/hermes" gateway run --replace
>>"$HOME/.hermes/logs/gateway-boot.log" 2>&1 < /dev/null &
exit 0
验证:手动执行该脚本,返回 0 且进程数不变(防重复生效);当前 gateway 仍由原 PID 运行,QQBot Ready。
5. 小结:启动与自启速查
| 症状 | 解药 |
|---|---|
su 报 “service name too long” |
命令写入脚本文件,push 到 /data/local/tmp/ 再执行 |
| 后台进程随 adb 会话消失 | setsid nohup ... < /dev/null & |
| QQBot 首连超时 | 正常,等 40s 自动重连即可 |
| 开机不自启 / 重复启动 | KernelSU /data/adb/service.d/ 放一份脚本 + 防重复检查,清掉冲突副本 |
至此,手机上的 Hermes 从「装好了」真正变成「一直在跑」——重启手机自动拉起,QQ 机器人随时在线。折腾 Android 上的 Agent,到这步才算闭环。



暂无评论内容