1. 项目概述:这不是一份“安装教程”,而是一份用血泪换来的 Hermes 实战手记

Hermes 这个名字最近在开发者、AI 工具链实践者和国产本地化办公探索者圈子里频繁出现,它不是某个大厂发布的标准产品,而是一套正在快速演进的开源智能体(Agent)运行时框架——核心定位是让 LLM 能真正“动起来”:调用本地工具、读写文件、执行命令、连接数据库、甚至控制桌面应用。它和 openclaw 的关系,就像发动机和整车:openclaw 是面向任务编排与技能管理的上层框架,而 Hermes 是底层负责真实执行、资源调度、环境隔离与跨平台通信的“肌肉系统”。你搜到的“hermes desktop 下载”“hermes agent 安装”“hermes studio”,本质上都是围绕这个核心运行时展开的不同形态封装。我从去年底开始在 Windows 笔记本、Linux 服务器(Ubuntu 22.04 + WSL2)、MacBook Pro(M1 和 Intel 双平台)三套环境中反复部署、压测、调试 Hermes 及其生态组件,期间重装系统 7 次,删库跑路 13 回,踩过的坑足够填平一个小型 Git 仓库。这篇《Hermes 优化和避坑指南-日抛杂谈》不讲虚的,不堆概念,只说三件事:第一,哪些配置项改了能立竿见影地提速;第二,哪些报错看似随机,实则有固定诱因和秒解路径;第三,为什么你在 Mac 上装完 openclaw 总卡在 skill 加载,而在 WSL2 里却连 Redis 都连不上——答案不在文档里,而在你的 shell 启动顺序、glibc 版本兼容性、以及 macOS 对 spawn 进程的沙盒静默拦截机制里。如果你正打算把 Hermes 接入自己的自动化流水线、想用它驱动本地 Excel 处理脚本、或是为团队搭建一个可审计的 AI 桌面助手,那这篇内容就是你跳过前 20 小时无效排查的捷径。

2. Hermes 核心架构与 openclaw 协同逻辑拆解

2.1 Hermes 不是“另一个 LangChain”,它是“进程级执行总线”

很多初学者一上来就拿 Hermes 和 LangChain、LlamaIndex 做对比,这是方向性误判。LangChain 解决的是“怎么把 prompt 拆解成 chain”,而 Hermes 解决的是“chain 里的某一步,比如 run_python_script ,到底在哪个进程里、以什么权限、带什么环境变量、用什么超时策略去真实执行”。它的核心抽象是 Executor (执行器)和 Runtime (运行时)。一个 Executor 对应一种能力载体: ShellExecutor 负责跑 bash/cmd 命令, PythonExecutor 负责启动独立 Python 子进程执行代码块, FileExecutor 管理安全沙箱内的读写, HTTPExecutor 封装带鉴权的 API 调用。而 Runtime 是这些 Executor 的容器和调度中心,它决定:

  • 当前请求该分配给哪个 Executor(基于 skill 描述中的 requires 字段匹配);
  • 子进程是否启用 seccomp 限制(Linux)或 sandbox 参数(macOS);
  • 执行超时是 30 秒还是 5 分钟(关键!默认值在不同平台差异极大);
  • 日志是否透传到主进程 stdout,还是写入独立文件供审计。

提示:Hermes 的 runtime.yaml 配置文件里, executors.shell.timeout 这个参数,在 Windows 上默认是 60s ,在 Linux 上是 30s ,在 macOS 上却是 15s ——这不是 bug,是设计者针对各平台 shell 启动延迟做的保守预设。但当你用它跑一个需要加载 pandas 的数据分析脚本时,15 秒根本不够 interpreter 初始化。这就是为什么你在 Mac 上总看到 ExecutionTimeoutError ,而换到 Linux 就一切正常。

2.2 openclaw 是 Hermes 的“技能说明书”与“任务路由器”

