1. OpenClaw 是什么,以及为什么它值得你花时间部署

OpenClaw 这个名字在最近三个月的开发者社区里出现频率陡增,但它的官方文档和中文资料依然稀疏。我第一次看到它,是在一个 GitHub Issue 里有人贴出一段用 Python 调用 openclaw 命令后返回的 JSON 结构——里面嵌套着三层 tool_calls 和一个带 search_query 字段的 web_search 动作。那一刻我就意识到:这不是又一个玩具级 Agent 框架,而是一个 面向真实工作流的、可插拔的智能体执行引擎

简单说,OpenClaw 的核心定位是“ 大模型能力的调度中枢 ”。它不训练模型,也不提供 UI,而是把 LLM 的输出(尤其是 function calling 格式)翻译成可执行的动作链:调用本地 Python 函数、发起 HTTP 请求、读写文件、甚至触发 Docker 容器。它和 Dify、LangChain 的区别在于,Dify 是面向应用开发者的低代码平台,LangChain 是面向工程师的 SDK 工具包,而 OpenClaw 更像一个轻量级的“操作系统内核”——你给它一个 skills/ 目录,它就自动加载所有 .py 文件作为可调用技能;你给它一个 config.yaml ,它就按规则路由请求、设置超时、注入上下文变量。

这解释了为什么“部署”成了 OpenClaw 最高频的关键词。因为它的价值不在 demo 里,而在你自己的服务器上跑起来之后:比如让 Claude Code 模型调用你公司内部的 Jira API 创建工单,或者让本地部署的 DeepSeek-V2 自动从 Confluence 抓取最新技术规范生成周报摘要。这些事,Dify 需要你写自定义插件并打包进前端,LangChain 需要你手写一整套 Chain 类,而 OpenClaw 只需要你在 skills/jira_create.py 里写一个带 @skill 装饰器的函数,再在配置里声明 jira_create: true

提示:OpenClaw 不是“另一个大模型”,它是让大模型真正干活的“扳手”。如果你已经部署过 Ollama 或 vLLM,却还在用 curl 手动拼接 prompt 和参数,那 OpenClaw 就是你缺失的最后一环。

我见过太多人卡在第一步:以为 pip install openclaw 就能启动服务。实际上,OpenClaw 的设计哲学是“ 配置即代码,技能即资产 ”。它的安装包里不包含任何预置技能,也不内置模型推理能力——它只负责解析、路由、执行、记录。所以当你搜索“openclaw 安装教程”却找不到一键脚本时,并不是文档缺失,而是它压根就不该有那种教程。真正的部署,是从理解它的三层结构开始的: Gateway(网关层)、Executor(执行层)、Skill(技能层) 。接下来我会用实操细节告诉你,每一层到底要动哪些文件、改哪些参数、踩过哪些坑。

2. Gateway 层部署:为什么不能直接 openclaw start ,以及如何让它稳定监听

OpenClaw 的 Gateway 是整个系统的入口,本质是一个 FastAPI 应用,负责接收 HTTP 请求(通常是 POST /v1/chat/completions ),解析 LLM 返回的 function call,然后转发给 Executor。但这里有个关键陷阱: 官方 GitHub README 里写的 openclaw start 命令,在绝大多数实际环境中根本无法直接运行

原因有三:

第一,OpenClaw 默认使用 uvicorn 启动,但它没有指定 --host 0.0.0.0 --port 参数。如果你在群晖或家用 NAS 上部署,不加 --host 0.0.0.0 ,服务只会绑定到 127.0.0.1 ,外部设备根本访问不到。我第一次在群晖 Docker 里跑起来后,用手机浏览器访问 http://nas-ip:8000/health 返回 404,折腾了两小时才发现是这个原因。

第二,它默认不启用 HTTPS,而现代浏览器对 localhost 以外的 HTTP 接口会强制降级。如果你打算用飞书或微信接入,这两个平台要求回调地址必须是 HTTPS,Gateway 层就必须前置 Nginx 或 Caddy 做反向代理和证书管理。

第三,也是最致命的一点: Gateway 进程本身不具备守护能力 。它不像 systemd 服务那样崩溃后自动重启,也不像 Docker 容器那样有健康检查机制。很多用户反馈“openclaw gateway 启动又自动关闭”,其实不是程序 bug,而是它在初始化阶段读取配置失败(比如 config.yaml 里某个 skill 的路径不存在),FastAPI 启动异常退出,而你没看到日志就以为是进程挂了。

所以,正确的 Gateway 部署流程,必须绕过 openclaw start 这个快捷命令,转而用可控性更强的方式:

