有些安装问题不是“没装上”,而是更烦:看起来装好了,但命令一执行就没反应。
NousResearch/hermes-agent issue #21454 记录的就是这种情况:用户之前已经安装过 Hermes,后来重新运行新版 install.sh,结果 hermes、hermes doctor、hermes gateway 全部挂住,没有输出,直到手动 Ctrl+C。
这不是模型慢,也不是 DeepAI、OpenAI-compatible API、网络代理或 provider 配置问题。
根因在安装脚本:新版 install.sh 想把 ~/.local/bin/hermes 写成一个清理 Python 环境变量的 bash wrapper,但旧安装里这个路径本来是指向 venv 内 pip console script 的 symlink。脚本用 cat > ~/.local/bin/hermes 写文件时,shell 会沿着 symlink 写到目标文件,于是把真正的 venv/bin/hermes 覆盖成了一个调用自己的 wrapper。
结果就是:
hermes -> venv/bin/hermes -> exec venv/bin/hermes -> exec venv/bin/hermes -> ...
一个漂亮的无限递归。
典型症状:Hermes CLI 没报错,只是卡住
受影响时,表现通常不是 traceback。
而是:
hermes
没输出。
hermes doctor
没输出。
hermes gateway
也没输出。
命令像是在运行,但不会进入正常逻辑。
如果你刚刚重跑过:
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
并且之前机器上已经有旧版 Hermes 安装,那么这个 issue 的匹配度就很高。
旧安装留下了什么?
issue 里说,旧版安装脚本的 setup_path() 大致是这样做的:
ln -sf "$HERMES_BIN" "$command_link_dir/hermes"
也就是说,它会创建:
~/.local/bin/hermes -> ~/.hermes/hermes-agent/venv/bin/hermes
这里的 venv/bin/hermes 是 pip 生成的 Python console script,内容大概是:
#!/home/user/.hermes/hermes-agent/venv/bin/python3
import sys
from hermes_cli.main import main
if __name__ == "__main__":
sys.exit(main())
这个结构本身没问题。
~/.local/bin/hermes 是门牌,真正入口在 venv 里。
新脚本想做什么?
后来某次改动为了避免继承外部 Python 环境变量,把入口改成了 bash wrapper。
逻辑类似:
cat > "$command_link_dir/hermes" <<EOF
#!/usr/bin/env bash
unset PYTHONPATH
unset PYTHONHOME
exec "$HERMES_BIN" "\$@"
EOF
这个设计意图是合理的:
- 清掉
PYTHONPATH - 清掉
PYTHONHOME - 再执行 venv 内真正的 Hermes
问题出在写入目标。
如果:
$command_link_dir/hermes
已经是一个 symlink,那么:
cat > "$command_link_dir/hermes"
不会替换 symlink 本身,而是沿着 symlink 写到目标文件。
于是它实际覆盖的是:
~/.hermes/hermes-agent/venv/bin/hermes
也就是 pip 生成的真实入口。
最坏的结果:venv/bin/hermes 变成“调用自己”的脚本
覆盖后,venv/bin/hermes 可能变成:
#!/usr/bin/env bash
unset PYTHONPATH
unset PYTHONHOME
exec "/home/user/.hermes/hermes-agent/venv/bin/hermes" "$@"
注意最后一行:
exec "/home/user/.hermes/hermes-agent/venv/bin/hermes" "$@"
它执行的正是自己。
所以每次运行 hermes doctor,都会变成:
venv/bin/hermes exec venv/bin/hermes
venv/bin/hermes exec venv/bin/hermes
venv/bin/hermes exec venv/bin/hermes
...
没有进入 Python,也没有进入 hermes_cli.main。
这就是为什么它不是报错,而是“挂住”。
官方修复方向:写 wrapper 前先 rm -f 旧路径
issue 里给出的修复非常直接:
mkdir -p "$command_link_dir"
rm -f "$command_link_dir/hermes"
cat > "$command_link_dir/hermes" <<EOF
#!/usr/bin/env bash
unset PYTHONPATH
unset PYTHONHOME
exec "$HERMES_BIN" "\$@"
EOF
chmod +x "$command_link_dir/hermes"
关键是这一行:
rm -f "$command_link_dir/hermes"
它先删除旧的 symlink。
这样后面的:
cat > "$command_link_dir/hermes"
写出来的就是一个新的普通文件,而不会穿透 symlink 覆盖 venv/bin/hermes。
评论里也确认:该问题与 #21332 同源,PR / commit 链路中提到 #25734、commit c75e1a03f 已修复 scripts/install.sh::setup_path(),通过 rm -f 防止 redirect 跟随陈旧 symlink。
怎么判断自己是不是这个问题?
1. 看 ~/.local/bin/hermes 是不是 symlink
ls -l ~/.local/bin/hermes
如果看到类似:
/home/user/.local/bin/hermes -> /home/user/.hermes/hermes-agent/venv/bin/hermes
说明你有旧安装遗留的 symlink 结构。
2. 看 venv/bin/hermes 内容
head -20 ~/.hermes/hermes-agent/venv/bin/hermes
正常情况下,它应该是 Python console script,包含类似:
from hermes_cli.main import main
如果你看到:
#!/usr/bin/env bash
unset PYTHONPATH
unset PYTHONHOME
exec "/home/user/.hermes/hermes-agent/venv/bin/hermes" "$@"
那基本就是入口被覆盖了。
3. 看命令是不是全部无输出卡住
hermes doctor
如果没有任何输出且一直挂起,也符合这个问题。
已经中招怎么临时恢复?
issue 里给了恢复思路:把 venv/bin/hermes 恢复成 pip console script。
如果旁边有 venv/bin/hermes-agent,可以用它作为模板生成 hermes。
评论中有人用过类似方法:
cd ~/.hermes/hermes-agent
mv venv/bin/hermes venv/bin/hermes.broken.bak
sed 's|from run_agent import main|from hermes_cli.main import main|' \
venv/bin/hermes-agent > venv/bin/hermes
chmod +x venv/bin/hermes
hash -r
hermes doctor
注意:这属于针对当时环境的 workaround。不同版本的 console script 内容可能不同,最稳妥的方式还是使用包含修复的新版安装脚本重新安装,或者重新生成 venv 内 console entry point。
为什么这是安装脚本 bug,不是 shell PATH 问题?
PATH 问题通常表现为:
command not found
或者执行到了旧版本。
但 #21454 里,hermes 确实能被找到,也确实执行了。
它卡住,是因为入口脚本内部自我 exec。
所以重点不是:
echo $PATH
而是检查:
ls -l ~/.local/bin/hermes
head -20 ~/.hermes/hermes-agent/venv/bin/hermes
对 DeepAI API 中转站用户的边界说明
如果你用 Hermes 接 DeepAI API 中转站,通常会关注:
OPENAI_BASE_URLhttps://api.deepai.wang/v1- API Key
- 模型名
- OpenAI-compatible provider 配置
但这个问题发生得更早。
Hermes CLI 入口还没进入 Python 主程序,当然也不会进入 provider 初始化、HTTP 请求或模型调用阶段。
所以:
- DeepAI 不能修复
venv/bin/hermes被覆盖; - OpenAI-compatible API 配置不会影响这个无限递归;
- 换模型、换 key、换 base URL 都没用;
- 先修 CLI entry point,再谈模型 API。
FAQ
为什么重跑 install.sh 会把旧安装弄坏?
因为旧安装留下的 ~/.local/bin/hermes 是 symlink。新版脚本直接 cat > ~/.local/bin/hermes 时,写入穿透 symlink,覆盖了 venv 内真实入口。
为什么命令没有报错?
入口脚本不断 exec 自己,没有进入 Python 主程序,所以不会打印正常错误信息。
rm -f 为什么能修复?
它先删除旧 symlink,再写入 wrapper。这样写入目标是新的普通文件,而不是 symlink 指向的 venv/bin/hermes。
这个问题和 #21332 是一回事吗?
评论中维护者指出它与 #21332 是同一根因:commit 043a118d4 后的 install.sh wrapper 写入逻辑跟随旧 symlink,造成 self-exec loop。
DeepAI API 中转站配置会导致这个问题吗?
不会。这是本地安装器/CLI entry point 问题,发生在任何模型 API 调用之前。
总结
#21454 的教训很简单:
覆盖可执行入口前,先确认目标不是旧 symlink。
安装脚本要从“创建 symlink”迁移到“写 wrapper 文件”时,必须先:
rm -f "$command_link_dir/hermes"
否则 cat > 可能不是在写 wrapper,而是在把 venv 里的真实 Python entry point 改成一个会永远调用自己的脚本。