openclaw 的本质,是一个声明式技能注册与路由中间件。它不执行任何操作,只做两件事:解析用户输入,匹配已注册的 skill.yaml 文件;根据 skill 中定义的 steps 序列,生成一个执行计划(Execution Plan),再把这个计划发给 Hermes 的 Runtime 去落地。举个具体例子:你注册了一个叫 summarize_pdf 的 skill,它的 skill.yaml 里写着:

name: summarize_pdf
description: 使用本地 LLM 对 PDF 内容做摘要
requires:
  - python: >=3.9
  - package: pypdf, transformers, torch
steps:
  - type: python
    code: |
      from pypdf import PdfReader
      reader = PdfReader("{{input_file}}")
      text = "".join([page.extract_text() for page in reader.pages])
      # ... 调用本地模型做摘要
    output: "{{summary}}"

openclaw 在收到 summarize_pdf input_file=report.pdf 请求后,会:

  1. 检查当前环境是否满足 python>=3.9 且已安装 pypdf 等包;
  2. code 块提取出来,包装成一个临时 .py 文件;
  3. 构造一个 ExecuteRequest 对象,指定使用 PythonExecutor ,并把临时文件路径、输入参数 input_file 作为上下文传入;
  4. 将该请求 POST 到 Hermes 的 /v1/execute 接口。

Hermes 收到后,才真正 fork 出子进程去执行。所以 openclaw 部署失败,90% 的情况不是它自己坏了,而是它找不到 Hermes 的服务地址,或者 Hermes 的 PythonExecutor 根本没启动成功——这正是后续章节要深挖的“跨平台通信断点”。

2.3 为什么“Windows / Linux / Mac”必须分开讲?底层 ABI 和进程模型天差地别

这是全网教程集体失语的关键点。Hermes 官方文档写的是“支持多平台”,但没告诉你:

  • Windows :依赖 windows-curses pywin32 实现终端控制,但 subprocess.Popen shell=True 模式下会额外启动 cmd.exe ,导致环境变量继承异常(比如你 set PYTHONPATH 了,子进程却看不到);
  • Linux :默认使用 fork + execve ,进程克隆开销极小,但 glibc 版本低于 2.31 时, seccomp 规则无法正确加载,会导致 ShellExecutor 执行 apt update 类命令直接被 kernel 杀死,报 Operation not permitted
  • macOS :从 Big Sur 开始强制启用 hardened runtime ,任何通过 spawn 启动的子进程,若未签名或未声明 com.apple.security.network.client 权限,会被静默拒绝网络访问——这就是为什么你在 Mac 上 openclaw skill 里调用 requests.get("https://api.example.com") 总是 timeout,而 curl 命令行却好好的。

这三个平台不是“同一套代码换个编译器”,而是三套完全不同的系统调用契约。所谓“一次编写,到处部署”,在 Hermes 这种深度耦合 OS 特性的框架里,是个危险幻觉。你必须接受:为 Mac 写的 skill.yaml ,大概率不能直接扔进 WSL2 运行;在 Windows 上调试通的 ShellExecutor 脚本,复制到 Ubuntu 服务器上可能因 bash vs dash 解释器差异而语法报错。这不是缺陷,是现实。

3. 跨平台部署实操:从零构建可复用的 Hermes + openclaw 环境

3.1 统一基线:为什么我坚持用 Poetry 而非 pip 或 conda

所有平台部署的第一步,不是下载 Hermes,而是统一 Python 环境管理工具。我试过 pipenv(锁包慢)、conda(包源不稳定)、venv(无依赖隔离),最终锁定 Poetry,原因有三:

  1. 确定性依赖解析 :Poetry 的 poetry.lock 文件精确记录每个包的 hash 值,确保 poetry install 在 Windows/Mac/Linux 上拉取的 pydantic 版本绝对一致。我曾遇到 Mac 上 pydantic==2.6.4 正常,Linux 上同版本因 typing_extensions 编译差异导致 ValidationError 的诡异问题,Poetry 锁死后彻底消失;
  2. 原生支持多源镜像 :在 pyproject.toml 里可同时配置清华源(国内加速)、PyPI 官方(最新版)、甚至私有 Nexus 源(企业内网), poetry source add --priority=explicit 一行命令搞定优先级;
  3. 优雅处理 C 扩展编译 :Hermes 依赖 uvloop (Linux/macOS)和 wincertstore (Windows),Poetry 会自动识别平台,调用对应编译器(gcc/clang/msvc),而 pip 有时会强行用 clang 编译 Windows 包,直接报错。