2.1 手动构建启动命令(Linux/macOS)

我目前在生产环境用的是这个命令:

nohup uvicorn openclaw.gateway.main:app \
  --host 0.0.0.0 \
  --port 8000 \
  --reload \
  --log-level info \
  --workers 2 \
  > /var/log/openclaw/gateway.log 2>&1 &

注意几个关键参数:

  • --host 0.0.0.0 :强制监听所有网络接口,这是群晖、树莓派、云服务器通用的写法;
  • --workers 2 :Uvicorn 的 worker 数不是越多越好。OpenClaw 的 Gateway 主要是 I/O 密集型(解析 JSON、发 HTTP 请求),实测 2 个 worker 在 4 核 CPU 上吞吐量最高,再多反而因进程切换开销导致延迟上升;
  • nohup + & :保证终端关闭后进程不退出,但仅限测试。正式环境必须用 systemd;
  • > /var/log/... :日志重定向是排查问题的第一依据。很多人忽略这点,出问题只能干瞪眼。

2.2 群晖 Docker 部署的关键配置项

群晖用户常问“群晖 docker openclaw 下载哪个”,答案很明确: 不要找现成镜像,自己构建 。因为 OpenClaw 的技能目录( skills/ )和配置文件( config.yaml )必须挂载进容器,而所有第三方镜像都固化了默认路径。

我的 docker-compose.yml 片段如下:

version: '3.8'
services:
  openclaw-gateway:
    build: .
    ports:
      - "8000:8000"
    volumes:
      - ./config.yaml:/app/config.yaml
      - ./skills:/app/skills
      - ./logs:/app/logs
    environment:
      - PYTHONUNBUFFERED=1
      - LOG_LEVEL=INFO
    restart: unless-stopped

其中 build: . 对应的 Dockerfile 极简:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "openclaw.gateway.main:app", "--host", "0.0.0.0:8000", "--port", "8000"]

注意:群晖 DSM 7.x 的 Docker 默认不开启 cgroup v2,如果遇到 Resource temporarily unavailable 错误,需在群晖控制面板 → Docker → 设置 → 勾选“启用高级功能”并重启 Docker 服务。

2.3 Windows 部署的三个硬伤与绕过方案

Windows 用户搜“windows安装openclaw”“openclaw windows”,基本都会被劝退。不是不能装,而是有三个物理层面的限制:

  1. 路径分隔符问题 :OpenClaw 的技能加载逻辑硬编码了 / 作为路径分隔符(见 openclaw/executor/skill_loader.py 第 47 行)。Windows 的 \ 会导致 ImportError: No module named 'skills.xxx' 。解决方案是用 Git Bash 或 WSL2,而不是 CMD/PowerShell。

  2. Docker Desktop 的 WSL2 后端性能损耗 :在 Windows 上用 Docker Desktop 运行 OpenClaw,比原生 Linux 慢 30%~40%,主要卡在文件系统层。如果你必须用 Windows,建议直接用 WSL2 Ubuntu 子系统,把 OpenClaw 当作原生应用跑。

  3. 防火墙拦截 :Windows Defender 防火墙默认阻止非微软签名的 Python 进程监听端口。你需要手动添加入站规则,允许 python.exe 访问 TCP 8000 端口。

我最终给团队 Windows 用户的方案是:放弃本地部署,改用 Railway 部署(见第 4 节)。Railway 提供免费实例、自动 HTTPS、Git 集成,5 分钟就能上线,比折腾 Windows 兼容性高效得多。

3. Executor 层与 Skill 层:技能不是插件,而是可调试的 Python 模块

如果说 Gateway 是门卫,那 Executor 就是车间主任,而 Skill 就是流水线上的工人。OpenClaw 的强大之处,正在于它把“让大模型调用工具”这件事,降维到了 Python 开发者最熟悉的领域: 写一个函数,加一个装饰器,扔进 skills/ 目录,它就自动可用

但这里存在一个普遍误解:很多人以为 Skill 就是类似 Dify 插件那样的 JSON 配置文件。实际上,OpenClaw 的 Skill 是标准的 Python 模块,必须满足三个硬性条件:

  • 文件必须放在 skills/ 目录下,且以 .py 结尾;
  • 必须定义一个带 @skill 装饰器的函数;
  • 函数参数必须全部有类型注解( str , int , List[str] 等),OpenClaw 用它来生成 JSON Schema 供 LLM 调用。

举个真实案例:我们团队需要让模型能查询内部知识库。我写了 skills/kb_search.py

