openclaw-plugin-wecom 是一个专为 OpenClaw 框架开发的企业微信(WeCom)集成插件。它允许你将强大的 AI 能力无缝接入企业微信,支持 AI 机器人模式和自建应用模式,并具备多层消息投递回退机制。
- AI 机器人模式 (Bot Mode): 基于企业微信最新的 AI 机器人流式分片机制,实现流畅的打字机式回复体验。支持 JSON 格式的回调消息。
- 自建应用模式 (Agent Mode): 支持企业微信自建应用,可处理 XML 格式的回调消息,支持收发消息、上传下载媒体文件。
- Webhook Bot 模式: 支持通过 Webhook 发送消息到群聊,适用于群通知场景。
- Markdown 格式支持: 流式回复的
content字段支持常见 Markdown 格式,包括加粗、斜体、代码块、列表、标题、链接等,企业微信客户端会自动渲染。 - 思考过程展示: 当 LLM 回复包含
<think>...</think>标签时,插件自动解析并通过thinking_content字段在客户端展示可折叠的思考过程。 - 被动回复思考模式: 首次被动回复即启用思考模式 UI(通过
thinking_content字段),用户无需等待即可看到模型正在思考的状态。 - 图片混合回复: 支持在最终回复(
finish=true)时包含msgtype为image的msg_item,流式过程中图片会排队等待最终发送。
- 四层投递回退机制: 确保消息可靠送达
- 流式通道: 优先通过活跃流式通道发送
- Response URL 回退: 流式通道关闭后,使用企业微信 response_url 发送
- Webhook Bot 回退: 支持通过 Webhook 发送到指定群聊
- Agent API 回退: 通过自建应用 API 主动推送消息
- 消息防抖合并: 同一用户在短时间内(2 秒内)连续发送的多条消息自动合并为一次 AI 请求。
- 内存自动清理: 定期清理过期的流元数据和响应 URL,防止内存泄漏。
- 动态 Agent 管理: 默认按"每个私聊用户 / 每个群聊"自动创建独立 Agent。每个 Agent 拥有独立的工作区与对话上下文,实现更强的数据隔离。
- 群聊深度集成: 支持群聊消息解析,可通过 @提及(At-mention)精准触发机器人响应。
- 管理员用户: 可配置管理员列表,默认绕过指令白名单;可选开启“绕过动态 Agent 路由”。
- 指令白名单: 内置常用指令支持(如
/new、/status),并提供指令白名单配置功能。
- 丰富消息类型: 支持文本、图片、语音、图文混排、文件、位置、链接等消息类型。
- 入站媒体处理: 自动解密企业微信 AES-256-CBC 加密的图片,下载并保存语音、视频、文件等媒体供 AI 分析。
- 出站图片发送: 支持通过
msg_itemAPI 发送 base64 编码图片,单张最大 2MB,每条消息最多 10 张。 - 文件上传下载: Agent 模式下支持上传临时媒体文件和下载用户发送的媒体文件。
- 安全与认证: 完整支持企业微信消息加解密、URL 验证及发送者身份校验。
- 高性能异步处理: 采用异步消息处理架构,确保即使在长耗时 AI 推理过程中,企业微信网关也能保持高响应性。
- 模块化架构: 清晰的代码组织结构,易于维护和扩展。
- 已安装 OpenClaw (版本 2026.3.2+)
- 企业微信管理后台权限,可创建智能机器人应用或自建应用
- 可从企业微信访问的服务器地址(HTTP/HTTPS)
openclaw plugins install @sunnoy/wecom此命令会自动:
- 从 npm 下载插件
- 安装到
~/.openclaw/extensions/目录 - 更新 OpenClaw 配置
- 注册插件
npm test运行单元测试(使用 Node.js 内置测试运行器)。
在 OpenClaw 配置文件(~/.openclaw/openclaw.json)中添加:
{
"plugins": {
"entries": {
"wecom": {
"enabled": true
}
}
},
"channels": {
"wecom": {
"enabled": true,
"token": "你的 Bot Token",
"encodingAesKey": "你的 Bot EncodingAESKey",
"adminUsers": ["管理员userid"],
"commands": {
"enabled": true,
"allowlist": ["/new", "/status", "/help", "/compact"]
},
"network": {
"egressProxyUrl": "http://your-proxy-host:8080"
},
"agent": {
"corpId": "企业 CorpID",
"corpSecret": "应用 Secret",
"agentId": 1000002,
"token": "回调 Token (Agent 模式)",
"encodingAesKey": "回调 EncodingAESKey (Agent 模式)"
},
"webhooks": {
"ops-group": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx",
"dev-group": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy"
}
}
}
}| 配置项 | 类型 | 必填 | 说明 |
|---|---|---|---|
plugins.entries.wecom.enabled |
boolean | 是 | 启用插件 |
channels.wecom.token |
string | 是* | 企业微信机器人 Token (*Bot 模式必填) |
channels.wecom.encodingAesKey |
string | 是* | 消息加密密钥(43 位)(*Bot 模式必填) |
channels.wecom.adminUsers |
array | 否 | 管理员用户 ID 列表(绕过指令白名单) |
channels.wecom.commands.enabled |
boolean | 否 | 是否启用指令白名单过滤(默认 true) |
channels.wecom.commands.allowlist |
array | 否 | 允许的指令白名单 |
配置按人/按群隔离的 Agent 管理:
| 配置项 | 类型 | 必填 | 说明 |
|---|---|---|---|
channels.wecom.dynamicAgents.enabled |
boolean | 否 | 是否启用动态 Agent(默认 true) |
channels.wecom.dynamicAgents.adminBypass |
boolean | 否 | 管理员是否跳过动态 Agent 路由(默认 false) |
channels.wecom.dm.createAgentOnFirstMessage |
boolean | 否 | 私聊时为每个用户创建独立 Agent(默认 true) |
channels.wecom.groupChat.enabled |
boolean | 否 | 是否启用群聊处理(默认 true) |
channels.wecom.groupChat.requireMention |
boolean | 否 | 群聊是否必须 @ 提及才响应(默认 true) |
配置工作区模板目录,为动态创建的 Agent 工作区预置初始化文件:
| 配置项 | 类型 | 必填 | 说明 |
|---|---|---|---|
channels.wecom.workspaceTemplate |
string | 否 | 模板目录路径,支持 AGENTS.md、BOOTSTRAP.md 等 bootstrap 文件 |
当动态 Agent 首次创建时,会自动从模板目录复制 bootstrap 文件到对应的工作区。详细说明请参考动态 Agent 路由章节。
配置自建应用以实现更强大的消息收发能力:
| 配置项 | 类型 | 必填 | 说明 |
|---|---|---|---|
channels.wecom.agent.corpId |
string | 是 | 企业 CorpID |
channels.wecom.agent.corpSecret |
string | 是 | 应用 Secret |
channels.wecom.agent.agentId |
number | 是 | 应用 Agent ID |
channels.wecom.agent.token |
string | 是 | 回调 Token (用于验证签名) |
channels.wecom.agent.encodingAesKey |
string | 是 | 回调 EncodingAESKey (43 位) |
用于 Agent / Webhook 等外发请求走固定出口代理(适用于企业微信固定 IP 白名单场景)。
| 配置项 | 类型 | 必填 | 说明 |
|---|---|---|---|
channels.wecom.network.egressProxyUrl |
string | 否 | 外发 HTTP(S) 代理地址,例如 http://proxy:8080 |
WECOM_EGRESS_PROXY_URL |
env | 否 | 环境变量方式配置代理,优先级高于 channels.wecom.network.egressProxyUrl |
配置 Webhook Bot 用于群通知:
| 配置项 | 类型 | 必填 | 说明 |
|---|---|---|---|
channels.wecom.webhooks |
object | 否 | Webhook URL 映射 (key: 名称, value: URL) |
AI 机器人模式适用于简单的问答场景,支持流式输出。
📖 官方文档:企业微信 AI 机器人开发指南
创建步骤:
- 登录企业微信管理后台
- 进入「应用管理」→「应用」→ 下拉找到「智能机器人」→ 点击「创建应用」
- 关键步骤:在创建页面底部,选择 「API 模式创建」,而非「标准模式创建」
⚠️ 必须选择 API 模式。标准模式下回调消息为 XML 格式,API 模式为 JSON 格式,本插件的 Bot 模式仅支持 JSON。 - 填写机器人名称、头像等基本信息,点击「创建」
- 创建完成后,进入机器人详情页:
- 复制
Token(用于验证消息签名) - 复制
EncodingAESKey(43位字符,用于消息加解密)
- 复制
- 点击「接收消息」区域的「设置」:
- URL:
https://your-domain.com/webhooks/wecom - Token: 填入上一步复制的 Token
- EncodingAESKey: 填入上一步复制的 EncodingAESKey
- URL:
- 保存配置并启用消息接收
自建应用模式提供更完整的消息收发能力,支持 XML 回调、主动推送、媒体文件处理。
📖 官方文档:企业微信自建应用开发指南、接收消息服务器配置
创建步骤:
- 登录企业微信管理后台
- 进入「应用管理」→「应用」→ 点击「创建应用」
- 填写应用信息:
- 应用名称:如 "AI 助手"
- 应用头像:上传应用图标
- 可见成员:选择可使用该应用的成员
- 点击「创建应用」,记录以下信息:
AgentId:应用 ID(数字)Secret:应用凭证(点击「查看」获取)
- 在「接收消息」区域点击「设置 API 接收」:
- URL:
https://your-domain.com/webhooks/app - Token: 点击「随机生成」获取
- EncodingAESKey: 点击「随机生成」获取(43位字符)
- 点击「保存」时,企业微信会发送验证请求到上述 URL 进行域名校验
⚠️ 注意:保存前请确保服务已部署并可访问,否则校验会失败。如果遇到「回调 URL 校验失败」,请检查:- 服务器是否可以从公网访问
- URL 路径是否正确(
/webhooks/app) - Token 和 EncodingAESKey 是否已正确配置到插件
- 防火墙是否放行了企业微信服务器 IP 段
- URL:
- 获取企业 CorpID:
- 进入「我的企业」页面
- 复制页面底部的「企业ID」
- 配置应用可见范围(确保需要使用 AI 助手的成员在可见范围内)
Webhook Bot 用于向群聊发送通知消息。
📖 官方文档:企业微信群机器人开发指南
创建步骤:
- 在手机或电脑端打开目标群聊
- 点击群聊右上角「···」→「群机器人」→「添加机器人」
- 选择「新建机器人」,填写机器人名称
- 复制 Webhook 地址(格式:
https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx) - 将 Webhook 地址配置到
openclaw.json的webhooks中
注意事项:
- Webhook Bot 仅支持发送消息,不支持接收消息
- 每个群聊可添加多个机器人
- Webhook 地址请妥善保管,避免泄露
企业微信提供了三种不同的接入方式,每种方式在私聊和群聊场景下的消息收发能力不同:
| 能力 | Bot 模式 (AI 机器人) | Agent 模式 (自建应用) | Webhook 模式 (群机器人) |
|---|---|---|---|
| 私聊接收 | ✅ JSON 回调 | ✅ XML 回调 | ❌ 不支持 |
| 私聊被动回复 | ✅ 流式 stream | ✅ 同步回复 | ❌ 不支持 |
| 私聊主动发送 | ❌ 不支持 | ✅ 应用消息 API | ❌ 不支持 |
| 群聊接收 | ✅ @提及 JSON 回调 | ✅ @提及 XML 回调 | ❌ 不支持 |
| 群聊被动回复 | ✅ 流式 stream | ✅ 同步回复 | ❌ 不支持 |
| 群聊主动发送 | ❌ 不支持 | ✅ 应用消息 API | ✅ Webhook URL |
| 流式回复 | ✅ 打字机效果 | ❌ 仅完整消息 | ❌ 仅完整消息 |
| 思考过程展示 | ✅ thinking_content | ❌ | ❌ |
| 媒体发送 | ✅ msg_item (图片) | ✅ API 上传 (图片/文件) | ✅ base64/upload |
| Markdown | ✅ stream content | ✅ Markdown 消息类型 | ✅ Markdown 消息类型 |
消息接收机制:企业微信将用户消息以 JSON 格式通过 HTTP POST 回调到配置的 URL。支持私聊消息和群聊中 @提及机器人的消息。
消息回复机制:采用**流式分片(streaming)**回复。收到回调后立即返回 stream_id,后续通过 stream_refresh 轮询接口推送增量内容。客户端展示打字机效果。
- 被动回复:用户发消息 → 回调触发 → 流式回复(支持文本、Markdown、图片、思考过程)
- 主动发送:❌ 不支持。AI 机器人没有主动发送 API,只能在收到消息后回复
- 适用场景:实时对话、问答,流式体验好
消息接收机制:企业微信将用户消息以 XML 格式通过 HTTP POST 回调到配置的 URL。支持私聊和群聊消息,以及图片、语音、文件等多种消息类型。
消息回复机制:
-
被动回复:在回调响应中直接返回 XML 格式回复(需在 5 秒内响应)
-
主动发送:通过应用消息 API 可主动向用户发送文本、图片、文件、Markdown 等消息。支持指定
touser(用户)、toparty(部门)、totag(标签) -
适用场景:需要主动推送的场景(异步任务完成通知、定时报告),需要收发文件的场景
消息发送机制:通过 HTTP POST 请求向 Webhook URL 发送消息。支持文本、Markdown、图片(base64)、文件(需先上传获取 media_id)。
- 接收消息:❌ 不支持。Webhook 仅为单向发送通道
- 主动发送:✅ 向 Webhook URL POST 即可发送到群聊
- 适用场景:单向通知(告警、日报)、定时推送
Webhook 配置好后(见方式三),有以下方式发送消息:
openclaw message send --channel wecom --to "webhook:ops-group" "服务已恢复正常"让 agent 处理消息后将回复发到 webhook 群:
openclaw agent --agent myagent \
--message "帮我总结今天的监控告警" \
--deliver \
--reply-channel wecom \
--reply-to "webhook:ops-group"在 agent 配置中添加 heartbeat,自动定时触发并将回复发到 webhook 群:
{
"id": "report-agent",
"heartbeat": {
"every": "1h",
"target": "webhook:ops-group",
"prompt": "请总结最新的系统监控状态",
"activeHours": {
"start": "09:00",
"end": "18:00",
"timezone": "Asia/Shanghai"
}
}
}every— 触发间隔(如30m,1h,6h)target— 回复目标,webhook:前缀加配置中的 webhook 名称prompt— 每次触发时给 agent 的提示语activeHours— 可选,限制只在工作时间段内触发
# crontab -e
# 每天早上9点发送日报
0 9 * * * openclaw agent --agent report-agent --message "生成今日晨报" --deliver --reply-channel wecom --reply-to "webhook:ops-group"
# 每小时发送监控摘要
0 * * * * openclaw message send --channel wecom --to "webhook:monitor-group" "$(curl -s http://localhost:9090/api/v1/alerts | jq -r '.data.alerts | length') 条活跃告警"| 需求 | 推荐模式 |
|---|---|
| 实时对话,流式打字机体验 | Bot 模式 |
| 双向对话 + 主动推送 + 文件处理 | Agent 模式 |
| 仅需向群聊推送通知 | Webhook 模式 |
| 同时需要对话和群通知 | Bot/Agent 模式 + Webhook 模式 组合使用 |
💡 三种模式可以同时启用。例如:Bot 模式处理日常对话,Webhook 模式负责定时推送通知到群。配置时在同一个
channels.wecom下同时填写token/encodingAesKey(Bot)、agent(Agent)和webhooks(Webhook)即可。
| 类型 | 方向 | 说明 |
|---|---|---|
| 文本 (text) | 收/发 | 纯文本消息 |
| 图片 (image) | 收/发 | 入站图片自动解密;出站通过 msg_item base64 发送 |
| 语音 (voice) | 收 | 企业微信自动转文字后处理(仅限私聊) |
| 图文混排 (mixed) | 收 | 文本 + 图片混合消息 |
| 文件 (file) | 收 | 文件附件(下载后传给 AI 分析) |
| 位置 (location) | 收 | 位置分享(转换为文本描述) |
| 链接 (link) | 收 | 分享链接(提取标题、描述、URL 为文本) |
流式回复的 content 字段支持以下 Markdown 格式,企业微信客户端会自动渲染:
| 格式 | 语法 | 示例 |
|---|---|---|
| 加粗 | **text** |
加粗文本 |
| 斜体 | *text* |
斜体文本 |
| 行内代码 | `code` |
code |
| 代码块 | ```lang ... ``` |
多行代码 |
| 列表 | - item / 1. item |
有序/无序列表 |
| 标题 | # H1 / ## H2 |
各级标题 |
| 链接 | [text](url) |
超链接 |
当 LLM 模型(如 DeepSeek、QwQ 等支持思考模式的模型)在回复中输出 <think>...</think> 标签时,插件会自动:
- 解析
<think>标签,将思考内容与可见内容分离 - 映射 思考内容到企业微信流式回复的
thinking_content字段 - 展示 企业微信客户端会以可折叠的方式显示模型的思考过程
流式处理说明:
- 被动回复(首次同步响应)立即启用思考模式 UI,显示「思考中...」
- 当检测到未闭合的
<think>标签(流式输出中),thinking_content持续更新 </think>闭合后,思考内容固定,后续内容显示为可见回复- 代码块内的
<think>标签不会被解析(避免误匹配)
支持的标签变体: <think>, <thinking>, <thought>(均不区分大小写)
图片通过 msg_item 以 base64 编码在流式回复结束时发送:
- 仅在
finish=true(最终回复)时包含msgtype为image的msg_item - 流式过程中生成的图片会排队,待回复完成后一次性发送
- 单张图片最大 2MB,支持 JPG/PNG 格式,每条消息最多 10 张
管理员用户默认可以绕过指令白名单限制。若希望管理员用户同时跳过动态 Agent 路由(直接路由到主 Agent),可开启 dynamicAgents.adminBypass。
{
"channels": {
"wecom": {
"adminUsers": ["user1", "user2"],
"dynamicAgents": {
"adminBypass": true
}
}
}
}管理员用户 ID 不区分大小写,匹配企业微信的 userid 字段。
本插件实现"按人/按群隔离"的 Agent 管理:
- 企业微信消息到达后,插件生成确定性的
agentId:- 单账号私聊:
wecom-dm-<userId> - 单账号群聊:
wecom-group-<chatId> - 多账号私聊:
wecom-<accountId>-dm-<userId> - 多账号群聊:
wecom-<accountId>-group-<chatId>
- 单账号私聊:
- OpenClaw 自动创建/复用对应的 Agent 工作区
- 每个用户/群聊拥有独立的对话历史和上下文
- 管理员用户默认参与动态路由;当
dynamicAgents.adminBypass=true时跳过动态路由,直接使用主 Agent
配置在 channels.wecom 下:
{
"channels": {
"wecom": {
"dynamicAgents": {
"enabled": true
},
"dm": {
"createAgentOnFirstMessage": true
},
"groupChat": {
"enabled": true,
"requireMention": true
}
}
}
}| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
dynamicAgents.enabled |
boolean | true |
是否启用动态 Agent |
dynamicAgents.adminBypass |
boolean | false |
管理员是否跳过动态 Agent 路由 |
dm.createAgentOnFirstMessage |
boolean | true |
私聊使用动态 Agent |
groupChat.enabled |
boolean | true |
启用群聊处理 |
groupChat.requireMention |
boolean | true |
群聊必须 @ 提及才响应 |
如果需要所有消息进入默认 Agent:
{
"channels": {
"wecom": {
"dynamicAgents": { "enabled": false }
}
}
}支持在一个 OpenClaw 实例中接入多个企业微信机器人,每个机器人独立配置 Token、Agent 凭证、Webhook 等,互不干扰。
💡 典型场景:一个企业微信里创建多个 AI 机器人(如「客服助手」「技术支持」),各自对应不同的 Agent 和会话空间。
配置方式: 将 channels.wecom 下的值改为字典结构,每个 key 是账号 ID(如 bot1、bot2),value 包含该账号的完整配置:
{
"channels": {
"wecom": {
"bot1": {
"token": "Bot1 的 Token",
"encodingAesKey": "Bot1 的 EncodingAESKey",
"adminUsers": ["admin1"],
"workspaceTemplate": "/path/to/bot1-template",
"agent": {
"corpId": "企业 CorpID",
"corpSecret": "Bot1 应用 Secret",
"agentId": 1000001,
"token": "Bot1 回调 Token",
"encodingAesKey": "Bot1 回调 EncodingAESKey"
},
"webhooks": {
"ops-group": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
}
},
"bot2": {
"token": "Bot2 的 Token",
"encodingAesKey": "Bot2 的 EncodingAESKey",
"agent": {
"corpId": "企业 CorpID",
"corpSecret": "Bot2 应用 Secret",
"agentId": 1000002
}
}
}
}
}说明:
| 项目 | 说明 |
|---|---|
| 账号 ID | 字典的 key,如 bot1、bot2,仅支持小写字母、数字、-、_ |
| 完全兼容 | 旧的单账号配置(token 直接写在 wecom 下)自动识别为 default 账号,无需修改 |
| Webhook 路径 | 自动按账号分配:/webhooks/wecom/bot1、/webhooks/wecom/bot2 |
| Agent 回调路径 | 自动按账号分配:/webhooks/app/bot1、/webhooks/app/bot2 |
| 工作区模板 | 支持按账号自定义:channels.wecom.<accountId>.workspaceTemplate(覆盖全局配置) |
| 动态 Agent ID | 按账号隔离:wecom-bot1-dm-{userId}、wecom-bot2-group-{chatId} |
| 冲突检测 | 启动时自动检测重复的 Token 或 Agent ID,避免消息路由错乱 |
⚠️ 注意:多账号模式下,每个账号的 Webhook URL 需要在企业微信后台分别配置对应的路径(如/webhooks/wecom/bot1)。
可以为动态创建的 Agent 工作区预置初始化文件。当新 Agent 首次创建时,会自动从模板目录复制 bootstrap 文件。
{
"channels": {
"wecom": {
"workspaceTemplate": "/path/to/template-dir"
}
}
}支持的模板文件:
AGENTS.md- Agent 列表配置BOOTSTRAP.md- 初始化引导文档CLAUDE.md- Claude Code 指令集- 其他自定义文件
模板目录中的文件会复制到动态 Agent 的工作区(~/.openclaw/workspace-<agentId>/),仅当目标文件不存在时才会复制。
通过 OpenClaw 的 bindings 配置,可以将不同的 WeCom 账户绑定到不同的 Agent,实现多 Agent 精确路由。
{
"bindings": [
{
"agentId": "amy",
"match": {
"channel": "wecom",
"accountId": "bot1"
}
},
{
"agentId": "bob",
"match": {
"channel": "wecom",
"accountId": "bot2"
}
}
]
}- 当消息到达时,插件检查
bindings中是否有匹配当前channel: "wecom"和accountId的条目 - 如果匹配到 binding,使用 binding 指定的
agentId路由,不会被动态 Agent 覆盖 - 如果没有匹配的 binding,按正常的动态 Agent 路由逻辑处理
| 场景 | 路由结果 |
|---|---|
| 有匹配 binding | 使用 binding 中的 agentId |
| 无 binding + 动态 Agent 开启 | 自动生成 wecom-dm-<userId> 等 |
| 无 binding + 动态 Agent 关闭 | 使用默认 Agent |
💡 典型场景:多账号模式下,
bot1的所有消息路由到amyAgent,bot2的消息路由到bobAgent,各自拥有独立的指令集和上下文。
插件支持多种目标格式,用于消息路由和 Webhook 发送:
| 格式 | 示例 | 说明 |
|---|---|---|
webhook:<name> |
webhook:ops-group |
发送到配置的 Webhook 群 |
wecom:<userId> |
wecom:zhangsan |
企业微信用户 ID |
party:<id> |
party:2 |
部门 ID(数字) |
tag:<name> |
tag:Developers |
标签名称 |
group:<chatId> |
group:wr123456 |
群聊 ID |
chatId |
wr123456 |
以 wr 或 wc 开头的群聊 ID |
通过 OpenClaw 向企业微信发送消息时,可以使用上述格式指定目标:
# 发送给指定用户
openclaw send "wecom:zhangsan" "Hello!"
# 发送到 Webhook 群
openclaw send "webhook:dev-group" "部署成功!"
# 发送给部门
openclaw send "party:2" "全体员工通知"为防止普通用户通过企业微信消息执行敏感的 Gateway 管理指令,本插件支持指令白名单机制。
{
"channels": {
"wecom": {
"commands": {
"enabled": true,
"allowlist": ["/new", "/status", "/help", "/compact"]
}
}
}
}| 指令 | 说明 | 安全级别 |
|---|---|---|
/new |
重置当前对话,开启全新会话 | 用户级 |
/compact |
压缩当前会话上下文 | 用户级 |
/help |
查看帮助信息 | 用户级 |
/status |
查看当前 Agent 状态 | 用户级 |
安全提示:不要将
/gateway、/plugins等管理指令添加到白名单,避免普通用户获得 Gateway 实例的管理权限。配置在adminUsers中的管理员不受此限制。
当用户在短时间内(2 秒内)连续发送多条消息时,插件会自动将它们合并为一次 AI 请求。这样可以避免同一用户触发多个并发的 LLM 调用,提供更连贯的回复。
- 第一条消息的流式通道接收 AI 回复
- 后续被合并的消息会显示已合并的提示
- 指令消息(以
/开头)不参与防抖,会立即处理
A: 这是企业微信机器人创建模式选错导致的。企业微信提供两种机器人创建方式:
- 标准模式:回调消息为 XML 格式,本插件不支持
- API 模式:回调消息为 JSON 格式,本插件所需
解决方法:删除当前机器人,重新创建时在页面底部选择 "API 模式创建"。
A: 企业微信使用 AES-256-CBC 加密用户发送的图片。插件会自动:
- 从企业微信的 URL 下载加密图片
- 使用配置的
encodingAesKey解密 - 保存到本地并传给 AI 进行视觉分析
图文混排消息也完全支持——文本和图片会一起提取并发送给 AI。
A: 插件会自动处理 OpenClaw 生成的图片(如浏览器截图):
- 本地图片(来自
~/.openclaw/media/)会自动进行 base64 编码,通过企业微信msg_itemAPI 发送 - 图片限制:单张图片最大 2MB,支持 JPG 和 PNG 格式,每条消息最多 10 张图片
- 无需配置:开箱即用,配合浏览器截图等工具自动生效
- 图片会在 AI 完成回复后显示(流式输出不支持增量发送图片)
如果图片处理失败(超出大小限制、格式不支持等),文本回复仍会正常发送,错误信息会记录在日志中。
A: 支持!私聊中的语音消息会被企业微信自动转录为文字并作为文本处理,无需额外配置。
A: 支持。用户发送的文件会被下载并作为附件传给 AI。AI 可以分析文件内容(如读取 PDF 或解析代码文件)。MIME 类型根据文件扩展名自动检测。
A: Agent 模式提供更强大的消息收发能力,包括主动推送消息和接收 XML 格式回调。
配置步骤:
-
在企业微信管理后台创建"自建应用"
-
获取应用凭证:
corpId: 企业 ID(在"我的企业"页面)agentId: 应用 IDcorpSecret: 应用 Secret
-
设置接收消息:
- 获取
token和encodingAesKey(随机生成) - 回调 URL:
https://your-domain.com/webhooks/app
- 获取
-
在
openclaw.json中添加 Agent 配置:{ "channels": { "wecom": { "agent": { "corpId": "wwxxxxxxxxxxxxxxxx", "corpSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "agentId": 1000002, "token": "your_callback_token", "encodingAesKey": "your_43_char_encoding_aes_key" } } } }
Agent 模式与 Bot 模式的区别:
| 特性 | Bot 模式 | Agent 模式 |
|---|---|---|
| 创建方式 | 智能机器人 | 自建应用 |
| 回调格式 | JSON | XML |
| 主动推送 | 不支持 | 支持 |
| 媒体下载 | 不支持 | 支持 |
| 文件消息 | 不支持 | 支持 |
A: Webhook Bot 适用于向群聊发送通知消息。
配置步骤:
-
在企业微信群聊中添加"群机器人"
-
复制 Webhook URL(包含 key 参数)
-
在配置中添加 webhook 映射:
{ "channels": { "wecom": { "webhooks": { "ops-group": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx", "dev-group": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy" } } } } -
使用
webhook:前缀作为目标:- 文本:
webhook:ops-group - 支持 Markdown、图片、文件等多种消息类型
- 文本:
A: 插件采用四层回退机制确保消息可靠送达:
| 层级 | 条件 | 说明 |
|---|---|---|
| Layer 1 | 活跃流式通道 | 正常对话时,消息通过流式通道实时推送 |
| Layer 2 | response_url | 流式通道关闭后 1 小时内,可通过 response_url 发送 |
| Layer 3a | Webhook Bot | 目标以 webhook: 开头时,使用 Webhook 发送 |
| Layer 3b | Agent API | 配置了 Agent 时,通过自建应用 API 主动推送 |
当上一层级不可用时,自动回退到下一层级。这种设计确保了即使在流式通道关闭的情况下,AI 生成的异步消息(如定时任务、子 Agent 输出)仍能送达。
-
Gateway Auth Token (
gateway.auth.token) 主要用于:- WebUI 访问认证
- WebSocket 连接认证
- CLI 远程连接认证
-
企业微信 Webhook (
/webhooks/wecom) 的认证机制:- 使用企业微信自己的签名验证(Token + EncodingAESKey)
- 不需要 Gateway Auth Token
- OpenClaw 插件系统会自动处理 webhook 路由
部署建议:
- 如果使用反向代理(如 Nginx),可以为
/webhooks/wecom路径配置豁免认证 - 或者将 webhook 端点暴露在独立端口,不经过 Gateway Auth
A: 常见原因和解决方法:
-
检查配置键名:确保使用正确的键名
encodingAesKey(注意大小写){ "channels": { "wecom": { "encodingAesKey": "..." } } } -
检查密钥长度:EncodingAESKey 必须是 43 位字符
# 检查长度 echo -n "你的密钥" | wc -c
-
检查是否有多余空格/换行:确保密钥字符串前后没有空格或换行符
A: 这是企业微信对「自建应用 API 主动发送消息」的安全限制。错误码 60020 表示:当前服务器出口公网 IP 未加入企业微信应用的可信 IP 白名单。
典型日志示例:
[wecom] [agent-inbound] reply delivery failed {"error":"agent send text failed: 60020 not allow to access from your ip, ... from ip: xx.xx.xx.xx"}原因说明
当插件使用 Agent API 回退(或 Agent 模式主动推送)发送消息时,会调用企业微信开放接口(如 qyapi.weixin.qq.com)。 如果企业微信后台为该应用启用了 企业可信IP / 接口可信IP 校验,而当前服务器出口公网 IP 不在白名单内,企业微信会拒绝请求并返回 60020。
解决方法
-
登录企业微信管理后台
-
进入对应的 自建应用 详情页
-
找到 企业可信IP 配置项
-
将服务器公网出口 IP 加入白名单
- 建议以错误日志中的 from ip 为准(你的服务器公网ip)
-
保存配置后重试发送消息
openclaw-plugin-wecom/
├── index.js # 插件入口
├── package.json # npm 包配置
├── openclaw.plugin.json # OpenClaw 插件清单
├── crypto.js # 企业微信加密算法(消息 + 媒体)
├── logger.js # 日志模块
├── utils.js # 工具函数(TTL 缓存、消息去重)
├── stream-manager.js # 流式回复管理
├── think-parser.js # 思考标签解析(<think> 标签分离)
├── image-processor.js # 图片编码/校验(msg_item)
├── webhook.js # 企业微信 Bot 模式 HTTP 通信处理
├── dynamic-agent.js # 动态 Agent 分配逻辑
├── wecom/ # 核心模块目录
│ ├── channel-plugin.js # 主频道插件逻辑
│ ├── http-handler.js # HTTP 请求处理器
│ ├── agent-api.js # Agent API 客户端(AccessToken 缓存、消息发送)
│ ├── agent-inbound.js # Agent 模式入站处理器(XML 回调)
│ ├── webhook-bot.js # Webhook Bot 客户端
│ ├── inbound-processor.js # 入站消息处理器
│ ├── xml-parser.js # XML 解析器(Agent 模式)
│ ├── target.js # 目标解析器(支持多种目标格式)
│ ├── commands.js # 命令处理
│ ├── constants.js # 常量定义
│ ├── state.js # 状态管理
│ ├── stream-utils.js # 流式处理工具
│ ├── response-url.js # response_url 处理
│ ├── allow-from.js # 权限控制
│ ├── media.js # 媒体文件处理
│ ├── webhook-targets.js # Webhook 目标管理
│ └── workspace-template.js # 工作区模板
├── tests/ # 测试目录
│ ├── accounts-reserved-keys.test.js # 多账号保留键测试
│ ├── api-base-url.test.js # API 基础 URL 测试
│ ├── channel-plugin.media-type.test.js # 媒体类型测试
│ ├── dynamic-agent.test.js # 动态 Agent 路由测试
│ ├── http-handler.test.js # HTTP 处理器测试
│ ├── inbound-processor.image-merge.test.js # 图片合并测试
│ ├── issue-fixes.test.js # Issue 修复验证测试
│ ├── outbound.test.js # 出站投递回退逻辑测试
│ ├── outbound-security.test.js # 出站安全测试
│ ├── target.test.js # 目标解析器测试
│ ├── think-parser.test.js # 思考标签解析测试
│ ├── workspace-template.test.js # 工作区模板测试
│ └── xml-parser.test.js # XML 解析器测试
├── README.md # 本文档
├── CONTRIBUTING.md # 贡献指南
└── LICENSE # 开源协议
我们非常欢迎开发者参与贡献!如果你发现了 Bug 或有更好的功能建议,请提交 Issue 或 Pull Request。
本项目采用 ISC License 协议。
OpenClaw 支持自定义 Skills 并通过沙箱(Docker)隔离执行,以下是生产环境的实践配置:
{
"agents": {
"defaults": {
"sandbox": {
"mode": "all",
"workspaceAccess": "rw",
"scope": "agent",
"docker": {
"image": "your-registry.com/openclaw-agent:v2026.x.x",
"readOnlyRoot": false,
"network": "bridge",
"extraHosts": [
"your-domain.internal:xxx.xxx.xxx.xxx"
],
"binds": [
"/path/to/skills:/workspace/skills:ro"
],
"dangerouslyAllowReservedContainerTargets": true,
"dangerouslyAllowExternalBindSources": true
},
"prune": {
"idleHours": 87600,
"maxAgeDays": 3650
}
}
}
},
"skills": {
"allowBundled": ["_none_"],
"load": {
"extraDirs": ["/path/to/skills"],
"watch": true,
"watchDebounceMs": 250
}
}
}| 配置项 | 说明 |
|---|---|
sandbox.mode |
沙箱模式:all 所有操作都走沙箱 |
sandbox.workspaceAccess |
工作区访问权限:rw 读写 |
sandbox.scope |
沙箱作用域:agent 每个 Agent 独立沙箱 |
sandbox.docker.image |
沙箱使用的 Docker 镜像 |
sandbox.docker.readOnlyRoot |
是否只读根文件系统 |
sandbox.docker.network |
网络模式:bridge 桥接网络 |
sandbox.docker.binds |
挂载目录:将宿主机 skills 目录映射到沙箱内 /workspace/skills(只读) |
sandbox.docker.extraHosts |
添加额外 hosts,解决内网服务域名解析 |
sandbox.docker.dangerouslyAllowReservedContainerTargets |
允许容器访问保留目标 |
sandbox.docker.dangerouslyAllowExternalBindSources |
允许外部绑定源 |
sandbox.prune.idleHours |
空闲容器清理时间(小时) |
sandbox.prune.maxAgeDays |
容器最大存活天数 |
skills.allowBundled |
允许的内置 skills(["_none_"] 表示禁用所有内置) |
skills.load.extraDirs |
自定义 skills 加载目录 |
skills.load.watch |
启用热加载,修改 skill 无需重启 |
skills.load.watchDebounceMs |
热加载防抖时间(毫秒) |
- 在宿主机创建自定义 skill 目录
- 配置
binds将目录映射到沙箱 - 在
skills.load.extraDirs指定加载路径 - Agent 在沙箱中可通过
/workspace/skills访问自定义 skills - 使用
/skill命令查看和管理 skills