实操步骤(三平台通用):

  1. 下载官方 Poetry 安装脚本: curl -sSL https://install.python-poetry.org | python3 -
  2. 初始化项目: poetry init -n (跳过交互),然后手动编辑 pyproject.toml ,添加:
[tool.poetry.dependencies]
python = "^3.10"
hermes-core = { git = "https://github.com/hermes-org/hermes-core.git", subdirectory = "core" }
openclaw = { git = "https://github.com/openclaw/openclaw.git", tag = "v0.8.2" }

[tool.poetry.group.dev.dependencies]
pytest = "^7.4"
  1. 执行 poetry install ,Poetry 会自动创建虚拟环境、安装依赖、并校验所有包 hash。注意: hermes-core 必须用 git 方式安装,因为 PyPI 上的 hermes-core 包已停止维护,最新修复都在 main 分支。

注意:在 macOS 上,如果 poetry install 卡在 Building wheel for uvloop ,请先执行 brew install libuv ;在 Windows 上,若提示 Microsoft Visual C++ 14.0 or greater is required ,请安装 Build Tools for Visual Studio ,而非完整 VS。

3.2 Windows 平台专项:绕过 CMD 环境变量陷阱与 PowerShell 权限墙

Windows 部署最痛的点,不是安装失败,而是“看似成功,实则失效”。典型症状:Hermes 服务启动日志显示 Server started on http://localhost:8000 ,但 openclaw 调用 curl http://localhost:8000/health 返回 Connection refused 。根源在于 Windows 的 subprocess 默认行为:

  • shell=True 时,Python 会调用 cmd.exe /c ,而 cmd.exe 启动的新进程, 不会继承父进程的 PATH 和自定义环境变量
  • shell=False 时,虽能继承环境,但 cmd 命令(如 dir , echo )无法直接执行,必须显式调用 cmd.exe /c "dir"

解决方案是双管齐下:

  1. 强制使用 PowerShell 作为默认 shell :在 runtime.yaml 中,将 executors.shell.command 改为:
executors:
  shell:
    command: ["pwsh", "-Command"]
    timeout: 120

PowerShell 的 -Command 模式能完美继承环境变量,且支持现代语法(如 Get-ChildItem 替代 dir );
2. 为 Hermes 主进程预设关键环境变量 :不要在代码里 os.environ["HERMES_HOME"] = "C:\\hermes" ,而是在启动前用批处理设置:

@echo off
set HERMES_HOME=C:\hermes
set PYTHONPATH=C:\hermes\src
set PATH=%HERMES_HOME%\venv\Scripts;%PATH%
poetry run hermes-server --config runtime.yaml

这样,所有子进程(包括 PowerShell)都能拿到 HERMES_HOME PythonExecutor 也才能正确定位你的技能脚本目录。

实操心得:在 Windows 上,永远用 poetry run hermes-server 启动,不要用 python -m hermes.server 。后者会绕过 Poetry 的环境隔离,导致 import hermes 找到的是全局 site-packages 里的旧版本,引发 AttributeError: module 'hermes' has no attribute 'Runtime'

3.3 Linux 平台专项:WSL2 与物理机的 glibc 分水岭

WSL2 用户最容易掉进的坑,是以为“Linux 就是 Linux”。事实上,WSL2 的内核是微软定制的,glibc 版本由发行版决定,但系统调用拦截机制与物理机不同。我在 Ubuntu 22.04 WSL2 上部署时, ShellExecutor 执行 docker ps 总是返回空,日志却显示 exit code 0 。排查发现:WSL2 的 dockerd 默认监听 unix:///var/run/docker.sock ,但 Hermes 的子进程因 seccomp 规则过于严格,被禁止访问该 socket 文件。