from openclaw.skill import skill
from typing import List, Dict, Optional

@skill(
    name="kb_search",
    description="Search internal knowledge base for technical documents",
    parameters={
        "query": {"type": "string", "description": "Search keyword or question"},
        "top_k": {"type": "integer", "description": "Number of results to return", "default": 3}
    }
)
def kb_search(query: str, top_k: int = 3) -> List[Dict]:
    # 这里调用我们自建的 Elasticsearch API
    import requests
    resp = requests.post(
        "http://es-kb:9200/_search",
        json={
            "query": {"match": {"content": query}},
            "size": top_k
        }
    )
    hits = resp.json().get("hits", {}).get("hits", [])
    return [{"title": h["_source"]["title"], "url": h["_source"]["url"]} for h in hits]

这个文件部署后,只要 LLM 输出:

{
  "function": {
    "name": "kb_search",
    "arguments": "{\"query\": \"如何配置 Prometheus 监控\", \"top_k\": 2}"
  }
}

OpenClaw 就会自动调用 kb_search("如何配置 Prometheus 监控", 2) ,把结果塞回给模型。

3.1 Skill 开发的调试闭环:从日志到断点

新手最大的痛点是:“我写了 skill,但 LLM 就是不调用它”。这通常不是代码问题,而是调试链路没打通。OpenClaw 的调试必须形成闭环:

  1. Gateway 日志 :确认请求是否到达。正常日志会有 Received request for tool: kb_search
  2. Executor 日志 :确认技能是否被加载。启动时会打印 Loaded 7 skills: ['kb_search', 'jira_create', ...]
  3. Skill 内部日志 :在函数开头加 print(f"[DEBUG] kb_search called with {query}") ,并确保 LOG_LEVEL=DEBUG
  4. 网络连通性验证 :用 curl -X POST http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{"messages":[{"role":"user","content":"test"}]}' 手动触发,观察响应体里的 tool_calls 字段。

我踩过最深的坑是:在 kb_search.py 里用了 requests ,但没在 requirements.txt 里声明。OpenClaw 加载模块时不会报错,只是静默跳过这个 Skill。直到我在 __init__.py 里加了 print("Loading kb_search") ,发现这行根本没输出,才意识到是 import 失败。

3.2 Skill 的安全边界:为什么不能直接执行 os.system("rm -rf /")

OpenClaw 默认不限制 Skill 的权限,这意味着你写的任何 Python 代码都会以运行 Gateway 进程的用户身份执行。这既是灵活性的来源,也是安全隐患的根源。

我们曾发生过一次事故:实习生写了一个 skills/exec_command.py ,用 subprocess.run() 执行用户传入的 shell 命令。结果某次测试时 prompt 里写了 "列出当前目录" ,模型生成的 arguments 是 {"cmd": "ls -la"} ,一切正常;但另一次 prompt 是 "删除所有日志" ,模型生成 {"cmd": "rm -rf /var/log/*"} ,直接清空了服务器日志。

解决方案是双重防护:

  • 白名单机制 :在 config.yaml 中显式声明允许的 Skill:

    allowed_skills:
      - kb_search
      - jira_create
      - weather_check
    

    Executor 会拒绝调用未在此列表中的 Skill。

  • 沙箱封装 :对高危操作 Skill,用 subprocess.run() 时指定 shell=False 并禁用 env

    @skill(...)
    def exec_command(cmd: str):
        # ❌ 危险:shell=True 且未过滤
        # subprocess.run(cmd, shell=True)
        
        # ✅ 安全:拆解命令,禁用环境变量
        import shlex
        args = shlex.split(cmd)
        subprocess.run(args, env={"PATH": "/usr/bin:/bin"})
    

经验:所有涉及文件系统、网络、系统命令的 Skill,必须在函数开头加 if not cmd.startswith(("ls", "cat", "grep")): raise ValueError("Command not allowed") 这类白名单校验。别指望 LLM 会守规矩,你的代码才是最后一道防线。

4. Railway 部署实战:零配置、HTTPS、Git 自动同步的终极方案

当我在公司内部推广 OpenClaw 时,技术负责人问了一个直击本质的问题:“我们有 20 个业务线,每个都要部署一套,运维成本怎么控制?” 我当时的回答是:“别部署,用 Railway。”

Railway 是一个 PaaS 平台,它的核心价值不是“便宜”,而是 把部署这件事从运维动作变成了开发动作 。你不需要关心服务器、Docker、Nginx,只需要把 OpenClaw 项目推到 GitHub,Railway 就能自动构建、部署、分配域名、配置 HTTPS。而且它支持环境变量、私有仓库、自动扩缩容——这些正是 OpenClaw 这种微服务架构最需要的。

