职贝云数AI新零售门户
标题:
手把手教你部署Openclaw,打通企业微信与您的智能助手聊天
[打印本页]
作者:
OZQ
时间:
8 小时前
标题:
手把手教你部署Openclaw,打通企业微信与您的智能助手聊天
还在愁企业微信没有专属智能聊天小助手?教你疾速部署小龙虾 Openclaw,轻松完成企业微信与智能助手的无缝对接,日常办公咨询、音讯回复全搞定,全程步骤明晰,新手也能跟着做!
后期预备
一台云服务器(某云平台即可),系统选择 Linux,确保服务器可正常联网并能停止端口和面板配置;
企业微信管理员权限,可进入运用管理停止新增运用、配置服务器等操作;
MiniMax 账号(用于获取智能接口密钥),官网注册即可,新用户自带 15 元体验额度,足够后期测试运用。
核心部署步骤:先搞定 Openclaw 小龙虾基础环境
步骤 1:云服务器基础配置,开放必备端口
购买 Linux 云服务器后,首先进入服务器防火墙设置,开放 18789 端口(小龙虾 Openclaw 的核心服务端口)和3000 端口(后续企业微信音讯转发接口端口),两个端口缺一不可,需确保为入站规则开放,避免后续衔接失败。
步骤 2:安装 1panel 面板,部署 Openclaw 核心程序
在云服务器上安装 1panel 管理面板(安装命令可参考 1panel 官方文档,Linux 系统一键安装即可),安装完成后经过服务器 IP + 面板端口进入管理后台;
打开 1panel 的运用商店,搜索Openclaw,选择最新版本(当前为 2026.2.9)停止一键安装,面板会自动完成容器化部署,无需手动配置基础环境。
步骤 3:配置 MiniMax 密钥,启动 Openclaw 容器
登录 MiniMax 官网,在个人中心找到接口密钥,复制备用;
前往 1panel,进入 Openclaw 的容器管理页面,找到容器挂载的目录,在环境变量配置项中粘贴复制的 MiniMax 接口密钥;
保存配置后启动 Openclaw 容器,等待启动完成后,在阅读器输入http://[你的服务器IP]:18789,即可进入 Openclaw 的聊天和管理界面,基础的小龙虾智能助手就可以用啦!
步骤 4:验证 Openclaw 部署,完成核心衔接
进入 Openclaw 容器目录,找到openclaw.json文件,打开后查找并复制外面的token值;
回到http://[你的服务器IP]:18789的管理界面,点击Overview选项,在 token 输入框中粘贴复制的内容,点击衔接;
若界面Status显示为Connected,阐明 Openclaw 小龙虾部署成功,此时可直接在该界面与小龙虾停止智能聊天测试。
关键对接步骤:打通企业微信,完成音讯互通
部署好基础的 Openclaw 后,接上去我们将其与企业微信对接,让企业微信里的同事都能经过专属小助手和小龙虾聊天,核心是配置音讯中转服务,完成企业微信与 Openclaw 的音讯双向转发。
步骤 5:企业微信创建专属小龙虾小助手,配置服务器回调
登录企业微信管理后台,进入运用管理,点击创建运用,运用称号填写 “小龙虾小助手”,上传图标后完成创建;
进入刚创建的小龙虾小助手运用概况页,找到Api 接收音讯服务器配置;
配置项中填写服务器地址:http://[你的服务器IP]:3000/wework/callback,其他项暂时默许,点击保存;
保存后会随机生成Token和EncodingAESKey,务必记录上去;同时在企业微信后台找到企业的corpId、该运用的agentId和secret,全部备用,后续配置会频繁用到。
配置IP 白名单:将云服务器的公网 IP 添加到运用的 IP 白名单中,否则企业微信无法向服务器推送音讯。
步骤 6:创建音讯转发文件,配置对接参数
前往云服务器,进入 Openclaw 容器的openclaw/data/workspace/目录;
新建文件wework-openclaw.js,该文件是企业微信与 Openclaw 的音讯中转核心,需在文件中填写以下配置参数,将之前记录的信息对应交换:
openclaw: { wsUrl: 'ws://127.0.0.1:18789/', token: '[你的openclaw Token]', sessionKey: 'agent:main:wechat' },wechat: { corpId: '[corpId]', agentId: '[agentId]', secret: '[secret]', token: '[token]', aesKey: '[aesKey]' }, const express = require('express');const WebSocket = require('ws');const crypto = require('crypto');const axios = require('axios');const app = express();let ws = null, wsHandshakeDone = false, accessToken = '', tokenExpireTime = 0;let runHandlers = {};function wechatDecrypt(text) { try { const aesKey = Buffer.from(CONFIG.wechat.aesKey + '=', 'base64'); const encrypted = Buffer.from(text, 'base64'); const decipher = crypto.createDecipheriv('aes-256-cbc', aesKey, encrypted.slice(0, 16)); decipher.setAutoPadding(false); let decrypted = decipher.update(encrypted.slice(16)) + decipher.final('binary'); const pad = decrypted.charCodeAt(decrypted.length - 1); if (pad < 1 || pad > 32) pad = 0; decrypted = decrypted.slice(0, decrypted.length - pad); const len = decrypted.charCodeAt(0) | (decrypted.charCodeAt(1) << 8) | (decrypted.charCodeAt(2) << 16) | (decrypted.charCodeAt(3) << 24); return decrypted.slice(4, 4 + len).toString(); } catch (e) { return null; }}function parseWeChatXML(xml) { const msgType = xml.match(/<MsgType[^>]*><!\[CDATA\[([^\]]+)\]\]><\/MsgType>/); const fromUser = xml.match(/<FromUserName[^>]*><!\[CDATA\[([^\]]+)\]\]><\/FromUserName>/); const content = xml.match(/<Content[^>]*><!\[CDATA\[([^\]]+)\]\]><\/Content>/); return { msgType: msgType?.[1]?.trim()||'', fromUser: fromUser?.[1]?.trim()||'', content: content?.[1]?.trim()||'' };}function connectOpenClaw() { console.log('🔌 衔接 OpenClaw...'); ws = new WebSocket(CONFIG.openclaw.wsUrl); ws.on('open', () => { console.log('✅ 已衔接'); }); ws.on('message', (data) => { try { const raw = data.toString(); if (raw.includes('res') || raw.includes('event')) { console.log('📥 WS音讯:', raw.slice(0, 150)); } const msg = JSON.parse(raw); // 认证 if (msg.event === 'connect.challenge') { ws.send(JSON.stringify({ type: 'req', method: 'connect', id: '1', params: { minProtocol: 1, maxProtocol: 3, client: { id: 'cli', displayName: 'WeChat', version: '1.0.0', platform: 'node', mode: 'cli' }, auth: { token: CONFIG.openclaw.token }, scopes: ['operator.admin'] } }) + '\n'); } else if (msg.type === 'res' && msg.id === '1' && msg.ok) { console.log('✅ 认证成功'); wsHandshakeDone = true; } // 流式音讯 - 打印一切 agent 事情 else if (msg.type === 'event' && msg.event === 'agent') { console.log('📥 Agent事情:', JSON.stringify(msg.payload).slice(0, 200)); if (runHandlers[msg.payload?.runId]) { // 支持多种格式的文本提取 const text = msg.payload?.data?.text || msg.payload?.data?.delta || ''; if (text) { runHandlers[msg.payload.runId].reply += text; console.log('📝 累积文本:', text.slice(0, 50)); } if (msg.payload?.stream === 'stop' || msg.payload?.data?.phase === 'end') { const h = runHandlers[msg.payload.runId]; console.log('📬 完成,回复:', h?.reply?.slice(0, 100)); if (h) { h.resolve(h.reply); delete runHandlers[msg.payload.runId]; } } } } // 呼应 - 保存 runId,不删除 id版本的 handler else if (msg.type === 'res' && msg.id) { console.log('📥 收到呼应, msg.id:', msg.id, ', 能否有handler:', !!runHandlers[msg.id], ', payload:', JSON.stringify(msg.payload).slice(0, 100)); if (runHandlers[msg.id]) { clearTimeout(runHandlers[msg.id].timeout); const runId = msg.payload?.runId; if (runId) { runHandlers[runId] = runHandlers[msg.id]; // 用 runId 关联 handler console.log('✅ 已关联 runId:', runId); } // 不要删除 id 版本的 handler,由于后续能够还会用到 } } } catch (e) {} }); ws.on('error', (err) => console.error('WS 错误:', err.message)); ws.on('close', () => { console.log('🔌 断开,3秒后重连'); wsHandshakeDone = false; setTimeout(connectOpenClaw, 3000); });}function sendToOpenClaw(question) { return new Promise((resolve) => { if (!wsHandshakeDone) return resolve('OpenClaw 未衔接'); const id = crypto.randomUUID(); let reply = ''; const timeout = setTimeout(() => { delete runHandlers[id]; resolve(reply || '请稍后再试'); }, 15000); runHandlers[id] = { resolve, reply, timeout }; // 用 id 作为 idempotencyKey,这样呼应会用 id 作为回复 id ws.send(JSON.stringify({ type: 'req', method: 'chat.send', id, params: { sessionKey: CONFIG.openclaw.sessionKey, message: question, idempotencyKey: id } }) + '\n'); console.log('📤 已发送, request id:', id); });}async function getAccessToken() { if (Date.now() < tokenExpireTime) return accessToken; const res = await axios.get(`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${CONFIG.wechat.corpId}&corpsecret=${CONFIG.wechat.secret}`); if (res.data.errcode !== 0) throw new Error(res.data.errmsg); accessToken = res.data.access_token; tokenExpireTime = Date.now() + (res.data.expires_in - 60) * 1000; return accessToken;}async function sendToWeChat(userId, content) { const token = await getAccessToken(); const res = await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${token}`, { touser: userId, msgtype: 'text', agentid: CONFIG.wechat.agentId, text: { content }, safe: 0 }, { timeout: 5000 }); if (res.data.errcode !== 0) throw new Error(res.data.errmsg); console.log('✅ 已回复\n');}app.use(express.raw({ type: 'text/xml' }));app.use(express.raw({ type: 'application/xml' }));app.get('/wework/callback', (req, res) => res.send('success'));app.post('/wework/callback', async (req, res) => { console.log('📨 收到回调, body:', req.body?.toString?.()?.slice(0, 200)); try { const bodyStr = req.body?.toString?.() || ''; if (!bodyStr.includes('<Encrypt>')) return res.send('success'); const match = bodyStr.match(/<Encrypt[^>]*><!\[CDATA\[([^\]]+)\]\]><\/Encrypt>/); if (!match) return res.send('success'); const xml = wechatDecrypt(match[1]); if (!xml) return res.send('success'); const msg = parseWeChatXML(xml); if (!msg || msg.msgType !== 'text' || !msg.content) return res.send('success'); console.log(`📩 ${msg.fromUser}: ${msg.content}`); const reply = await sendToOpenClaw(msg.content); console.log(`💬 OpenClaw回复: ${reply}`); await sendToWeChat(msg.fromUser, reply); res.send('success'); } catch (err) { console.error('错误:', err.message); res.send('success'); }});console.log('🚀 企业微信 → OpenClaw 中转服务\n');connectOpenClaw();app.listen(CONFIG.server.port, () => console.log(`✅ 运转: http://localhost:${CONFIG.server.port}`));
保存文件,确保参数无拼写错误,否则会导致音讯转发失败。同时需求在容器里安装相关的依赖。
步骤 7:安装 Node.js,启动中转服务并测试
进入 Openclaw 容器外部,安装Node.js v20 及以上版本(可经过官网下载安装包或包管理器一键安装),安装完成后经过node -v验证版本;
在openclaw/data/workspace/目录下,执行命令node wework-openclaw.js启动音讯中转服务;
启动后,打开企业微信,向 “小龙虾小助手” 发送恣意音讯,若能收到 Openclaw 的智能回复,阐明中转服务测试成功;若未收到,检查参数配置和端口能否开放。
步骤 8:设置中转服务自启动,完成容器联动
为了避免服务器或容重视启后中转服务失效,我们需求将中转服务设置为随 Openclaw 容器一同启动的系统服务,与日俱增。
在openclaw/data/workspace/目录下,新建文件wework-service.sh,编写服务启动脚本,核心内容为启动 wework-openclaw.js(脚本需确保可执行权限,可经过chmod +x wework-service.sh设置);
#!/bin/bash# wework-service.sh - 企业微信中转服务 watchdog# 自动启动并保活SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"NODE_SCRIPT="$SCRIPT_DIR/wework-openclaw.js"LOG_FILE="$SCRIPT_DIR/wework-service.log"log(){ echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"}log "🚀 启动企业微信中转服务 watchdog"
while true; do if[!-f "$NODE_SCRIPT"]; then log "❌ 脚本不存在: $NODE_SCRIPT" sleep 10 continue fi log "▶ 启动服务..." node "$NODE_SCRIPT" >> "$LOG_FILE" 2 >& 1 log "⚠️ 进程加入,5秒后重启..." sleep 5done
前往 1panel 的 Openclaw 容器编排页面,修正容器配置:
添加中转服务启动命令:
sh -c "node dist/index.js gateway --bind lan --port 18789 & sleep 5 && /home/node/.openclaw/workspace/wework-service.sh"
添加中转服务端口的窗口映射:
- ${HOST_IP}:${PANEL_APP_PORT_3000:-3000}:3000
保存容器配置后重启 Openclaw 容器,重启完成后再次在企业微信测试音讯发送,确认回复正常。
最终验证
一切步骤完成后,做两个简单验证:
直接访问http://[服务器IP]:18789,小龙虾聊天界面正常运用;
企业微信向 “小龙虾小助手” 发送音讯,秒级收到智能回复,服务器后台无报错。假如有成绩可以查看日志文件来排查。
至此,小龙虾 Openclaw 就成功部署并与企业微信完成对接啦!后续可根据实践需求,在 MiniMax 后台充值额度、调整 Openclaw 的智能回复配置,也可以在企业微信中修正小助手的权限,设置可运用的部门和人员。整个部署过程核心在于端口开放、参数准确配置和服务联动,只需跟着步骤一步步来,新手也能轻松搞定,赶紧给本人的企业微信安排上专属智能小助手吧!
欢迎光临 职贝云数AI新零售门户 (https://www.taojin168.com/cloud/)
Powered by Discuz! X3.5