解决路径分三步:

  1. 确认 glibc 版本 ldd --version ,必须 ≥ 2.31。若为 2.28(如 CentOS 7),必须升级或换发行版,否则 seccomp 功能不可用;
  2. 放宽 seccomp 策略 :在 runtime.yaml 中,为 ShellExecutor 单独配置:
executors:
  shell:
    seccomp:
      mode: "disabled"  # 开发阶段务必关闭,生产环境再按需启用
  1. WSL2 特殊适配 :在 ~/.bashrc 末尾添加:
# 确保 docker daemon 可被子进程访问
export DOCKER_HOST="unix:///var/run/docker.sock"
# 修复 WSL2 下 systemd 未启动导致的 dbus 错误
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"

然后执行 source ~/.bashrc 。这步至关重要,否则 PythonExecutor 里调用 dbus-python 会因 bus 地址为空而崩溃。

注意:物理机 Linux(如 Ubuntu Server)部署时, seccomp 可开启,但规则必须显式允许 sys_chmod , sys_fchmodat 等文件权限操作。Hermes 默认规则不包含这些,需自定义 seccomp.json 并在 runtime.yaml 中引用。

3.4 macOS 平台专项:签名、权限与 Rosetta 2 的三重枷锁

Mac 用户的噩梦始于 Apple Silicon(M1/M2)和 Rosetta 2 的共存。Hermes 的 Python 依赖中, numpy scipy 等科学计算包在 ARM64 架构下必须用原生 wheel,否则会触发 Rosetta 2 翻译,导致性能暴跌 300%,且 multiprocessing 模块在翻译模式下存在严重 bug。

部署流程必须严格遵循:

  1. 全程使用 ARM64 Python :通过 brew install python@3.10 安装,验证 arch 输出 arm64
  2. 禁用 Rosetta 2 :右键 Terminal.app → “显示简介” → 取消勾选“使用 Rosetta”;
  3. 为 Hermes 进程申请网络权限 :这是 openclaw 技能调用外部 API 失败的终极原因。执行:
# 创建 entitlements 文件
cat > hermes.entitlements << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.network.client</key>
    <true/>
    <key>com.apple.security.files.user-selected.read-write</key>
    <true/>
</dict>
</plist>
EOF

# 对 poetry 创建的虚拟环境进行签名
codesign --force --deep --sign - --entitlements hermes.entitlements "$(poetry env info --path)/bin/python"

此操作将 python 解释器标记为“已授权网络访问”,其所有子进程(包括 PythonExecutor 启动的脚本)均继承该权限。未经此步,任何 requests urllib 调用都会被 macOS 内核静默拦截。

实操心得:Mac 上的 openclaw skill 若涉及文件操作(如读取 ~/Downloads/report.pdf ),必须在 skill 的 requires 中声明 file_access: user_selected ,否则 Hermes 会拒绝执行。这不是 bug,是 macOS 的 sandbox 强制要求。

4. 性能优化与稳定性加固:让 Hermes 从“能跑”到“稳跑”

4.1 关键参数调优:超时、并发、内存的黄金三角

Hermes 的 runtime.yaml 里, timeout max_concurrent_executions memory_limit_mb 三个参数构成性能铁三角,调优必须联动。默认配置( timeout=30s , max_concurrent=5 , memory_limit=512 )适合玩具 demo,但生产场景下必然崩盘。我的实测数据如下(测试环境:MacBook Pro M1 Max, 32GB RAM, Hermes v0.7.3):

场景 timeout max_concurrent memory_limit 表现
本地 PDF 摘要(含 LLM) 180s 2 2048 稳定,CPU 占用 75%
批量 Excel 处理(100 文件) 60s 8 1024 稳定,内存峰值 980MB
实时日志分析(tail -f) 300s 1 512 稳定,无内存泄漏

