自动化 Agent 能执行终端命令,是效率来源,也是风险来源。
NousResearch/hermes-agent issue #3397 记录了一个很典型的“控制平面误伤自己”问题:Telegram Gateway 里的 Agent 想设置提醒,误判 Gateway 没运行,于是执行:
pkill -f "cli.py --gateway"
结果这条命令不是清理无关进程,而是直接把正在承载自己的 Gateway 进程杀掉了。
systemd 看到的是一次“正常退出”:
hermes-gateway.service: Deactivated successfully.
但从用户角度看,机器人突然离线,直到人工重启。
表面现象:Agent 说 gateway 没跑,然后真的把 gateway 干掉了
issue 里的日志很有画面感。
Agent 先得出一个错误判断:
gateway çalışmıyor (port 8000/8080'de dinleme yok)
翻译过来就是:
gateway 没有运行,因为 8000/8080 端口没有监听。
问题是,这个判断本身就不稳。
Telegram Gateway 可以是 polling 模式,不一定监听 HTTP 端口。
于是 Agent 基于错误的健康检查,继续执行“清理命令”:
pkill -f "cli.py --gateway"
然后 journalctl 里出现:
[tool] pkill -f "cli.py --gateway"...
systemd[1]: hermes-gateway.service: Deactivated successfully.
这就是典型的:
排障动作比原问题更致命。
根因:DANGEROUS_PATTERNS 拦了 pkill -9,却没拦 pkill -f
issue 指向 tools/approval.py 的 DANGEROUS_PATTERNS。
当时的危险命令拦截覆盖了类似:
r'\bpkill\s+-9\b'
也就是强杀:
pkill -9 ...
但没有覆盖:
pkill -f "cli.py --gateway"
-f 的危险性在于:它按完整命令行匹配。
如果匹配对象是:
hermes
gateway
cli.py --gateway
那就很可能是在杀 Agent 自己的控制平面。
所以危险不只来自 -9。
危险来自:
kill / pkill / killall 的目标是不是 Hermes/Gateway 本身。
为什么这是 Gateway 场景里的高危命令?
Gateway 是 Agent 和用户之间的通道。
如果 Agent 在 Gateway 内运行,又执行命令杀 Gateway,就会出现悖论:
Agent 通过 Gateway 接收指令
→ Agent 判断 Gateway 状态
→ Agent 杀掉 Gateway
→ Agent 失去接收/回复通道
这类问题和普通进程管理不同。
普通 shell 里用户自己敲:
pkill -f "cli.py --gateway"
至少用户知道自己在停服务。
但 Agent 自动执行这条命令时,应该进入审批流,给用户一次确认机会。
正确的安全边界:杀控制平面必须审批
issue 的预期行为很明确:
pkill -f "cli.py --gateway" should be caught by DANGEROUS_PATTERNS and trigger approval flow.
也就是说,不一定完全禁止,但至少不能静默执行。
更合理的拦截规则类似:
(r'\b(pkill|killall)\b.*\b(hermes|gateway|cli\.py)\b',
"kill hermes/gateway process (self-termination)")
这个 pattern 的重点是组合判断:
- 命令是
pkill或killall; - 目标包含
hermes、gateway、cli.py等控制平面关键词。
这样不会把所有 pkill 都一刀切,但会拦住高风险自终止。
后续修复线索:PR #9895 扩大了审批拦截范围
issue 评论里提到,该问题已经修复:
pkill -f "cli.py --gateway"
会被已有的 pkill.*hermes/gateway dangerous command pattern 捕获。
评论还提到 PR #9895 扩展了拦截范围,包括:
hermes gateway stop/restarthermes updatesystemctl restart
这些都属于“可能影响当前 Agent 运行环境”的操作。
这很合理。
因为真正需要保护的不是某一个命令字符串,而是一类动作:
让 Agent 所在服务停止、重启、升级或失联。
为什么“检查端口”会误判 Gateway 状态?
这个 issue 里还有一个隐藏教训:不要用不匹配的健康检查判断服务是否运行。
Agent 之所以动手杀进程,是因为它检查了:
port 8000/8080
发现没有监听,就认为 Gateway 没跑。
但 Telegram polling bot 不一定需要在本机监听 HTTP 端口。
所以正确排查应该看:
systemctl status hermes-gateway
journalctl -u hermes-gateway -n 100 --no-pager
ps aux | grep hermes
而不是简单假设:
没监听 8000/8080 = gateway 不运行
错误诊断 + 高权限清理命令,是危险组合。
Windows 评论:execute_code 绕过 DANGEROUS_PATTERNS 的另一个风险
issue 后续评论还提到 Windows native 场景:Agent 可能通过 execute_code + schtasks /end 强制重启宿主进程。
重点不是 Windows 本身,而是:
如果危险命令只在 terminal tool 层拦截,而 execute_code 里的 subprocess 绕过拦截,那仍然会自终止。
这说明安全边界不能只看“用户输入的 shell 命令”。
还要考虑:
- terminal tool;
- code execution tool;
- Python subprocess;
- scheduled task;
- service manager;
- systemctl / launchctl / schtasks。
只要能停止 Gateway,就应该进入更严格的审批或防护策略。
排查建议:先问“我是不是在杀自己?”
如果 Agent 或自动化脚本准备执行这些命令,先停一下:
pkill -f "hermes"
pkill -f "gateway"
pkill -f "cli.py --gateway"
killall hermes
systemctl restart hermes-gateway
hermes gateway restart
这些不是不能执行。
但应该满足至少一个条件:
- 用户明确要求重启/停止 Gateway;
- 有审批流确认;
- 当前会话不依赖这个 Gateway;
- 有 supervisor 自动拉起,并且用户知道会丢失 inflight session;
- 命令目标经过精确确认,不是模糊
pkill -f。
否则,Agent 很可能一边“修复”,一边把自己断线。
更安全的替代做法
1. 只读检查优先
先运行:
systemctl status hermes-gateway
journalctl -u hermes-gateway -n 100 --no-pager
不要先 kill。
2. 用服务管理器,不用 pkill
如果确实要重启:
systemctl restart hermes-gateway
但这也应该触发审批,因为它会中断服务。
3. 避免模糊匹配
少用:
pkill -f something
因为 -f 会匹配完整命令行,误伤概率高。
4. Gateway 内部不要随意管理 Gateway 本身
如果 Agent 正通过 Gateway 和用户通信,停止 Gateway 等于切断自己的控制通道。
这种操作应该更像“维护模式”,而不是普通排障动作。
对 DeepAI API 中转站用户的边界说明
如果 Hermes 后端使用 DeepAI API 中转站,完整链路可能是:
Telegram / Discord / Mattermost → Hermes Gateway → Agent → DeepAI / OpenAI-compatible API
#3397 出错在最前面的 Gateway 控制平面。
也就是说:
- 消息通道被 Agent 自己杀掉;
- 请求不会继续到 Agent;
- 更不会到 DeepAI;
- 换 Base URL、换模型、换 API Key 都解决不了 Gateway 被 pkill 的问题。
DeepAI 可以作为稳定的 OpenAI-compatible API 后端,例如:
https://api.deepai.wang/v1
但它不能防止本地 Agent 执行 pkill -f "cli.py --gateway"。
要先保证控制平面活着,再谈模型调用质量。
FAQ
为什么 pkill -f 比 pkill -9 更值得拦?
-9 是强杀信号,危险很明显;-f 按完整命令行匹配,可能悄悄命中 Gateway 自己,同样危险。
Agent 为什么会误判 gateway 没运行?
它检查了 HTTP 端口 8000/8080,但 Telegram polling gateway 不一定监听这些端口。
这个问题修复了吗?
issue 评论称已修复,pkill -f "cli.py --gateway" 会被 pkill.*hermes/gateway dangerous command pattern 捕获,PR #9895 还扩大了相关 blocklist。
systemctl restart 也要审批吗?
在 Gateway Agent 场景下应该要。它会中断当前消息通道,可能丢失进行中的 session。
DeepAI 能解决这个问题吗?
不能。这是本地 Gateway / terminal safety / approval flow 问题,不是模型 API 问题。
总结
#3397 的核心教训是:
Agent 不能静默执行会杀死自己控制平面的命令。
尤其是:
pkill -f "cli.py --gateway"
这种看似普通的清理命令,在 Gateway 内部就是自终止。
安全拦截不应该只盯着 pkill -9,而应该识别“kill 命令 + Hermes/Gateway 目标”的组合,并把它交给用户审批。