Hermes Agent Windows 排错全攻略:幽灵目录与 Web UI 修复
在 Windows 上折腾 Hermes Agent,有时候会遇到一些让人摸不着头脑的问题。最近就有一个典型例子:明明在服务器上配好了喝水提醒的定时任务,日志也显示一切正常,但三个月过去,微信里一条提醒都没有。
不是任务没跑——它压根就没被 Hermes 读取过。
问题出在配置写到了一个错误的目录里,而这个错误是 Windows 上特有的路径陷阱。下面就从这个“幽灵任务”开始,一步步拆解排查过程。
1. 幽灵目录
先说现象。
用 Hermes 列出所有 Cron 任务:
cronjob list → 返回:深圳每日天气
但明明之前创建过一个“喝水提醒”。翻到 ~/.hermes/cron/jobs.json,确实存在:
{
"name": "喝水提醒",
"schedule": "0 15 * * *"
}
⚠️ 天气任务在这个文件里不存在。反过来,cronjob list 输出的任务里也没有“喝水提醒”。
一个文件里有喝水没天气,另一个工具里有天气没喝水——它们读的根本不是同一个文件。
搜索整个 ~/.hermes/ 目录,天气任务的 ID 也找不到。这个天气任务到底从哪儿来的?
2. 源码会说话
带着疑问翻 Hermes 源码。找到 hermes_constants.py,一个函数暴露了真相:
def _get_platform_default_hermes_home() -> Path:
if sys.platform == "win32":
local_appdata = os.environ.get("LOCALAPPDATA", "").strip()
base = Path(local_appdata) if local_appdata else Path.home() / "AppData" / "Local"
return base / "hermes"
return Path.home() / ".hermes"
Linux/macOS 上,Home 就是 ~/.hermes,很直觉。但 Windows 上,Hermes 走了 %LOCALAPPDATA% 路径,最终指向:
C:Users<你的用户名>AppDataLocalhermes
终端里敲 ~ 展开的是 C:Users<你的用户名>。两个完全不同的地方。
所以实际状态是这样的:
~/.hermes/ | AppDataLocalhermes | |
|---|---|---|
| 谁在读 | 没人 | Hermes 全家桶 |
| 模型配置 | 有(mimo-v2.5) | 空 |
| API Key | 有 | 无 |
| Gateway 进程 | 无 | 运行中 |
| Cron 任务 | 喝水提醒(从没执行) | 天气播报(正常) |
| 历史会话 | 964 条 | 349 条 |
| Skills | 26 个 | 18 个 |
~/.hermes/ 成了一个孤儿目录——可能是早期安装时手动创建的,也可能是旧版本遗留,但当前版本的 Hermes 根本不读它。
喝水提醒就是这么死的:写到了对的格式,但放到了对的位置的隔壁房间。
3. CLI 和 Gateway:一个脑袋两只手
很多人以为 CLI 和 Gateway 是两套系统,其实不是。
CLI 就是终端里敲 hermes 跟 AI 聊天——你说话,它回答,关了终端就没了。
Gateway 是个常驻后台的服务,干三件事:连接微信、Telegram 这些消息平台,驱动 Cron 定时任务,暴露 API Server 供 Web UI 连接。
它们读的是同一个 Home 目录。Gateway 启动脚本里还显式设了环境变量:
set "HERMES_HOME=C:Users<你的用户名>AppDataLocalhermes"
不存在「CLI 配置好了但 Gateway 没配置」这种事——配置一份,两边共享。反过来也一样,Gateway 的配置缺了什么,CLI 也帮不上忙。
4. 给 Gateway 打补丁
Gateway 当时有两个问题:不知道用什么模型,也没有 API Key。定时任务自然跑不成功。
修复很简单,把孤儿目录里的配置搬过来:
# 模型配置
python -c "
import yaml
with open('~/.hermes/config.yaml') as f: src = yaml.safe_load(f)
with open('AppData/Local/hermes/config.yaml') as f: cfg = yaml.safe_load(f)
cfg['model'] = src.get('model', {})
yaml.dump(cfg, open('AppData/Local/hermes/config.yaml','w'))
"# API Key
grep "YOUR_API_KEY" ~/.hermes/.env >> AppData/Local/hermes/.env# 重启
hermes gateway restart
三行命令,问题解决。
5. Web UI:不止终端能聊
Hermes Gateway 内置了一个 OpenAI 兼容的 API Server,在 http://localhost:8642/v1 用标准格式调用就行。所有支持 OpenAI API 的前端都能对接。
这里选了 Open WebUI,Docker 一行搞定:
docker run -d
--name open-webui
--restart always
-p 3000:8080
-e OPENAI_API_BASE_URLS="http://host.docker.internal:8642/v1"
-e OPENAI_API_KEYS=***
-e DEFAULT_MODELS="hermes-agent"
-e WEBUI_NAME="Hermes AI"
ghcr.io/open-webui/open-webui:main
浏览器打开 localhost:3000,注册,选模型,聊天。比终端丝滑多了。
但这里又踩了一个坑:Open WebUI 打开后显示「暂无可用模型」。
查 Gateway 日志:
API server rejected invalid API key
Key 明明写在 .env 里了啊?
翻源码找到原因。API Server 的认证逻辑:
self._api_key = extra.get("key", os.getenv("API_SERVER_KEY", ""))
它优先从 config.yaml 的 platforms.api_server.extra.key 读,环境变量只是 fallback。Gateway 进程启动时 .env 的加载可能有时序问题,key 没被读到。
直接在 config.yaml 的 platforms 段里写死 key,不依赖环境变量:
platforms:
api_server:
enabled: true
extra:
key: "你的密钥"
port: 8642
重启 Gateway,Open WebUI 立刻能连上了。
6. 喝水提醒复活记
所有问题解决后,该把喝水提醒找回来了。
从孤儿目录的 jobs.json 里把任务提出来,追加到正确位置的 jobs.json:
import json
with open('AppData/Local/hermes/cron/jobs.json') as f:
current = json.load(f)
with open('~/.hermes/cron/jobs.json') as f:
old = json.load(f)
current['jobs'].append(old['jobs'][0])
with open('AppData/Local/hermes/cron/jobs.json', 'w') as f:
json.dump(current, f, indent=2, ensure_ascii=False)
顺便把投递目标改了——旧配置 deliver: "local" 只存本地文件,改成微信的 channel ID 才能推送。
用 cronjob run 手动触发一次,微信里收到提醒,水喝上了。
另外天气任务原来用的 mimo-v2.5-pro,查个天气没必要上 Pro,降级到 mimo-v2.5 省点钱。
7. Hermes Home 都有啥
最后把 AppDataLocalhermes 里的东西捋一遍,以后遇到问题知道往哪看。
配置方面:config.yaml 是主配置,.env 放 API Key,SOUL.md 是 AI 的人格设定,auth.json 是 OAuth 凭证。
数据库有三个:state.db 最值钱,存了所有聊天记录和会话历史,5.7M;kanban.db 是多 Agent 协作的看板;response_store.db 给 API Server 用。
Gateway 相关的文件:gateway.pid 和 gateway.lock 管进程,gateway_state.json 记运行状态,gateway-service/Hermes_Gateway.cmd 是 Windows 服务启动脚本,channel_directory.json 索引已连接的聊天频道。
目录方面:hermes-agent/ 最大,源码加 Python 虚拟环境,五万三千多个文件。skills/ 是技能库,Hermes 的核心能力都在这。cron/ 放定时任务配置和历史输出。sessions/ 是会话索引。memories/ 存 AI 的长期记忆。weixin/ 是微信连接配置。logs/ 是日志,出问题先看这里。
可以放心删的:audio_cache/、image_cache/、cache/ 这些缓存删了自动重建;logs/ 不影响功能;images/、pastes/ 是临时文件。
绝对不能删的:config.yaml、state.db、.env、hermes-agent/、skills/——删了哪个都是灾难。
后记
几个容易被忽视的点:
Windows 的 Home 路径不直觉,这是整个问题的根源。Linux 用户不会遇到,Windows 用户迟早会。Hermes 用 %LOCALAPPDATA% 而不是 $HOME,本身是合理的 Windows 开发规范,但确实容易让人困惑。
配置只有一份,CLI 和 Gateway 共享同一个 Home。不存在「CLI 配好了 Gateway 还没」的情况,配置的时候注意看路径就行。
API Server 的认证走 config.yaml,环境变量可以设,但 config.yaml 里的 platforms 配置优先级更高。建议直接写在 config 里。
Cron 任务的模型要匹配复杂度,查天气用基础模型就够了,Pro 留给需要深度推理的场景。
迁移数据要验证,手动改 jobs.json 可以迁移 Cron 任务,但改完一定要用 cronjob run 测试一下,确认能正常执行和投递。
这篇文章基于 Hermes Agent v0.15.1,Windows 11 环境。如果也在折腾 Hermes,希望这些经验能帮你少走点弯路。