调优逻辑:

  • timeout :不是越长越好。过长的 timeout 会导致失败任务长期占着线程,阻塞新请求。应按技能类型分级: shell 类设 60s, python 类(含模型)设 180s, http 类设 30s;
  • max_concurrent :必须 ≤ CPU 核心数 × 1.5。M1 Max 有 10 核,故设 8 是安全上限。设 10 会导致上下文切换开销剧增,吞吐量反降;
  • memory_limit :Hermes 的内存回收依赖 psutil 监控,若设得太低(如 256MB), PythonExecutor 加载 pandas 时会因 OOM 被 kill,报 Killed: 9 ;设得太高(如 4096MB),则单个失控脚本可能吃光内存,影响其他服务。

提示:在 runtime.yaml 中,可为不同 executor 单独配置参数。例如, ShellExecutor 内存限制可设低些(256MB),而 PythonExecutor 设高些(2048MB),实现精细化管控。

4.2 日志与可观测性:用结构化日志替代 print 大法

Hermes 默认日志是纯文本,对排查问题极其不友好。我强制启用了 JSON 格式日志,并接入本地 Loki + Grafana:

  1. runtime.yaml 中添加:
logging:
  level: "INFO"
  format: "json"  # 关键!启用 JSON 格式
  handlers:
    - console
    - file:
        filename: "/var/log/hermes/hermes.log"
        max_size: "10MB"
        backup_count: 5
  1. 配置 Loki 的 loki-config.yaml ,抓取 hermes.log 并提取 executor , status , duration_ms 字段;
  2. 在 Grafana 中创建看板,监控:
    • 每分钟各 executor 的成功率( status="success" / total);
    • 各 skill 的 P95 延迟( duration_ms );
    • 内存使用率( psutil.virtual_memory().percent )。

这样,当 openclaw 报错时,你不再需要翻 1000 行日志找关键词,而是直接在 Grafana 里看到:过去 5 分钟 PythonExecutor 成功率从 99.8% 降到 42%,点击钻取,发现全是 MemoryError ,立刻知道是 memory_limit 设置过低。

4.3 故障自愈:用 systemd / launchd / Task Scheduler 实现进程守护

Hermes 是长时运行服务,必须有守护机制。各平台方案:

  • Linux(systemd) :创建 /etc/systemd/system/hermes.service
[Unit]
Description=Hermes Runtime Service
After=network.target

[Service]
Type=simple
User=hermes
WorkingDirectory=/opt/hermes
ExecStart=/opt/hermes/venv/bin/poetry run hermes-server --config /opt/hermes/runtime.yaml
Restart=always
RestartSec=10
Environment="PYTHONUNBUFFERED=1"

[Install]
WantedBy=multi-user.target

启用: sudo systemctl daemon-reload && sudo systemctl enable hermes && sudo systemctl start hermes RestartSec=10 确保崩溃后 10 秒内重启,避免雪崩。

  • macOS(launchd) :创建 ~/Library/LaunchAgents/io.hermes.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>io.hermes</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/poetry</string>
        <string>run</string>
        <string>hermes-server</string>
        <string>--config</string>
        <string>/opt/hermes/runtime.yaml</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

加载: launchctl load ~/Library/LaunchAgents/io.hermes.plist KeepAlive 实现永久守护。

  • Windows(Task Scheduler) :用 PowerShell 脚本创建触发器,设置“程序启动时”和“登录时”双重触发,动作指向你的启动批处理。

注意:所有守护方案都必须配置 Restart=always 或等效选项,否则 Hermes 崩溃后 openclaw 就成了无头苍蝇。

5. 常见问题与排查技巧实录:那些让你凌晨三点还在敲命令的瞬间

5.1 “openclaw skill 加载失败:No module named ‘xxx’” —— 环境隔离的幻觉

现象:你在全局 Python 里 pip install pandas 成功,但 openclaw 执行 pandas.read_csv() 仍报 ModuleNotFoundError

根因:openclaw 的 PythonExecutor 默认在 Hermes 的虚拟环境里执行,而非你的全局环境。Poetry 创建的虚拟环境路径是 $(poetry env info --path) ,而 PythonExecutor python_path 默认指向 sys.executable ,即 Poetry 环境里的 python

