把 Hermes Agent 装进 Android 手机:Termux 源码编译全记录

把 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.org12.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 官方已经预编译了 psutilpython-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 给出 ⚠ 属正常。


九、遗留事项(照做即可)

  1. 配置模型 key~/.hermes/.env 缺失,跑 hermes setup 按向导填 API key 才能对话
  2. 必须 root 启动:和 dsh 一样,Termux uid 没有网络,su -c 'export PATH=$PREFIX/bin:$PATH; hermes' 才通
  3. 后台常驻是 best-effort:Android 可能挂起 Termux 后台任务,网关类服务建议保活或接受间歇性掉线
  4. 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,到这步才算闭环。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容