OpenClaw 微信机器人搭建教程

微信在国内的地位不需要多说。超过 13 亿月活用户,几乎所有商业沟通都发生在这里。如果你想把 AI 能力接入微信,OpenClaw 是目前最顺手的方案之一。
2026 年初这个话题在中文开发者圈子里热度很高。@frxiaobei 在 X 上发布了「微信直接支持 OpenClaw 教程」,@xiangxiang103 整理了详细的「OpenClaw 微信插件安装使用教程」,@jonnytang6 也在龙虾日记系列里记录了微信接入成功的完整流程。r/ai_chinese 上同期也出现了专门讨论 WeChat bridge 配置的高热度帖子。官方插件方面,腾讯提供了 @tencent-weixin/openclaw-weixin-cli 作为微信接入的标准工具包,本教程的代码方案也与该插件兼容。
本教程从架构原理讲起,带你一步步完成公众号接入、企业微信配置、消息处理逻辑,最后部署到阿里云 ECS。全程有 Node.js 代码示例,注释用中文写。
如果你还没安装 OpenClaw,先看这篇:OpenClaw 完全安装指南 2026。
一、整体架构
OpenClaw 接入微信的方式有两条路:
路径 A:微信公众号(服务号/订阅号)
用户在公众号对话框发消息,消息通过微信服务器转发到你的 webhook,OpenClaw 处理后返回回复。整个链路是:
用户发消息 -> 微信服务器 -> 你的 webhook 服务器 -> OpenClaw API -> 回复
路径 B:企业微信机器人
企业微信群里 @机器人,消息通过 webhook 推送到你的服务,OpenClaw 处理后把结果发回群里。链路更简单:
群成员 @机器人 -> 企业微信 webhook -> OpenClaw API -> 发消息到群
两条路都要求你有一个公网可访问的服务器,并且支持 HTTPS。没有固定 IP 的本地开发阶段可以用 frp 或者 ngrok 做内网穿透临时测试,但正式上线建议直接用 ECS。
二、微信公众号接入
2.1 准备公众号
登录微信公众平台,进入「设置与开发」->「基本配置」。
你需要填写:
- 服务器地址(URL):你的 webhook 地址,格式为
https://your-domain.com/wechat/webhook - 令牌(Token):自己随机填一个字符串,用于验证请求来源
- 消息加解密密钥(EncodingAESKey):点「随机生成」即可
- 消息加解密方式:建议选「安全模式」
保存之前,微信会向你填的 URL 发一个 GET 请求做验证。你的服务器要先跑起来。
2.2 搭建 webhook 服务器
// server.js
const express = require('express')
const crypto = require('crypto')
const xml2js = require('xml2js')
const app = express()
// 微信配置(从环境变量读取,不要硬编码)
const WECHAT_TOKEN = process.env.WECHAT_TOKEN
const WECHAT_APP_ID = process.env.WECHAT_APP_ID
const WECHAT_APP_SECRET = process.env.WECHAT_APP_SECRET
// 验证微信服务器请求
app.get('/wechat/webhook', (req, res) => {
const { signature, timestamp, nonce, echostr } = req.query
// 按微信要求排序后拼接再 SHA1 加密
const str = [WECHAT_TOKEN, timestamp, nonce].sort().join('')
const hash = crypto.createHash('sha1').update(str).digest('hex')
if (hash === signature) {
// 验证通过,返回 echostr
res.send(echostr)
} else {
res.status(403).send('验证失败')
}
})
// 接收用户消息
app.post('/wechat/webhook', express.text({ type: 'text/xml' }), async (req, res) => {
const parser = new xml2js.Parser({ explicitArray: false })
const body = await parser.parseStringPromise(req.body)
const msg = body.xml
// 只处理文本消息
if (msg.MsgType !== 'text') {
res.send('success')
return
}
const userOpenId = msg.FromUserName
const toUser = msg.ToUserName
const userMessage = msg.Content
// 调用 OpenClaw 处理消息
const reply = await processWithOpenClaw(userMessage, userOpenId)
// 按微信要求返回 XML 格式
const replyXml = `
<xml>
<ToUserName><![CDATA[${userOpenId}]]></ToUserName>
<FromUserName><![CDATA[${toUser}]]></FromUserName>
<CreateTime>${Math.floor(Date.now() / 1000)}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${reply}]]></Content>
</xml>
`
res.set('Content-Type', 'text/xml')
res.send(replyXml)
})
app.listen(3000, () => {
console.log('微信 webhook 服务启动,端口 3000')
})
安装依赖:
npm install express xml2js
三、企业微信机器人配置
企业微信的接入比公众号简单很多,不需要服务号资质。
3.1 创建群机器人
在企业微信群里,点右上角「...」->「添加机器人」->「新创建一个机器人」,填写机器人名称,完成后会生成一个 webhook URL,格式类似:
https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
这个 URL 就是你往群里发消息的接口。
3.2 接收群消息
如果你需要接收群成员发的消息,还需要配置「群机器人接收消息」功能(需要企业管理员在后台开启)。配置方式和公众号类似,填写 webhook URL 和 Token。
// 企业微信机器人:往群里发消息
const axios = require('axios')
async function sendToWorkWeChat(webhookUrl, content) {
const payload = {
msgtype: 'text',
text: {
content: content
}
}
const response = await axios.post(webhookUrl, payload, {
headers: { 'Content-Type': 'application/json' }
})
return response.data
}
// 接收企业微信群消息的 webhook
app.post('/workwechat/webhook', express.json(), async (req, res) => {
const event = req.body
// 只处理文本消息类型
if (event.MsgType !== 'text') {
res.json({ errcode: 0 })
return
}
const userMessage = event.Content
const groupChatId = event.ChatId
// 用 OpenClaw 处理
const reply = await processWithOpenClaw(userMessage, groupChatId)
// 发回群里
await sendToWorkWeChat(process.env.WORK_WECHAT_WEBHOOK_URL, reply)
res.json({ errcode: 0 })
})
四、OpenClaw 消息处理核心逻辑
4.1 连接 OpenClaw API
// openclaw-client.js
const axios = require('axios')
const OPENCLAW_BASE_URL = process.env.OPENCLAW_BASE_URL || 'http://localhost:11434'
const OPENCLAW_MODEL = process.env.OPENCLAW_MODEL || 'claude-3-5-sonnet'
// 单轮对话:不保留上下文
async function chatSingle(userMessage) {
const response = await axios.post(`${OPENCLAW_BASE_URL}/v1/chat/completions`, {
model: OPENCLAW_MODEL,
messages: [
{
role: 'system',
content: '你是一个友好的助手,请用简洁的中文回答问题。回答控制在 200 字以内,适合微信消息阅读。'
},
{
role: 'user',
content: userMessage
}
],
max_tokens: 500,
temperature: 0.7
}, {
headers: {
'Authorization': `Bearer ${process.env.OPENCLAW_API_KEY}`,
'Content-Type': 'application/json'
},
// 超时设置:微信要求 5 秒内响应,OpenClaw 可能需要一些时间
timeout: 4500
})
return response.data.choices[0].message.content
}
module.exports = { chatSingle }
4.2 整合到 webhook
const { chatSingle } = require('./openclaw-client')
// 处理消息的主函数
async function processWithOpenClaw(userMessage, userId) {
try {
const reply = await chatSingle(userMessage)
return reply
} catch (error) {
// 超时或 API 错误时返回友好提示
if (error.code === 'ECONNABORTED') {
return '处理时间较长,请稍后再试。'
}
console.error('OpenClaw 调用失败:', error.message)
return '抱歉,暂时无法处理您的请求,请稍后再试。'
}
}
五、多轮对话与上下文管理
单轮问答已经够用了,但如果你想让机器人记住对话历史,需要加一个上下文存储层。
// context-store.js
// 简单的内存存储,生产环境建议换成 Redis
const contextMap = new Map()
// 每个用户最多保留 10 轮对话
const MAX_HISTORY = 10
function getContext(userId) {
if (!contextMap.has(userId)) {
contextMap.set(userId, [])
}
return contextMap.get(userId)
}
function addToContext(userId, role, content) {
const history = getContext(userId)
history.push({ role, content })
// 超出限制时删除最早的一轮
if (history.length > MAX_HISTORY * 2) {
history.splice(0, 2)
}
}
function clearContext(userId) {
contextMap.delete(userId)
}
module.exports = { getContext, addToContext, clearContext }
// 带上下文的多轮对话
const { getContext, addToContext, clearContext } = require('./context-store')
async function chatWithContext(userMessage, userId) {
// 支持用户主动清空对话
if (userMessage.trim() === '清除记忆' || userMessage.trim() === '/clear') {
clearContext(userId)
return '好的,我已经忘记之前的对话了,可以重新开始。'
}
const history = getContext(userId)
// 构建完整消息列表
const messages = [
{
role: 'system',
content: '你是一个友好的助手。用简洁的中文回答,适合微信消息阅读。如果用户想清除对话记录,告诉他们发送"清除记忆"即可。'
},
...history,
{ role: 'user', content: userMessage }
]
const response = await axios.post(`${OPENCLAW_BASE_URL}/v1/chat/completions`, {
model: OPENCLAW_MODEL,
messages,
max_tokens: 500,
temperature: 0.7
}, {
headers: {
'Authorization': `Bearer ${process.env.OPENCLAW_API_KEY}`,
'Content-Type': 'application/json'
},
timeout: 4500
})
const reply = response.data.choices[0].message.content
// 把这轮对话存入上下文
addToContext(userId, 'user', userMessage)
addToContext(userId, 'assistant', reply)
return reply
}
注意:内存存储在服务重启后会丢失,生产环境建议把 contextMap 替换为 Redis。
六、部署到阿里云 ECS
6.1 服务器要求
- 系统:Ubuntu 22.04 LTS(推荐)
- 配置:2 核 2GB 起,OpenClaw 本地运行的话建议 4 核 8GB
- 带宽:1Mbps 够用,主要是延迟要低
- 必须有公网 IP 和域名(微信要求 HTTPS)
6.2 配置 HTTPS
微信公众号的 webhook 地址必须是 HTTPS,自签证书不行。最简单的方式是用 Nginx + Let's Encrypt:
# 安装 Nginx 和 certbot
sudo apt update
sudo apt install nginx certbot python3-certbot-nginx
# 申请证书(把 your-domain.com 换成你的域名)
sudo certbot --nginx -d your-domain.com
配置 Nginx 反向代理到 Node.js 服务:
server {
listen 443 ssl;
server_name your-domain.com;
# certbot 会自动填充 ssl 相关配置
location /wechat/ {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
6.3 用 Docker 运行
在 ECS 上用 Docker 部署更方便管理:
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# docker-compose.yml
version: '3.8'
services:
wechat-bot:
build: .
ports:
- "3000:3000"
environment:
- WECHAT_TOKEN=${WECHAT_TOKEN}
- WECHAT_APP_ID=${WECHAT_APP_ID}
- WECHAT_APP_SECRET=${WECHAT_APP_SECRET}
- OPENCLAW_BASE_URL=${OPENCLAW_BASE_URL}
- OPENCLAW_API_KEY=${OPENCLAW_API_KEY}
- OPENCLAW_MODEL=${OPENCLAW_MODEL}
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
启动:
docker-compose up -d
七、限流与错误处理
微信公众号有接口调用频率限制:普通接口每天调用上限 1000 次(订阅号),服务号更高。OpenClaw 自身也可能有并发限制,视你的部署方式而定。
7.1 简单限流
// rate-limiter.js
// 按用户 ID 做限流,每分钟最多 5 次请求
const requestCounts = new Map()
const RATE_LIMIT = 5
const WINDOW_MS = 60 * 1000
function isRateLimited(userId) {
const now = Date.now()
const userRecord = requestCounts.get(userId) || { count: 0, windowStart: now }
// 超过时间窗口,重置计数
if (now - userRecord.windowStart > WINDOW_MS) {
requestCounts.set(userId, { count: 1, windowStart: now })
return false
}
// 在时间窗口内,检查次数
if (userRecord.count >= RATE_LIMIT) {
return true
}
// 计数加一
userRecord.count++
requestCounts.set(userId, userRecord)
return false
}
module.exports = { isRateLimited }
// 在消息处理中加入限流检查
const { isRateLimited } = require('./rate-limiter')
async function processWithOpenClaw(userMessage, userId) {
if (isRateLimited(userId)) {
return '你发送得太频繁了,请稍等一分钟再试。'
}
try {
return await chatWithContext(userMessage, userId)
} catch (error) {
if (error.code === 'ECONNABORTED') {
return '回答需要一点时间,请再发一次或稍后重试。'
}
console.error(`处理失败 [userId: ${userId}]:`, error.message)
return '遇到了一点问题,请稍后再试。'
}
}
7.2 微信 5 秒超时问题
微信要求服务器在 5 秒内响应,否则会重发消息并提示用户"该公众号暂时无法提供服务"。如果 OpenClaw 的响应时间可能超过 4 秒,有两个处理方案:
方案一:先回复"处理中",再异步推送结果
公众号不直接支持异步推送,需要用客服消息接口。这需要服务号资质,且需要先获取用户 access_token。
方案二:降低模型复杂度
对实时性要求高的场景,选用响应更快的模型,比如 Claude 3 Haiku。在 .env 里配置:
OPENCLAW_MODEL=claude-3-haiku-20240307
八、安全注意事项
微信机器人会接收到真实用户的输入,安全不能忽视。主要的几点:
-
验证请求来源:每次收到微信请求,都要验证签名,防止伪造请求。上面的代码已经包含了 GET 验证,POST 请求同样要做。安装过程中踩坑的用户可以参考 @IndieDevHailey 整理的排查笔记,里面列出了中文社区常见的安装报错和解决方法。
-
不要在日志里打印用户消息内容:用户隐私,做好脱敏。
-
API Key 放环境变量:不要写死在代码里,不要提交到 Git。
-
输入内容做基础过滤:防止用户通过消息内容做 prompt injection 攻击。
更详细的安全配置可以参考:OpenClaw 安全问题解决方案。
九、常见问题
Q:公众号验证一直失败怎么办?
先确认服务器确实在跑,curl https://your-domain.com/wechat/webhook?signature=test×tamp=123&nonce=456&echostr=hello 看看有没有响应。其次检查 Nginx 日志确认请求有没有到达 Node.js 服务。
Q:用户发消息没有收到回复?
查 Node.js 的控制台日志,看看消息有没有收到,OpenClaw API 有没有返回。最常见的原因是超时,调低 max_tokens 或换更快的模型。
Q:企业微信机器人能主动发消息吗?
可以,往那个 webhook URL 发 POST 请求即可,不需要用户先发消息触发。定时推送、告警通知都可以这么做。
Q:一个 OpenClaw 实例能同时服务多个微信账号吗?
可以。OpenClaw 的 API 是无状态的,多个 webhook 服务器指向同一个 OpenClaw 实例完全没问题,注意控制并发就好。
小结
OpenClaw 接入微信的核心链路并不复杂:webhook 接收消息,OpenClaw 处理,XML 或 JSON 格式返回。公众号适合面向 C 端用户,企业微信适合内部工具和团队协作。
部署方面,阿里云 ECS 加 Docker 是最稳的方案,域名和 HTTPS 是必须项。限流和错误处理做好,基本上就能稳定跑起来了。