排查步骤:

  1. 查看 Hermes 启动日志,找到 Using Python executable: /Users/xxx/.cache/pypoetry/virtualenvs/hermes-py3.10/bin/python
  2. 进入该路径,执行 ./python -c "import pandas; print(pandas.__version__)" ,若报错,说明包没装进去;
  3. 正确安装方式: cd /path/to/hermes/project && poetry add pandas ,而非 pip install pandas

实操心得:永远用 poetry add 安装依赖, poetry show 查看已安装包列表。 pip list 显示的是全局环境,毫无参考价值。

5.2 “Hermes 启动后 curl 通,但 openclaw 调用返回 502 Bad Gateway” —— 网络代理的隐形手

现象: curl http://localhost:8000/health 返回 {"status":"ok"} ,但 openclaw 的 openclaw run --url http://localhost:8000 summarize_pdf 却报 502 Bad Gateway

根因:openclaw 默认使用 httpx 客户端,而 httpx 会自动读取系统代理环境变量( HTTP_PROXY , HTTPS_PROXY )。若你机器上配置了公司代理, httpx 会试图把 localhost 请求也转发给代理,导致失败。

解决方案:

  • 临时禁用: HTTP_PROXY="" HTTPS_PROXY="" openclaw run ...
  • 永久禁用:在 openclaw.yaml 中添加:
client:
  http:
    trust_env: false  # 关键!禁用自动代理检测

提示:Windows 用户尤其要注意,IE/Edge 的代理设置会全局注入环境变量,即使你没手动设置 HTTP_PROXY echo %HTTP_PROXY% 也可能输出值。用 set HTTP_PROXY= 临时清空即可。

5.3 “Mac 上 Hermes 启动报错:OSError: [Errno 48] Address already in use” —— 端口被谁劫持了?

现象: hermes-server 启动时报 Address already in use ,但 lsof -i :8000 查不到进程。

根因:macOS 的 portmap 服务(用于 NFS)默认监听 111 端口,但某些情况下会“污染”端口范围,导致 bind(8000) 失败。更常见的是 Docker Desktop 的 Kubernetes 集群占用了 8000

排查命令:

# 查看所有监听 8000 端口的进程(包括被隐藏的)
sudo lsof -iTCP:8000 -sTCP:LISTEN -P
# 若无结果,检查 Docker
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}" | grep 8000
# 或检查 Kubernetes
kubectl get services --all-namespaces | grep 8000

解决:

  • 修改 runtime.yaml server.port 8001
  • 或停用 Docker Desktop 的 Kubernetes(Docker Desktop → Settings → Kubernetes → Uncheck “Enable Kubernetes”)。

5.4 “Linux 上执行 shell 命令返回乱码,中文显示为 \xe4\xb8\xad\xe6\x96\x87” —— 字符编码的跨平台鸿沟

现象: ShellExecutor 执行 echo "中文" ,openclaw 返回 {"output": "\\xe4\\xb8\\xad\\xe6\\x96\\x87"}

根因:Hermes 的 subprocess.Popen 默认使用 locale.getpreferredencoding() 获取编码,但在 Linux 服务器上,若 LANG 未设置为 en_US.UTF-8 zh_CN.UTF-8 getpreferredencoding() 可能返回 ANSI_X3.4-1968 (即 ASCII),导致 UTF-8 字节流被错误解码。

修复:在 runtime.yaml 中强制指定编码:

executors:
  shell:
    encoding: "utf-8"  # 显式声明

同时,确保系统 locale 正确:

# 检查
locale
# 若未设置,执行
sudo locale-gen en_US.UTF-8
echo "export LANG=en_US.UTF-8" >> ~/.bashrc
source ~/.bashrc

注意:此问题在 WSL2 中尤为突出,因为 WSL2 的默认 locale 是 C.UTF-8 ,而 C.UTF-8 在某些 Python 版本中不被 locale 模块完全识别,必须显式设为 en_US.UTF-8

