前后花了快2天时间,研究了一下小龙虾的部署使用,发出来供大家分享!
有条件最好还是使用源码进行部署,博主由于是公司服务器不好搞vpn,所以还是先用镜像部署
展开代码git clone https://github.com/openclaw/openclaw.git ./docker-setup.sh
挺简单的,后续配置一起写。
在我之前推荐的镜像站拉
展开代码docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/openclaw/openclaw:2026.3.8 docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/openclaw/openclaw:2026.3.8 openclaw/openclaw:2026.3.8
创建数据目录
展开代码mkdir -p data
创建环境配置
展开代码vim .env
文件内容如下:
展开代码OPENCLAW_IMAGE=openclaw/openclaw:2026.3.8 OPENCLAW_GATEWAY_TOKEN= OPENCLAW_DATA_DIR=./data
创建docker-compose.yml
展开代码vim docker-compose.yml
文件内容如下:
展开代码services: # --- 主服务:WebUI 和 Gateway (常驻) --- openclaw-gateway: image: ${OPENCLAW_IMAGE} container_name: openclaw-gateway restart: unless-stopped init: true # 核心改动1:启用宿主机网络模式 network_mode: host environment: # 必须配置 TZ: Asia/Shanghai OPENCLAW_GATEWAY_MODE: local OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN} # 基础环境 HOME: /home/node TERM: xterm-256color # 绑定设置(宿主机模式下建议绑定 0.0.0.0 或保留 lan) OPENCLAW_GATEWAY_BIND: "0.0.0.0" OPENCLAW_GATEWAY_PORT: 18789 volumes: - ${OPENCLAW_DATA_DIR}:/home/node/.openclaw - ${OPENCLAW_DATA_DIR}/workspace:/home/node/.openclaw/workspace # 核心改动2:移除 ports 映射(宿主机模式下无需映射) command: [ "node", "dist/index.js", "gateway", "--bind", "lan", "--port", "18789", ] # 补充:添加 root 用户解决权限问题(之前的核心需求) user: root # --- 工具箱:CLI (默认不启动) --- openclaw-cli: profiles: ["tools"] image: ${OPENCLAW_IMAGE} container_name: openclaw-cli init: true stdin_open: true # -i 允许输入 tty: true # -t 伪终端 # CLI 也启用宿主机网络(保持和主服务一致) network_mode: host environment: OPENCLAW_GATEWAY_MODE: local OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN} HOME: /home/node TERM: xterm-256color BROWSER: echo # 防止尝试打开宿主机浏览器 volumes: - ${OPENCLAW_DATA_DIR}:/home/node/.openclaw - ${OPENCLAW_DATA_DIR}/workspace:/home/node/.openclaw/workspace entrypoint: ["node", "dist/index.js"] # 补充:CLI 也添加 root 用户 user: root
需要注意的几个点:
执行如下命令开始初始化
展开代码docker compose run --rm -u root openclaw-cli onboard
一开始无脑点跳过和yes就行,后面有需要再配置
展开代码vim data/openclaw.json
需要改以下内容:
展开代码"gateway": { "port": 18789, "mode": "local", "bind": "lan", "controlUi": { #OpenClaw 的控制 UI 是网页端,浏览器会做跨域(CORS)验证,设为 true 时,若 UI 端的 Origin 验证失败,会降级使用请求头中的 Host 字段来判断是否允许访问; "dangerouslyAllowHostHeaderOriginFallback": true, #设为 true 时,允许在非加密通道(HTTP)下传递认证信息;实际情况是这个没卵用 "allowInsecureAuth": true }, "auth": { "mode": "token", "token": "8406dc0b3bfcffd579314ef9214b7dd66e031f8c1a97b054" }, "tailscale": { "mode": "off", "resetOnExit": false }, "tls": { #这个是开https的 "enabled": true, "autoGenerate": true }, "nodes": { "denyCommands": [ "camera.snap", "camera.clip", "screen.record", "contacts.add", "calendar.add", "reminders.add", "sms.send" ] } }
展开代码docker compose up -d
页面访问 https:://yourip:18789 即可进入controlUi
进入概览页面,先配置网关令牌

这里令牌获取方式如下
展开代码#进入容器 docker exec -it openclaw-gateway bash #执行生成token指令 openclaw dashboard --no-open #结果会生成http://127.0.0.1:18789/#token=8406dc0b3bfcffd579314ef9214b7dd66e031f8c1a97b054这样一个url,后面的token就是你要复制的值 #粘贴到web页面上进行连接,然后在容器内继续执行如下命令,进行设备匹配 openclaw devices list #找到对应ip的requesId,进行设备匹配认证 openclaw devices approve <requestId>
随后即可web页面进行访问聊天
执行如下命令
展开代码docker compose run --rm -u root openclaw-cli onboard
这一步选择Custom Provider

api的接口地址

API KEY


接口协议

模型id qwen-max或者百炼的其他模型

之后就OK了,暂时可以聊天了,之后可以在配置频道
Skill我觉得是现在大模型Agent系统的核心,下图是Skills的整体演化过程。MCP的技术门槛比较高,需要有一定的技术能力才能开发,Tools Call功能又过于单一,更多倾向于一些工具而非具体的流程。Skill其实也就是prompt的进化版本,通过定义一系列的提示词让模型完成整个工作流程。

以我要让模型具有给手机打语音电话的功能,可通过如下流程进行开发
展开代码#在docker的data映射目录新建skills目录 mkdir -p /data/skills/voice-alarm
展开代码--- name: voice-alarm title: 语音告警通知助手 description: 识别打电话/语音通知意图,提取手机号/位置/告警类型,调用接口发送语音短信 version: 1.1.0 author: your-name user-invocable: true command-dispatch: tool parameters: [] requires: bins: - curl - python3 # 用于URL编码(兼容所有系统,比shell内置工具更稳定) --- # 技能执行逻辑(性能优化版:合并命令、减少进程创建) ## 步骤1:根据用户的输入,提取出其中的关键信息,并根据实际值修改以下参数 export SIGN_NAME="" # 发生了什么事情 例如火灾告警或者学生安全行为预警等 export PHONE_NUM = "" #需要打电话的手机号码 export POSITION = "" #火灾位置 ## 步骤2:其余参数为固定参数 export SMS_REQUEST_URL="/sendVoice?phoneNum={0}&signName={1}&templateCode={2}&content={3}" export TEMPLATE_CODE="xxxx" export SMS_IP="http://xxxx:xxxx" ## 步骤3:校验必填信息 if [ -z "$PHONE_NUM" ]; then echo "[ERROR] 未从对话中提取到有效手机号码(格式:11位数字)" exit 1 fi if [ -z "$POSITION" ]; then echo "[ERROR] 未从对话中提取到位置信息(如:北京市、朝阳区)" exit 1 fi if [ -z "$ALARM_EVENT" ]; then echo "[ERROR] 未从对话中提取到告警类型(如:火灾、漏水)" exit 1 fi ## 步骤4:构造content参数并URL编码(合并为单次python调用,减少3次python进程启动) export CONTENT_RAW="{\"position\":\"$POSITION\",\"alarm_event\":\"$ALARM_EVENT\"}" # 一次python调用完成所有编码,输出为 | 分隔的字符串 ENCODED_VALUES=$(python3 -c " import urllib.parse raw = '$CONTENT_RAW' sign = '$SIGN_NAME' tpl = '$TEMPLATE_CODE' print('|'.join([ urllib.parse.quote(raw, encoding='utf-8'), urllib.parse.quote(sign, encoding='utf-8'), urllib.parse.quote(tpl, encoding='utf-8') ])) ") # 拆分编码结果 CONTENT_ENCODED=$(echo "$ENCODED_VALUES" | cut -d'|' -f1) SIGN_NAME_ENCODED=$(echo "$ENCODED_VALUES" | cut -d'|' -f2) TEMPLATE_CODE_ENCODED=$(echo "$ENCODED_VALUES" | cut -d'|' -f3) ## 步骤5:拼接完整请求URL(合并为单次sed调用,减少4次sed进程) export FULL_URL_PATH=$(echo "$SMS_REQUEST_URL" | sed -e "s/{0}/$PHONE_NUM/g" \ -e "s/{1}/$SIGN_NAME_ENCODED/g" \ -e "s/{2}/$TEMPLATE_CODE_ENCODED/g" \ -e "s/{3}/$CONTENT_ENCODED/g") export FULL_REQUEST_URL="$SMS_IP$FULL_URL_PATH" ## 步骤6:打印日志(请求URL和编码后的参数) echo "[INFO] 原始content参数:$CONTENT_RAW" echo "[INFO] URL编码后的content:$CONTENT_ENCODED" echo "[INFO] 完整请求URL:$FULL_REQUEST_URL" ## 步骤7:调用语音短信接口(设置10秒超时) RESPONSE=$(curl -s -m 10 "$FULL_REQUEST_URL") ## 步骤8:打印返回值日志并输出结果 if [ -z "$RESPONSE" ]; then echo "[ERROR] 接口调用超时/无返回值(URL:$FULL_REQUEST_URL)" echo "❌ 语音告警通知发送失败:接口无响应" else echo "[INFO] 语音短信接口返回值:$RESPONSE" echo "✅ 语音告警通知处理结果:" echo "├─ 手机号:$PHONE_NUM" echo "├─ 位置:$POSITION" echo "├─ 告警类型:$ALARM_EVENT" echo "├─ 接口请求地址:$FULL_REQUEST_URL" echo "└─ 接口返回:$RESPONSE" fi
docker compose down && docker compose up -d


可见该脚本自动调用了两个工具,一个是读取md文件,另一个是exec执行shell命令调用接口
本文作者:刘涛
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!