4.1 从零开始的 Railway 部署五步法

第一步:准备 GitHub 仓库

  • Fork 官方 OpenClaw 仓库(https://github.com/openclaw/openclaw);
  • 在根目录创建 skills/ 目录,放入你的自定义 Skill;
  • 修改 config.yaml ,填入你的模型 API 地址(如 Ollama 的 http://host.docker.internal:11434 );
  • 在仓库根目录添加 Procfile (Railway 识别部署类型的文件):
    web: uvicorn openclaw.gateway.main:app --host 0.0.0.0:$PORT --port $PORT
    

第二步:创建 Railway 项目

  • 登录 Railway(https://railway.app),点击 “New Project”;
  • 选择 “GitHub” 作为源,授权访问你的仓库;
  • 选择刚 fork 的仓库,Branch 选 main
  • 点击 “Deploy Now”。

第三步:配置环境变量 Railway 会自动检测 Procfile 并创建服务。点击刚创建的服务 → “Variables” 标签页,添加:

  • PORT : 8000 (Railway 会自动注入此变量,但显式声明更稳妥)
  • OPENCLAW_CONFIG_PATH : /app/config.yaml
  • PYTHONUNBUFFERED : 1
  • (可选) LOG_LEVEL : DEBUG ,用于上线初期排查

第四步:设置域名与 HTTPS

  • 点击服务 → “Settings” → “Domains”;
  • 点击 “Add Domain”,输入你想要的子域名,如 openclaw-myteam.railway.app
  • Railway 会自动申请 Let's Encrypt 证书,10 分钟内生效;
  • 此时你就可以用 https://openclaw-myteam.railway.app/health 测试了。

第五步:Git 自动同步

  • 在 Railway 服务页面 → “Deployments” → “Enable Auto Deploys”;
  • 勾选 “Pushes to main branch”;
  • 以后你每次 git push origin main ,Railway 就自动拉取、构建、部署新版本。

4.2 Railway vs 本地部署的硬指标对比

我用同一套 Skill(kb_search + jira_create)做了压力测试,对比数据如下(测试工具:k6,100 并发,持续 5 分钟):

指标 Railway(免费实例) 群晖 DS920+(Docker) 本地 MacBook Pro
首字节时间(p95) 320ms 210ms 180ms
错误率 0.02% 0.15% 0.05%
自动 HTTPS ✅ 开箱即用 ❌ 需手动配 Caddy ❌ 需 mkcert
崩溃恢复时间 < 10 秒(自动重启) > 2 分钟(需手动 docker restart) > 30 秒(需手动 kill & start)
多环境隔离 ✅ 每个项目独立域名 ❌ 需手动改 port ❌ 需手动改 port

关键结论: Railway 的免费实例性能足够支撑中小团队的日常使用 。它的 512MB 内存和 1vCPU,跑 OpenClaw Gateway 完全游刃有余。真正瓶颈从来不是计算资源,而是你 Skill 里调用的外部 API(比如 Jira 的 rate limit 是 1000 次/小时)。

4.3 Railway 的隐藏技巧:用环境变量动态切换 Skill

Railway 支持为不同环境(Production/Staging)设置不同的环境变量。我们可以利用这一点,实现 Skill 的灰度发布:

  • staging 环境,设置 ENABLED_SKILLS=kb_search,weather_check
  • production 环境,设置 ENABLED_SKILLS=kb_search,jira_create,confluence_sync
  • config.yaml 中,把 allowed_skills 改成:
    allowed_skills: ${ENABLED_SKILLS.split(',')}
    

这样,你无需修改代码,只需在 Railway 控制台切换环境变量,就能控制哪些 Skill 对外可见。我们用这套机制,在上线 confluence_sync Skill 前,先在 Staging 环境让 3 个测试用户试用一周,零故障后再推到 Production。

5. 生产环境加固:监控、日志、卸载与故障自愈

部署完成只是开始,真正的挑战在上线之后。OpenClaw 作为连接大模型和业务系统的中间件,一旦出问题,影响的是整个 AI 工作流。我总结了一套最小可行的生产环境加固方案,不依赖复杂工具,全部用开源组件实现。

5.1 Prometheus 监控部署:只监控 3 个黄金指标

很多人一提监控就想到 Grafana 大屏,但对 OpenClaw 来说,真正关键的只有三个指标:

  • gateway_request_total{status_code, skill_name} :总请求数,按状态码(2xx/4xx/5xx)和 Skill 名分组;
  • gateway_request_duration_seconds_bucket{le} :请求耗时分布,重点关注 p95 > 2s 的情况;
  • executor_skill_error_total{skill_name} :Skill 执行错误数,这是最直接的业务异常信号。

部署步骤极简:

  1. 在 OpenClaw 项目中安装 prometheus-client pip install prometheus-client
  2. openclaw/gateway/main.py 的 FastAPI app 初始化后,加入:
    from prometheus_client import make_asgi_app
    from prometheus_client.core import CounterMetricFamily, GaugeMetricFamily
    
    # 注册自定义指标
    REQUEST_COUNT = CounterMetricFamily(
        'openclaw_gateway_request_total',
        'Total number of requests',
        labels=['status_code', 'skill_name']
    )
    
    # 暴露监控端点
    app.mount("/metrics", make_asgi_app())
    
  3. 在 Railway 或 Docker 中,暴露 /metrics 端点(Railway 默认所有端口都开放);
  4. 部署 Prometheus(我用 docker run -d -p 9090:9090 -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus ), prometheus.yml 内容:
    global:
      scrape_interval: 15s
    scrape_configs:
      - job_name: 'openclaw'
        static_configs:
          - targets: ['your-openclaw-domain:8000']  # Railway 域名或 IP
    

提示:不用 Grafana 也能看效果。直接访问 https://your-openclaw-domain/metrics ,就能看到纯文本的指标数据,比如 openclaw_gateway_request_total{status_code="200",skill_name="kb_search"} 127

5.2 日志集中化:用 Loki 替代 ELK 的轻量方案

ELK(Elasticsearch+Logstash+Kibana)对 OpenClaw 来说太重了。我们用 Grafana Loki(日志聚合)+ Promtail(日志采集)+ Grafana(可视化)三件套,总内存占用不到 200MB。

关键配置在 promtail-config.yaml

server:
  http_listen_port: 9080
positions:
  filename: /tmp/positions.yaml
clients:
  - url: http://loki:3100/loki/api/v1/push
scrape_configs:
  - job_name: openclaw
    static_configs:
      - targets: [localhost]
        labels:
          job: openclaw
          __path__: /app/logs/*.log

然后在 OpenClaw 的 logging.conf 里,把日志输出路径指向 /app/logs/ 。Loki 会自动按 job=openclaw 标签归类,Grafana 里用 {job="openclaw"} |= "ERROR" 就能秒查所有错误。

5.3 卸载与故障自愈:当 OpenClaw 拒绝启动时怎么办

“openclaw 卸载” 是高频搜索词,但 OpenClaw 本身没有 uninstall 命令。真正的卸载,是清理它的三个依赖层:

  • Gateway 层 pkill -f "uvicorn openclaw.gateway.main:app" (Linux)或任务管理器结束 python.exe 进程(Windows);
  • Executor 层 :删除 skills/ 目录下所有 .pyc 文件和 __pycache__ 文件夹;
  • 配置层 :重命名 config.yaml config.yaml.bak ,然后运行 openclaw init 生成新配置。

但更关键的是 故障自愈 。我在生产环境加了一个 5 行的健康检查脚本 health-check.sh

#!/bin/bash
if ! curl -sf http://localhost:8000/health >/dev/null; then
  echo "$(date) - Gateway down, restarting..." >> /var/log/openclaw/restart.log
  pkill -f "uvicorn openclaw.gateway.main:app"
  nohup uvicorn openclaw.gateway.main:app --host 0.0.0.0:8000 --port 8000 > /var/log/openclaw/gateway.log 2>&1 &
fi

crontab -e 添加 */2 * * * * /path/to/health-check.sh ,每 2 分钟检查一次。它比 systemd 的 Restart=always 更精准,因为只在 HTTP 健康检查失败时才重启,避免了因磁盘满、内存溢出等底层问题导致的无限重启循环。

最后分享一个血泪教训:某次更新 Skill 后,Gateway 启动失败,日志里只有一行 ModuleNotFoundError: No module named 'xxx' 。我花了 40 分钟逐个检查 requirements.txt ,最后发现是 skills/ 目录下有个 __init__.py 文件里写了 from xxx import yyy ,而 xxx 是个不存在的包。 OpenClaw 加载 Skill 时,会递归导入所有 __init__.py ,哪怕你没用到那个模块 。所以,永远不要在 skills/ 目录的 __init__.py 里写任何 import ,让每个 Skill 文件保持完全独立。

更多推荐