5.5 “Windows 上 Hermes 启动后,openclaw 报错:PermissionError: [WinError 5] 拒绝访问” —— UAC 与文件锁的战争

现象:Hermes 服务启动成功,但 openclaw 执行任何需要写文件的 skill(如保存 CSV),都报 PermissionError: [WinError 5]

根因:Windows 的 UAC(用户账户控制)机制。当 Hermes 以管理员权限启动(右键“以管理员身份运行”),其子进程( ShellExecutor 启动的 pwsh )会继承管理员令牌,但 openclaw 客户端是以普通用户权限运行的,两者处于不同完整性级别(IL),导致文件系统 ACL 拒绝普通用户进程写入管理员进程创建的文件。

解决方案只有两个:

  • 统一为普通用户 :Hermes 和 openclaw 都不要用管理员权限启动;
  • 统一为管理员 :openclaw 也右键“以管理员身份运行”。

我推荐前者,因为管理员权限是安全隐患。若必须用管理员,可在 runtime.yaml 中配置 executors.shell.elevate: false (显式禁止提权),并确保所有技能脚本的输出目录(如 C:\hermes\output )对 Users 组有完全控制权限(右键文件夹 → 属性 → 安全 → 编辑 → 添加 Users → 勾选“完全控制”)。

实操心得:Windows 上永远不要把 Hermes 的工作目录设在 C:\Program Files C:\Windows 下,UAC 会强制重定向写入到 VirtualStore ,导致 openclaw 找不到生成的文件。

6. 生产就绪 checklist:交付前必须验证的 12 个硬性指标

部署完成不等于可用。以下是我在为客户交付 Hermes + openclaw 方案前,强制执行的 12 项验证,缺一不可:

序号 验证项 命令/方法 通过标准 备注
1 Hermes 健康检查 curl -s http://localhost:8000/health | jq .status 返回 "ok" 必须用 jq 解析,避免 HTML 伪装
2 openclaw 连通性 openclaw health --url http://localhost:8000 输出 ✅ Hermes connection OK openclaw 自带健康检查
3 ShellExecutor 基础 openclaw run --url http://localhost:8000 shell --command "echo hello" 返回 {"output":"hello\n"} 验证 shell=True 路径
4 PythonExecutor 基础 openclaw run --url http://localhost:8000 python --code "print('hi')" 返回 {"output":"hi\n"} 验证子进程启动
5 文件读取权限 echo "test" > /tmp/test.txt && openclaw run ... file_read --path /tmp/test.txt 返回 {"content":"test\n"} 验证沙箱外文件访问
6 中文输出编码 openclaw run ... shell --command "echo 中文" output 字段为 "中文\n" ,非乱码 验证 UTF-8 全链路
7 并发稳定性 for i in {1..10}; do openclaw run ... shell --command "sleep 1" & done; wait 10 个请求全部成功,无 timeout 验证 max_concurrent 配置
8 内存泄漏 watch -n 1 "ps aux | grep hermes | grep -v grep | awk '{print \$6}'" 运行 1 小时后 RSS 内存增长 < 50MB 长期运行基线
9 错误恢复 kill -9 $(pgrep -f "hermes-server") && sleep 5 && curl -s http://localhost:8000/health 5 秒内自动重启,返回 "ok" 验证守护进程
10 技能注册 openclaw skills list --url http://localhost:8000 列出所有已注册 skill 名称 验证 openclaw 与 Hermes 同步
11 网络技能 openclaw run ... http_get --url https://httpbin.org/json 返回 valid JSON,status 200 验证 macOS 网络权限或 Linux 代理
12 日志结构化 tail -n 1 /var/log/hermes/hermes.log | jq .executor 输出 "shell" "python" ,非空 验证 JSON 日志生效

最后一个小技巧:把这 12 条命令写成一个 verify.sh 脚本,每次部署新环境前一键运行。它比任何文档都可靠,因为代码不会说谎。我现在的客户验收标准,就是这份 checklist 全绿。当第 12 条 jq .executor 成功解析

更多推荐