@dingxiang-me/openclaw-wechat
v2.3.0
Published
WeCom (企业微信) channel plugin for OpenClaw (自建应用回调 + 发送 API).
Readme
OpenClaw-Wechat 企业微信插件
OpenClaw-Wechat 是一个面向 OpenClaw 的企业微信渠道插件,支持两种接入方式:
Agent 模式:企业微信自建应用(XML 回调,经典模式)Bot 模式:企业微信智能机器人 API 模式(JSON 回调,原生 stream)Webhook 目标出站:将消息主动投递到企业微信群 Webhook 或命名 Webhook 目标
适用于“个人微信扫码进入企业微信应用对话”、“企业内员工问答助手”、“多账户多业务线消息分流”等场景。
目录
- 可靠投递更新(v2.2.0)
- 功能概览
- 模式对比
- 5 分钟极速上手
- 前置要求
- 安装与加载
- 配置文件与路径职责
- 快速开始
- 文档工具(WeCom Doc)
- 配置参考
- 消息能力矩阵
- 命令与会话策略
- 环境变量速查
- 公网回调与 Gateway Auth
- Webhook 与 Heartbeat 运维
- 与其他渠道并存建议
- 故障排查
- 开发与发布
- FAQ
- 版本与贡献
可靠投递更新(v2.2.0)
这版重点不在接入元信息,而是把 WeCom 回复链路补成“可感知、可补发、可诊断”的可靠投递。
这版新增了什么
| 项目 | 结果 |
|---|---|
| 可靠投递状态 | /status 新增 24h 窗口 / 主动发送额度 / Pending Reply 摘要 |
| Pending Reply | 最终回复投递失败后自动入队,支持定时重试和下次入站补发 |
| Pending Reply 持久化 | 可选落盘,gateway 重启后继续补发未送达的最终回复 |
| 配额感知 | 统一区分 窗口过期 / 额度不足 / 传输失败 / 目标无效 |
| 推理展示策略 | delivery.reasoning 可控制 <think> 内容分离显示、合并到最终回复或隐藏 |
| Selfcheck 摘要 | wecom:selfcheck / wecom:agent:selfcheck / wecom:bot:selfcheck 增加 reliable-delivery 摘要 |
| 群策略诊断 | /status 与 selfcheck 会显示当前群规则来源、准入模式以及白名单是否生效 |
| 最终回复格式 | delivery.replyFormat 支持 auto / text / markdown,会按链路选择纯文本或 markdown 能力 |
| 媒体指令 | 模型最终回复支持 MEDIA: / FILE: 指令,自动回传图片/文件并隐藏指令行 |
| Bot/Agent 收口 | Bot fallback 与 Agent 最终回复统一纳入可靠投递跟踪 |
| 长连接日志降噪 | 正常的 connect / opened / subscribed 继续保持 debug,默认日志更安静 |
这版对接入有什么实际影响
- 现在能直接看出当前会话是否仍在
24h回复窗口内,以及是否存在待补发的最终回复。 - Bot / Agent 不再只是超时兜底,而是会把失败结果分类并进入 Pending Reply 重试。
- selfcheck 会明确告诉你可靠投递追踪是否打开、是否持久化,以及当前推理展示模式。
- 群聊策略不再只能靠日志反推,
/status和 selfcheck 会直接说明当前命中的群规则来源与白名单是否真的在限制触发。 - Bot 长连接默认日志仍然更安静,排障时再开
debug看正常心跳和订阅细节。
当前推荐的接入顺序
现在 package / manifest / runtime channel meta 都会暴露同一套 quickstart metadata,便于 installer、quickstart、doctor 和后续集成入口读取同一份推荐模式、starter config 和 setup checklist。
- 先选一个主入口:
- Bot 长连接:适合最快跑通对话
- Agent:适合需要主动发送、菜单、自建应用能力
- 再决定私聊准入:
open:直接可聊allowlist:仅显式白名单pairing:首次私聊先审批
- 最后再加增强项:
bindingsdynamicAgentwecom_doc
Quickstart 命令
推荐入口:
npx -y @dingxiang-me/openclaw-wecom-cli install如果你更想留在仓库内执行同一套流程:
npm run wecom:quickstart -- --mode bot_long_connection
npm run wecom:doctor -- --json如果你想走交互式向导:
npm run wecom:quickstart -- --wizard如果你已经准备好了 WECOM_* / WECOM_BOT_* 环境变量,也可以使用兼容性的 env-backed 初始化路径:
export WECOM_BOT_LONG_CONNECTION_BOT_ID=your-bot-id
export WECOM_BOT_LONG_CONNECTION_SECRET=your-bot-secret
openclaw channels add --channel wecom --use-env这条 channels add --use-env 路径不需要任何 OpenClaw core 补丁,但它只适合 env-backed 初始化。
日常文档、排障和安装说明都默认以 installer / quickstart / doctor 为主路径;如果你需要完整接入和迁移闭环,仍然优先用 npx -y @dingxiang-me/openclaw-wecom-cli install。
常见用法:
# 默认推荐模式:Bot 长连接
npm run wecom:quickstart -- --json
# 交互式选择 mode / dm / 群策略,并决定是否直接写入配置
npm run wecom:quickstart -- --wizard
# 把推荐 selfcheck 也串起来跑;如仍有占位项,默认会先阻止执行
npm run wecom:quickstart -- --run-checks
# 即使还没填完占位项,也强制执行推荐检查
npm run wecom:quickstart -- --run-checks --force-checks
# 把修复用的 configPatch 和 .env 模板直接写到目录里
npm run wecom:quickstart -- --run-checks --repair-dir ./.wecom-repair
# 直接把生成的 repair configPatch 合并进目标 openclaw.json
npm run wecom:quickstart -- --run-checks --apply-repair
# 先预览将要修改的字段,再确认是否真的应用 repair patch
npm run wecom:quickstart -- --run-checks --confirm-repair
# 单独盘点当前配置里的 legacy / mixed-layout 问题,并生成迁移 patch
npm run wecom:migrate -- --json
# 一次性聚合安装状态、迁移状态、自检、长连接探针和回调矩阵
npm run wecom:doctor -- --json
# 跑本地黑盒 onboarding E2E:install -> doctor -> fix -> rerun
npm run test:e2e:local
# 检查 root 包、installer CLI、manifest 和 npm pack 产物是否一致
npm run test:release
# 生成 sales 账号的 Agent 回调模板
npm run wecom:quickstart -- --mode agent_callback --account sales --dm-mode allowlist
# 直接带一份群白名单模板(值班群/运营群)
npm run wecom:quickstart -- --mode hybrid --group-profile allowlist_template --group-chat-id wr-ops-room --group-allow ops_lead,oncall_user
# 直接合并写入 openclaw.json,并自动备份原文件
npm run wecom:quickstart -- --mode hybrid --write--group-profile 可选值有:inherit、mention_only、open_direct、allowlist_template、deny。
默认行为只打印 starter config 和检查清单;只有显式传 --write 才会写文件。
--wizard 会把当前 CLI 参数当作默认值,然后逐步提问,最后再确认是否写入 openclaw.json。
--run-checks 会按当前 mode 的推荐命令执行自检;若 starter config 里还有占位项,默认会阻止执行,除非显式传 --force-checks。
--apply-repair 会把 postcheck.repairArtifacts.configPatch 直接 merge 到 --config 指向的配置文件,并自动备份原文件。
--confirm-repair 会先打印将要修改的字段,再询问是否真正执行 --apply-repair;交互提示走 stderr,不会污染 --json 的机器输出。
npm run wecom:migrate -- --json 不再生成 starter config,只做当前安装 / 迁移状态盘点,适合排查 legacy_config / mixed_layout / stale_package。
npm run wecom:migrate -- --json 和 npm run wecom:doctor -- --json 现在还会给出 migrationSource,直接区分 official-wecom / sunnoy-wecom / legacy-openclaw-wechat / mixed-source。
npm run wecom:doctor -- --json 会把 migration + selfcheck + agent/bot e2e + longconn probe + callback matrix 聚合成一份报告;可以加 --skip-network 先只看本地安装 / 迁移问题。
npm run wecom:doctor -- --fix --skip-network --json 会先应用当前可落盘的本地 fix patch(例如 migration patch、plugins.allow/entries),再用修正后的配置重跑 doctor。
npm run wecom:doctor -- --confirm-fix --skip-network --json 会先预览将要修改的字段,再确认是否真正写回。
npm run wecom:quickstart -- --json 现在也会带 sourcePlaybook,把当前来源推荐的检查顺序、占位项提示和默认 repair 策略一起返回。
npx -y @dingxiang-me/openclaw-wecom-cli install 会先尝试执行 openclaw plugins install @dingxiang-me/openclaw-wechat,再写入 starter config,并可选继续跑本地 doctor。
npm run test:e2e:local 会黑盒验证 install -> doctor -> fix -> rerun 这条本地闭环,不依赖真实企微网络。
npm run test:release 会校验 root 包、installer CLI、manifest、运行时版本常量和 npm pack --dry-run 产物,适合作为发版前门禁。
如果当前配置更像官方插件 / sunnoy / 旧版 OpenClaw-Wechat,安装器会在 --json 输出里直接给出 migration.guide、来源说明、legacy 字段路径和回滚命令。
如果你想人工确认是否附带执行 doctor --fix,可以加 --confirm-doctor-fix;要强制不附带 --fix,可加 --no-doctor-fix,自动确认则用 --yes。
安装器的 --json 现在还会直接输出 actions,把来源审阅、迁移 patch、回滚和重跑 doctor 这些步骤结构化暴露出来。
如果你没有显式传 --mode,安装器还会按来源和现有能力自动选择 bot_long_connection / agent_callback / hybrid,并在 sourceProfile 里说明为什么这么选。
sourceProfile 现在还会给出来源专属 checkOrder 和 repairDefaults。例如官方 / legacy 来源默认允许自动附带 doctor --fix,而 sunnoy / mixed-source 来源默认只给修复建议,不会直接附带 --fix。
仓库现在也自带两条 GitHub Actions 门禁:Onboarding E2E 跑本地安装闭环,Release Check 跑版本/打包一致性;tag 发布会走独立 release workflow,顺序发布插件包和 installer CLI。
--json 输出会额外给出:
placeholders:还有哪些模板占位项没替换setupChecklist:下一步应该执行的管理台配置和自检命令actions:可被 CLI / UI 直接消费的结构化 setup flowinstallState / migrationState:当前是 fresh、legacy_config、stale_package、mixed_layout 还是 readymigrationSource / migrationSourceSummary:当前更接近官方插件、sunnoy 配置、legacy-openclaw-wechat,还是 mixed-sourcefix:doctor--fix是否已提示、确认、落盘,以及真实changedPathssourcePlaybook:quickstart 基于当前来源生成的推荐检查顺序、占位提示和 repair 默认值sourceProfile.checkOrder / sourceProfile.repairDefaults:当前来源推荐的检查顺序,以及 installer 默认采用的修复策略warnings:当前 mode / group profile 下仍需确认的风险点postcheck:推荐 selfcheck 的执行结果、阻塞原因或汇总状态postcheck.remediation:把失败检查翻译成可执行的修复建议postcheck.repairArtifacts:自动生成最小configPatch和.env模板,便于直接修复当前检查暴露的问题postcheck.repairPlan:按项列出 repair patch 的配置变更、env 变更和会写出的文件migration.configPatch / migration.envTemplate:当前 legacy 配置可直接迁移到的新布局建议
如果再加 --repair-dir <path>,quickstart 还会把这些修复产物直接落盘成:
wecom.config-patch.jsonwecom.account-patch.jsonwecom.env.templateREADME.txt
如果加的是 --apply-repair,则会在输出中额外看到 repairApply,说明 repair patch 是否已实际写入目标配置。
如果加的是 --confirm-repair,repairApply 里还会带 prompted/confirmed,方便区分“用户拒绝”与“自动执行”;真正写入的字段会出现在 repairApply.changedPaths。
5 分钟极速上手
适合“先跑起来再细调”的场景。
Step 1. 安装插件
最快入口:
npx -y @dingxiang-me/openclaw-wecom-cli install它会复用仓库内的 quickstart / migrate / doctor 能力,把“安装插件 + 写 starter config + 跑本地体检”串成一次执行。
如果你只想单独安装插件包:
openclaw plugins install @dingxiang-me/openclaw-wechat最低建议版本:
2.3.0。如果openclaw.json里的plugins.installs.openclaw-wechat仍显示1.7.x,请先升级或重装;旧包不会正确注册wecomchannel 元数据,也不包含当前这套接入、迁移与可靠投递能力。
如果你是在本地开发或要直接跑仓库源码,再用下面这套:
git clone https://github.com/dingxiang-me/OpenClaw-Wechat.git
cd OpenClaw-Wechat
npm installStep 2. 在 OpenClaw 里启用插件
如果你是通过 openclaw plugins install 安装,在 ~/.openclaw/openclaw.json 增加:
{
"plugins": {
"enabled": true,
"allow": ["openclaw-wechat"],
"entries": {
"openclaw-wechat": {
"enabled": true
}
}
}
}如果你是源码路径加载,再使用下面这版(多一个 load.paths):
{
"plugins": {
"enabled": true,
"allow": ["openclaw-wechat"],
"load": {
"paths": ["/path/to/OpenClaw-Wechat"]
},
"entries": {
"openclaw-wechat": {
"enabled": true
}
}
}
}Step 3. 选择一种模式配置
| 模式 | 回调路径 | 企业微信侧类型 | 最少需要的配置 |
|---|---|---|---|
| Agent(自建应用) | /wecom/callback | 自建应用 API 接收 | corpId/corpSecret/agentId/callbackToken/callbackAesKey |
| Bot(智能机器人) | /wecom/bot/callback | 智能机器人 API 模式 | bot.enabled/token/encodingAesKey |
| Bot(智能机器人长连接) | 无需公网回调 | 智能机器人 长连接模式 | bot.enabled/bot.longConnection.enabled/bot.longConnection.botId/bot.longConnection.secret |
Agent 模式补充(重要):在企业微信自建应用后台请配置可信 IP,把 OpenClaw 网关实际出网 IP 加入白名单。否则可能出现“能收到消息但不回复”。
如果你希望私聊先审批,再开放会话,可以直接加:
{
"channels": {
"wecom": {
"dm": {
"mode": "pairing"
}
}
}
}Step 4. 重启并自检
openclaw gateway restart
openclaw gateway status
npm run wecom:selfcheck -- --all-accounts
npm run wecom:agent:selfcheck -- --all-accounts
npm run wecom:bot:selfcheck -- --all-accounts现在自检输出会先给出两行摘要:
readiness: 当前是否能收、能回、能发routing: 当前是否启用bindings和dynamicAgent
Step 5. 发一条消息验证
| 验证项 | 预期结果 |
|---|---|
| 文本消息 | 机器人返回文本 |
| 图片消息(Bot) | 不再提示“图片接收失败”,可识别图像内容 |
| openclaw gateway status | RPC probe: ok 且 WeCom 状态正常 |
功能概览
核心能力
| 能力 | 状态 | 说明 |
|---|---|---|
| 企业微信入站消息处理 | ✅ | 文本、图片、语音、链接、文件/视频(Agent + Bot) |
| AI 自动回复 | ✅ | 接入 OpenClaw Runtime,自动路由 Agent |
| Bot 原生 stream 协议 | ✅ | msgtype=stream 刷新与增量回包 |
| Bot 长连接(WebSocket) | ✅ | 原生 aibot_subscribe / aibot_msg_callback / aibot_respond_msg |
| Bot 卡片回包 | ✅ | 支持 markdown/template_card,失败自动降级文本 |
| 多账户 | ✅ | channels.wecom.accounts.<id> |
| 发送者授权控制 | ✅ | allowFrom + 账户级覆盖 |
| 私聊策略(DM) | ✅ | dm.mode=open/allowlist/pairing/deny + 账户级覆盖 |
| 事件欢迎语(enter_agent) | ✅ | events.enterAgentWelcome* 可配置 |
| 命令白名单 | ✅ | /help /status /clear /new 等 |
| 群聊触发策略 | ✅ | 支持 direct/mention/keyword 三种模式 |
| 企业微信文档工具 | ✅ | 内置 wecom_doc 工具:创建/重命名/分享/权限管理/收集表/表格属性 |
| 文本防抖合并 | ✅ | 窗口期内多条消息合并投递 |
| 异步补发(超时后) | ✅ | transcript 轮询补发最终回复 |
| 观测统计 | ✅ | 入站/回包/错误计数 + 最近失败样本(/status) |
| WeCom 出站代理 | ✅ | outboundProxy / WECOM_PROXY |
媒体能力
| 能力 | 状态 | 说明 |
|---|---|---|
| 图片识别(入站) | ✅ | 支持 URL 下载、类型识别、必要时解密后识别 |
| 图片发送(出站) | ✅ | Agent 模式支持 |
| 语音/视频/文件发送(出站) | ✅ | 自动判型上传后发送(语音支持 AMR/SILK) |
| 语音转写(本地) | ✅ | 企业微信 Recognition 优先,缺失时回退本地 whisper |
| Bot 模式媒体回传 | ✅ | active_stream 优先 msg_item(image);失败自动降级媒体链接,response_url/Webhook Bot 继续兜底 |
| Bot 思考过程展示 | ✅ | 识别 <think>/<thinking>/<thought>,映射到原生 thinking_content 折叠区 |
| Bot 文件入站 | ✅ | 支持 msgtype=file 下载并注入会话上下文 |
| Bot 引用消息上下文 | ✅ | 自动将 quote 内容前置到本轮上下文 |
模式对比
| 维度 | Agent 模式(自建应用) | Bot 模式(智能机器人 API) |
|---|---|---|
| 回调数据格式 | XML | JSON |
| 企业微信创建方式 | 应用管理 -> 自建应用 | 智能机器人 -> API 模式 |
| 回调路径默认值 | /wecom/callback | /wecom/bot/callback |
| 回复机制 | 主动调用 WeCom 发送 API | 回调响应 stream + 轮询刷新 |
| 流式体验 | 多条消息模拟增量 | 原生 stream 协议 |
| 思考展示 | 不适用 | 支持 <think> 标签映射到 thinking_content |
| 出站媒体(图/语音/视频/文件) | 支持 | 支持(active_stream msg_item(image) + response_url/Webhook 回包,video 自动按 file 回传) |
| 典型场景 | 标准企业应用、菜单/回调体系 | 对话机器人、连续流式问答 |
回调路径规划建议
| 场景 | 建议 |
|---|---|
| 同时开 Agent + Bot | 使用不同路径:/wecom/callback 与 /wecom/bot/callback |
| 多账户 Agent | 每个账户独立路径(如 /wecom/sales/callback) |
| 与 Telegram/Feishu 并存 | 不复用任何 webhook path,避免路由冲突 |
前置要求
| 项目 | 说明 |
|---|---|
| OpenClaw | 已安装并可正常运行 Gateway |
| 企业微信管理员权限 | 可创建应用或智能机器人并配置回调 |
| 公网入口 | 企业微信需回调到可访问 URL(常见用 Cloudflare Tunnel) |
| Node.js | 与 OpenClaw 运行环境一致 |
| 本地语音识别(可选) | whisper-cli 或 whisper |
| ffmpeg(推荐) | AMR 等格式转码时需要 |
安装与加载
方式 A:通过 OpenClaw 安装(推荐)
openclaw plugins install @dingxiang-me/openclaw-wechat安装后插件会进入 ~/.openclaw/extensions/openclaw-wechat/。这个目录主要用于 OpenClaw 运行时发现插件,通常不建议直接手改其中的 package.json、package-lock.json、openclaw.plugin.json。
方式 B:本地路径加载(开发模式)
git clone https://github.com/dingxiang-me/OpenClaw-Wechat.git
cd OpenClaw-Wechat
npm install在 ~/.openclaw/openclaw.json 中配置插件加载:
{
"plugins": {
"enabled": true,
"allow": ["openclaw-wechat"],
"load": {
"paths": ["/path/to/OpenClaw-Wechat"]
},
"entries": {
"openclaw-wechat": {
"enabled": true
}
}
}
}配置文件与路径职责
Issue #25 里问到的几个路径,职责完全不同。先把边界理清:
| 路径 | 应不应该手改 | 作用 |
|---|---|---|
| ~/.openclaw/openclaw.json | 应该 | OpenClaw 主配置入口。插件加载、channels.wecom.*、bindings、env.vars 都写这里 |
| ~/.openclaw/extensions/openclaw-wechat/package.json | 一般不要 | 已安装插件包的元数据,不是业务配置入口 |
| ~/.openclaw/extensions/openclaw-wechat/openclaw.plugin.json | 一般不要 | 插件 manifest / schema,供 OpenClaw 识别配置结构 |
| ~/.openclaw/extensions/openclaw-wechat/package-lock.json | 不要 | 安装锁文件,不承载运行配置 |
| ~/.openclaw/agents/<id>/sessions/sessions.json | 不要 | 运行时会话索引,属于状态数据,不是配置文件 |
| ~/.openclaw/agents/<id>/sessions/*.jsonl | 不要 | 会话 transcript / 运行产物 |
Windows 对应关系也是同一套逻辑,例如:
| Windows 示例路径 | 结论 |
|---|---|
| D:\\Win\\AppData\\LocalLow\\.openclaw\\openclaw.json | 这是主配置文件,参数加这里 |
| D:\\Win\\AppData\\LocalLow\\.openclaw\\extensions\\openclaw-wechat\\openclaw.plugin.json | 这是插件 schema,不是让你填业务参数的地方 |
| D:\\Win\\AppData\\LocalLow\\.openclaw\\agents\\main\\sessions\\sessions.json | 这是运行态索引,不要手动写参数 |
参数应该放到哪里
| 参数类型 | 推荐位置 |
|---|---|
| 插件启用 / 加载 | plugins.enabled、plugins.allow、plugins.entries.openclaw-wechat |
| 企业微信业务配置 | channels.wecom.* |
| 多账号配置 | channels.wecom.accounts.<id>.* |
| 文档工具默认账号 | channels.wecom.defaultAccount |
| 账号到 Agent 路由 | OpenClaw 根配置 bindings |
| 敏感信息 | 优先 env.vars.* 或系统环境变量;其次写入 openclaw.json |
Control UI、文件、环境变量怎么分工
| 方式 | 适合什么 |
|---|---|
| Control UI | 日常调整常规字段:corpId、callbackToken、accounts.*、tools.doc |
| openclaw.json | 结构化配置、版本管理、多人协作、bindings |
| env.vars / 系统环境变量 | Secret、代理、不同环境下的覆盖项 |
快速开始
1) 企业微信侧准备
Agent 模式(自建应用)
- 创建自建应用,拿到
AgentId、Secret - 在“我的企业”拿到
CorpId - 开启“接收消息”,配置:
- URL:
https://你的域名/wecom/callback - Token: 自定义随机字符串
- EncodingAESKey: 企业微信生成
- URL:
Bot 模式(智能机器人)
- 创建智能机器人时选择 API 模式
- 配置回调 URL:
https://你的域名/wecom/bot/callback - 获取并保存
token与encodingAesKey
2) OpenClaw 最小配置示例
Agent 最小可用
{
"channels": {
"wecom": {
"enabled": true,
"corpId": "wwxxxx",
"corpSecret": "xxxx",
"agentId": 1000004,
"callbackToken": "xxxx",
"callbackAesKey": "xxxx",
"webhookPath": "/wecom/callback"
}
}
}Bot 最小可用(Bot-only)
{
"channels": {
"wecom": {
"enabled": true,
"bot": {
"enabled": true,
"token": "xxxx",
"encodingAesKey": "xxxx",
"webhookPath": "/wecom/bot/callback"
}
}
}
}Bot 长连接最小可用(无需公网 Bot 回调)
{
"channels": {
"wecom": {
"enabled": true,
"bot": {
"enabled": true,
"longConnection": {
"enabled": true,
"botId": "your-bot-id",
"secret": "your-bot-secret"
}
}
}
}
}3) 启动与验证
openclaw gateway restart
openclaw gateway status
openclaw plugins list
npm run wecom:selfcheck -- --all-accounts
npm run wecom:bot:selfcheck -- --account defaultwecom:selfcheck 帮助:
node ./scripts/wecom-selfcheck.mjs --helpwecom:bot:selfcheck 帮助:
node ./scripts/wecom-bot-selfcheck.mjs --help文档工具(WeCom Doc)
插件现在内置了 wecom_doc 工具,不需要额外安装第二个插件。它复用当前 OpenClaw-Wechat 的账号、代理和多账户配置。
当前 wecom_doc 重点覆盖创建、权限、分享、收集表和诊断能力;不包含富文本正文编辑器式的文档内容编辑。如果需要改正文,请先在产品描述里明确这是后续能力,不要按“已支持编辑”对外承诺。
支持的动作
| action | 说明 | 关键参数 |
|---|---|---|
| create | 新建文档/表格,可创建后立即授权 | docName docType viewers? collaborators? |
| rename | 重命名文档 | docId newName |
| get_info | 获取文档基础信息 | docId |
| share | 获取文档分享信息 | docId |
| get_auth | 获取文档权限信息 | docId |
| diagnose_auth | 诊断为什么打不开文档/链接 | docId |
| validate_share_link | 校验分享链接对 guest/外部访问是否可用 | shareUrl |
| delete | 删除文档或收集表 | docId 或 formId |
| grant_access | 批量增删查看人/协作者 | docId viewers? collaborators? remove*? |
| add_collaborators | 快速添加协作者 | docId collaborators |
| set_join_rule | 修改文档可见范围/加入规则 | docId request |
| set_member_auth | 修改文档通知成员与权限 | docId request |
| set_safety_setting | 修改文档安全设置 | docId request |
| create_collect | 创建收集表 | formInfo spaceId? fatherId? |
| modify_collect | 修改收集表 | oper formId formInfo |
| get_form_info | 获取收集表定义 | formId |
| get_form_answer | 获取收集表答案 | repeatedId answerIds? |
| get_form_statistic | 获取收集表统计 | requests |
| get_sheet_properties | 获取在线表格属性 | docId |
启用方式
默认启用。你也可以显式配置:
{
"channels": {
"wecom": {
"defaultAccount": "docs",
"tools": {
"doc": true,
"docAutoGrantRequesterCollaborator": true
},
"accounts": {
"docs": {
"corpId": "wwxxxx",
"corpSecret": "xxxx",
"agentId": 1000008,
"tools": {
"doc": true
}
}
}
}
}
}账号选择规则
wecom_doc 在执行时按下面顺序选择账号:
- 工具参数里的
accountId - 当前 agent 绑定账号
channels.wecom.defaultAccount- 第一个启用了文档工具的可用账号
创建后自动授权
默认开启:如果 wecom_doc 是在企业微信会话里被调用,插件会把当前发送者自动加成文档协作者,避免“文档已创建但发起人无权限查看”。
create / share 结果现在会明确返回真实 docId,后续做权限、分享和诊断时应优先使用这个 docId,不要直接拿分享链接路径里的片段代替。
可关闭:
{
"channels": {
"wecom": {
"tools": {
"doc": true,
"docAutoGrantRequesterCollaborator": false
}
}
}
}使用示例
- “帮我新建一个企微文档,标题是《周会纪要》”
- “把这个文档改名为《Q2 Roadmap》”
- “查询文档
docxxxx的权限信息” - “诊断为什么这个企微文档链接打不开”
- “校验这个企微文档分享链接为什么对外打不开”
- “创建一个企微文档,并把我加成协作者”
- “给文档
docxxxx添加协作者dingxiang” - “把文档
docxxxx授权给alice查看,给bob协作” - “把文档
docxxxx的查看规则改成仅企业内部可见” - “创建一个收集表,标题是《报名表》”
- “查询收集表
formxxxx的定义和题目” - “读取这份收集表最近一次提交答案”
- “获取这个表格的 sheet 属性”
推荐工作流
| 目标 | 推荐动作顺序 |
|---|---|
| 创建后立刻给业务同事协作 | create -> grant_access / add_collaborators |
| 判断“为什么别人打不开这个文档” | diagnose_auth -> validate_share_link |
| 给外部链接排障 | 先看 validate_share_link,再决定是否执行 set_join_rule |
| 后续继续操作同一文档 | 始终使用 create/share 返回的真实 docId,不要直接复制分享链接路径片段 |
常见误区
| 误区 | 正确做法 |
|---|---|
| 分享链接路径里的 ID 就是 docId | 不一定。以后续工具返回的真实 docId 为准 |
| “加了协作者”就等于任何浏览器都能打开 | 不是。协作者权限、企业内访问、企业外访问、外部分享是不同层级 |
| 链接能在企业微信里打开,就代表外部环境也能打开 | 不成立。guest 视角可能仍然是 blankpage |
配置参考
主配置键(channels.wecom)
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
| enabled | boolean | true | 是否启用 WeCom 渠道 |
| corpId | string | - | 企业 ID(Agent 模式) |
| corpSecret | string | - | 应用 Secret(敏感) |
| agentId | number/string | - | 应用 AgentId |
| callbackToken | string | - | 回调 Token(敏感) |
| callbackAesKey | string | - | 回调 AES Key(敏感) |
| webhookPath | string | /wecom/callback | Agent 回调路径(非 default 账户未配置时自动生成 /wecom/<accountId>/callback) |
| agent | object | - | 兼容旧配置:agent.corpId/corpSecret/agentId(与顶层 Agent 字段等价) |
| outboundProxy | string | - | WeCom 出站代理 |
| apiBaseUrl | string | https://qyapi.weixin.qq.com | 可选:覆盖默认 WeCom API Base URL |
| defaultAccount | string | - | 多账号下的默认账号 ID(文档工具等优先使用) |
| tools.doc | boolean | true | 是否启用 wecom_doc 文档工具 |
| webhooks | object | - | 命名 Webhook 目标映射(如 { "ops": "https://...key=xxx" }) |
| accounts | object | - | 多账户配置(支持 accounts.<id>.bot 独立 Bot 配置) |
兼容说明:支持旧字段与旧结构迁移:name、token / encodingAesKey、agent.*、dynamicAgents.*、dm.createAgentOnFirstMessage、dm.allowFrom、workspaceTemplate、commandAllowlist/commandBlockMessage、commands.blockMessage、inline 账户写法 channels.wecom.<accountId>,以及官方 / sunnoy 风格的 botId、secret、network.egressProxyUrl、network.apiBaseUrl。新配置建议优先使用 accounts.<id>、callbackToken/callbackAesKey、bot.longConnection.*、outboundProxy/apiBaseUrl、commands.* 与 dynamicAgent.*。
提示:accounts.<id> 现在支持 Bot-only 账号(仅配置 bot.*),不再强制要求 corpId/corpSecret/agentId。
兼容提示:当使用默认新路径时会自动附加 legacy alias,便于旧回调地址平滑迁移:Agent 默认路径会附加 /webhooks/app(多账号为 /webhooks/app/<id>),Bot 默认路径会附加 /webhooks/wecom(多账号为 /webhooks/wecom/<id>)。若 alias 与另一类路由冲突会自动跳过并告警。
Bot 配置(channels.wecom.bot)
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
| enabled | boolean | false | 启用 Bot 模式 |
| token | string | - | Bot 回调 Token(敏感) |
| encodingAesKey | string | - | Bot 回调 AESKey(43 位,敏感) |
| webhookPath | string | /wecom/bot/callback | Bot 回调路径(非 default 账户未配置时自动生成 /wecom/<accountId>/bot/callback) |
| placeholderText | string | 消息已收到... | stream 初始占位文案(可设为空字符串) |
| streamExpireMs | integer | 600000 | stream 状态保留时间(30s~1h) |
| replyTimeoutMs | integer | 90000 | Bot 等待模型回包超时(15s~10m) |
| lateReplyWatchMs | integer | 180000 | Bot 超时后异步补发观察窗口(30s~10m) |
| lateReplyPollMs | integer | 2000 | Bot 异步补发轮询间隔(500ms~10s) |
| longConnection | object | - | 企业微信智能机器人长连接(WebSocket)配置 |
| card | object | 见下方 | Bot 卡片回包策略(response_url / webhook_bot) |
重要限制:企业微信官方 Bot 在群聊里通常仅对
@机器人消息触发回调。
因此 Bot 模式下即使配置groupChat.triggerMode=direct/keyword,也会按mention处理(插件会输出告警)。
Bot 长连接配置(channels.wecom.bot.longConnection)
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
| enabled | boolean | false | 启用企业微信智能机器人长连接 |
| botId | string | - | 企业微信智能机器人 BotID |
| secret | string | - | 企业微信智能机器人 Secret(敏感) |
| url | string | wss://openws.work.weixin.qq.com | 官方长连接地址 |
| pingIntervalMs | integer | 30000 | 心跳 ping 间隔 |
| reconnectDelayMs | integer | 5000 | 首次重连延迟 |
| maxReconnectDelayMs | integer | 60000 | 指数退避最大重连延迟 |
说明:
- 长连接模式下不需要暴露公网 Bot 回调地址。
- 插件会在网关启动后主动连接
wss://openws.work.weixin.qq.com,并自动发送aibot_subscribe。 - 入站消息与事件分别使用
aibot_msg_callback/aibot_event_callback,统一接入现有 Bot 处理链路。 - 模型 block 输出会直接通过长连接发送
aibot_respond_msg,不是被动等待stream-refresh拉取。
Bot 卡片配置(channels.wecom.bot.card)
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
| enabled | boolean | false | 启用卡片回包 |
| mode | string | markdown | markdown(兼容优先)或 template_card |
| title | string | OpenClaw-Wechat | 卡片标题 |
| subtitle | string | - | 卡片副标题 |
| footer | string | - | 卡片底部说明 |
| maxContentLength | integer | 1400 | 卡片正文最大长度(自动截断) |
| responseUrlEnabled | boolean | true | 是否在 response_url 层发送卡片 |
| webhookBotEnabled | boolean | true | 是否在 webhook_bot 层发送卡片 |
多账户 Bot 覆盖配置(channels.wecom.accounts.<id>.bot)
当你启用了 accounts 多账户时,可以为每个账户单独配置 Bot 回调密钥、路径、超时和代理;若未配置,则回退到 channels.wecom.bot。
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
| enabled | boolean | false | 是否启用该账户 Bot |
| token / callbackToken | string | - | 该账户 Bot 回调 Token(兼容旧字段) |
| encodingAesKey / callbackAesKey | string | - | 该账户 Bot 回调 AESKey(兼容旧字段) |
| webhookPath | string | /wecom/bot/callback | 该账户 Bot 回调路径 |
| placeholderText | string | 消息已收到... | stream 初始占位文案 |
| streamExpireMs | integer | 600000 | stream 状态保留时间 |
| replyTimeoutMs | integer | 90000 | Bot 等待模型回包超时 |
| lateReplyWatchMs | integer | 180000 | 超时后异步补发观察窗口 |
| lateReplyPollMs | integer | 2000 | 异步补发轮询间隔 |
| longConnection | object | - | 该账户专用长连接配置(覆盖全局 bot.longConnection) |
| card | object | - | 该账户专用卡片回包配置(覆盖全局 bot.card) |
兼容提示:如果你是从官方插件或 sunnoy 配置直接迁移,也可以先保留 channels.wecom.botId/secret 或 accounts.<id>.botId/secret,以及 network.egressProxyUrl/apiBaseUrl;插件会在运行时兼容读取,npm run wecom:migrate -- --json 会给出归一化 patch。
多账户文档工具覆盖(channels.wecom.accounts.<id>.tools)
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
| doc | boolean | true | 是否启用该账户的 wecom_doc 工具 |
| outboundProxy / proxyUrl / proxy | string | - | 该账户 Bot 专用代理(优先于全局) |
授权与指令策略
| 模块 | 配置键 | 作用 |
|---|---|---|
| 发送者授权 | allowFrom / accounts.<id>.allowFrom | 限定可对话用户;支持 * |
| 拒绝文案 | allowFromRejectMessage | 未授权提示 |
| 管理员 | adminUsers | 绕过命令白名单 |
| 命令白名单 | commands.enabled + commands.allowlist | 限制 / 指令 |
| 私聊策略 | dm.mode + dm.allowFrom + dm.rejectMessage | 控制私聊开放/白名单/配对审批/拒绝 |
| 事件策略 | events.enabled + events.enterAgentWelcomeEnabled + events.enterAgentWelcomeText | 控制事件处理与 enter_agent 欢迎语 |
| 群聊触发 | groupChat.enabled + triggerMode + mentionPatterns + triggerKeywords | 控制群消息触发条件(自建应用支持 direct/mention/keyword;Bot 模式按平台限制固定 mention) |
| 群聊准入策略 | groupPolicy + groupChat.policy + groups.<chatId>.policy | 显式控制 open / allowlist / deny;支持账户级覆盖与按群覆盖 |
| 群聊成员授权 | groupAllowFrom + groups.<chatId>.allowFrom | 与 allowlist 搭配使用,控制哪些群成员可以触发机器人;支持账户级覆盖与按群覆盖 |
| 动态路由 | dynamicAgent.*(兼容 dynamicAgents.*、dm.createAgentOnFirstMessage) | 动态 Agent + workspace bootstrap 播种 |
吞吐与稳定性
| 模块 | 配置键 | 说明 |
|---|---|---|
| 文本防抖 | debounce.enabled/windowMs/maxBatch | 合并短时间多条文本 |
| Agent 增量回包 | streaming.enabled/minChars/minIntervalMs | 多消息模拟流式 |
| 异步补发 | WECOM_LATE_REPLY_WATCH_MS/POLL_MS | dispatch 超时后补发最终回复 |
| Pending Reply 持久化 | delivery.pendingReply.persist/storeFile | 重启后恢复未送达最终回复;未指定 storeFile 时自动写入 OpenClaw state 目录 |
| 推理展示 | delivery.reasoning.mode/title/maxChars | 控制 <think> / reasoning 分离显示、附加到最终回复,或完全隐藏 |
| 最终回复格式 | delivery.replyFormat | auto / text / markdown;优先在支持的 WeCom 链路上保留 markdown,其余链路自动回退纯文本 |
| 观测统计 | observability.enabled/logPayloadMeta | 记录入站/回包/错误并在 /status 展示 |
语音转写(本地)
| 键 | 默认 | 说明 |
|---|---|---|
| voiceTranscription.enabled | true | 开启回退转写 |
| provider | local-whisper-cli | local-whisper-cli / local-whisper |
| command | 自动探测 | 本地命令路径 |
| modelPath | - | whisper-cli 模型路径 |
| model | base | whisper 模型名 |
| timeoutMs | 120000 | 单次转写超时 |
| maxBytes | 10485760 | 最大音频大小 |
| ffmpegEnabled | true | 不兼容格式自动转码 |
| transcodeToWav | true | 优先转为 wav |
多账户示例
{
"channels": {
"wecom": {
"outboundProxy": "http://127.0.0.1:7890",
"accounts": {
"default": {
"enabled": true,
"corpId": "ww-default",
"corpSecret": "secret-default",
"agentId": 1000004,
"callbackToken": "token-default",
"callbackAesKey": "aes-default",
"webhookPath": "/wecom/callback",
"allowFrom": ["*"]
},
"sales": {
"enabled": true,
"corpId": "ww-sales",
"corpSecret": "secret-sales",
"agentId": 1000005,
"callbackToken": "token-sales",
"callbackAesKey": "aes-sales",
"webhookPath": "/wecom/sales/callback",
"outboundProxy": "http://10.0.0.5:8888",
"bot": {
"enabled": true,
"token": "sales-bot-token",
"encodingAesKey": "sales-bot-aes",
"webhookPath": "/wecom/sales/bot/callback",
"replyTimeoutMs": 120000,
"outboundProxy": "http://10.0.0.9:7890"
},
"allowFrom": ["alice", "wecom:bob"],
"allowFromRejectMessage": "销售助手未授权,请联系管理员。"
}
}
}
}
}使用 OpenClaw bindings 做账号级 Agent 路由
OpenClaw-Wechat 不自己实现第二套路由规则;账号到 Agent 的稳定绑定,直接走 OpenClaw 核心 bindings。插件会把 channel=wecom 和 accountId=<id> 传给核心路由层。
示例:
{
"bindings": [
{
"match": {
"channel": "wecom",
"accountId": "sales"
},
"agentId": "sales"
},
{
"match": {
"channel": "wecom",
"accountId": "support"
},
"agentId": "support"
}
]
}这套绑定优先级高于插件里的动态账号猜测,适合多账号、多业务线、同一 OpenClaw 上挂多个 WeCom 入口的场景。
消息能力矩阵
Agent 模式
| 类型 | 入站 | 出站 | 备注 | |---|---|---|---| | 文本 | ✅ | ✅ | 自动分段 | | 图片 | ✅ | ✅ | 入站可识别,出站可发送 | | 语音 | ✅ | ✅ | 入站支持本地转写回退;出站支持 AMR/SILK | | 视频 | ✅ | ✅ | 下载并可回包 | | 文件 | ✅ | ✅ | 下载并可回包 | | 链接 | ✅ | ❌ | 提取标题/描述/URL |
Bot 模式
| 类型 | 入站 | 出站 | 备注 |
|---|---|---|---|
| 文本 | ✅ | ✅ | 原生 stream |
| 图片 | ✅ | ✅ | response_url mixed + webhook fallback |
| 语音 | ✅ | ✅ | 以文本结果回传 |
| 文件 | ✅ | ✅ | Bot 文件入站下载;出站可按 file 回传 |
| mixed(图文) | ✅ | ✅ | 聚合后回文本 |
| 链接/位置 | ✅ | ✅ | 转换为文本上下文 |
命令与会话策略
命令
| 命令 | 说明 |
|---|---|
| /help | 查看帮助 |
| /status | 查看运行状态 |
| /clear | 清理会话(兼容映射到 /reset) |
| /new | 新建会话(兼容映射到 /reset) |
| /reset | 重置会话 |
| /compact | 压缩会话(由上层运行时支持) |
会话策略
- 默认账号一用户一会话:
wecom:<userid> - 非默认账号一用户一会话:
wecom:<accountId>:<userid> - 群聊可配置“仅 @ 才触发”,避免误触发
出站目标格式
user:wecom:alice/user:alicegroup(chat):group:wrxxxx/chat:wcxxxx(自动走appchat/send)party:party:2/dept:2tag:tag:opswebhook:webhook:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx或webhook:key:xxxwebhook(命名):webhook:ops(从channels.wecom.webhooks.ops或accounts.<id>.webhooks.ops解析)
环境变量速查
核心与回调
| 变量 | 必填 | 说明 |
|---|---|---|
| WECOM_CORP_ID | Agent 必填 | 企业 ID |
| WECOM_CORP_SECRET | Agent 必填 | 应用 Secret |
| WECOM_AGENT_ID | Agent 必填 | AgentId |
| WECOM_CALLBACK_TOKEN | Agent 必填 | 回调 Token |
| WECOM_CALLBACK_AES_KEY | Agent 必填 | 回调 AESKey |
| WECOM_WEBHOOK_PATH | 否 | Agent 回调路径(默认 /wecom/callback) |
| WECOM_WEBHOOK_TARGETS | 否 | 命名 Webhook 目标映射(name=url,多个用 ,/; 分隔) |
Bot
| 变量 | 必填 | 说明 |
|---|---|---|
| WECOM_BOT_ENABLED | 否 | 是否启用 Bot 模式 |
| WECOM_BOT_TOKEN | Bot 必填 | Bot Token |
| WECOM_BOT_ENCODING_AES_KEY | Bot 必填 | Bot EncodingAESKey |
| WECOM_BOT_WEBHOOK_PATH | 否 | Bot 回调路径 |
| WECOM_BOT_PLACEHOLDER_TEXT | 否 | stream 占位文案 |
| WECOM_BOT_STREAM_EXPIRE_MS | 否 | stream 保留时长 |
| WECOM_BOT_REPLY_TIMEOUT_MS | 否 | Bot 等待模型回包超时 |
| WECOM_BOT_LATE_REPLY_WATCH_MS | 否 | Bot 超时后补发观察窗口 |
| WECOM_BOT_LATE_REPLY_POLL_MS | 否 | Bot 补发轮询间隔 |
| WECOM_BOT_CARD_ENABLED | 否 | 是否启用 Bot 卡片回包 |
| WECOM_BOT_CARD_MODE | 否 | 卡片模式:markdown / template_card |
| WECOM_BOT_CARD_TITLE | 否 | 卡片标题 |
| WECOM_BOT_CARD_SUBTITLE | 否 | 卡片副标题 |
| WECOM_BOT_CARD_FOOTER | 否 | 卡片底部说明 |
| WECOM_BOT_CARD_MAX_CONTENT_LENGTH | 否 | 卡片正文最大长度 |
| WECOM_BOT_CARD_RESPONSE_URL_ENABLED | 否 | response_url 层卡片开关 |
| WECOM_BOT_CARD_WEBHOOK_BOT_ENABLED | 否 | webhook_bot 层卡片开关 |
| WECOM_<ACCOUNT>_BOT_* | 否 | 账户级 Bot 覆盖(如 WECOM_SALES_BOT_TOKEN) |
| WECOM_<ACCOUNT>_BOT_PROXY | 否 | 账户级 Bot 媒体下载/回包代理 |
策略与流控
| 变量 | 说明 |
|---|---|
| WECOM_ALLOW_FROM / WECOM_<ACCOUNT>_ALLOW_FROM | 发送者白名单 |
| WECOM_ALLOW_FROM_REJECT_MESSAGE / WECOM_<ACCOUNT>_ALLOW_FROM_REJECT_MESSAGE | 未授权提示 |
| WECOM_ADMIN_USERS | 管理员用户列表 |
| WECOM_COMMANDS_ENABLED / WECOM_COMMANDS_ALLOWLIST / WECOM_COMMANDS_REJECT_MESSAGE | 命令白名单策略 |
| WECOM_DM_POLICY / WECOM_DM_MODE / WECOM_DM_ALLOW_FROM / WECOM_DM_REJECT_MESSAGE | 私聊策略(支持 WECOM_<ACCOUNT>_DM_* 覆盖) |
| WECOM_EVENTS_ENABLED / WECOM_EVENTS_ENTER_AGENT_WELCOME_ENABLED / WECOM_EVENTS_ENTER_AGENT_WELCOME_TEXT | 事件处理与 enter_agent 欢迎语(支持 WECOM_<ACCOUNT>_EVENTS_*) |
| WECOM_GROUP_CHAT_ENABLED / WECOM_GROUP_CHAT_REQUIRE_MENTION / WECOM_GROUP_CHAT_MENTION_PATTERNS | 群触发策略 |
| WECOM_DEBOUNCE_ENABLED / WECOM_DEBOUNCE_WINDOW_MS / WECOM_DEBOUNCE_MAX_BATCH | 文本防抖 |
| WECOM_STREAMING_ENABLED / WECOM_STREAMING_MIN_CHARS / WECOM_STREAMING_MIN_INTERVAL_MS | Agent 增量回包 |
| WECOM_LATE_REPLY_WATCH_MS / WECOM_LATE_REPLY_POLL_MS | 异步补发窗口与轮询频率 |
| WECOM_OBSERVABILITY_ENABLED / WECOM_OBSERVABILITY_PAYLOAD_META | 观测统计与载荷元信息日志开关 |
语音回退转写
| 变量 | 说明 |
|---|---|
| WECOM_VOICE_TRANSCRIBE_ENABLED | 启用本地语音转写回退 |
| WECOM_VOICE_TRANSCRIBE_PROVIDER | local-whisper-cli / local-whisper |
| WECOM_VOICE_TRANSCRIBE_COMMAND | 转写命令 |
| WECOM_VOICE_TRANSCRIBE_MODEL_PATH | whisper-cli 模型路径 |
| WECOM_VOICE_TRANSCRIBE_MODEL | whisper 模型名 |
| WECOM_VOICE_TRANSCRIBE_TIMEOUT_MS | 转写超时 |
| WECOM_VOICE_TRANSCRIBE_MAX_BYTES | 音频大小上限 |
| WECOM_VOICE_TRANSCRIBE_FFMPEG_ENABLED | 是否允许 ffmpeg 转码 |
| WECOM_VOICE_TRANSCRIBE_TRANSCODE_TO_WAV | 是否优先转 WAV |
公网回调与 Gateway Auth
目标
企业微信访问你的回调地址时,必须直接命中 OpenClaw 网关的 webhook 路由。
不能被这些中间层拦住:
- Gateway Auth / Token 鉴权
- 反向代理登录页 / SSO
- 前端 WebUI 路由
- 另一台静态站点或错误 upstream
推荐架构
| 场景 | 推荐做法 |
|---|---|
| 单域名 | 将 /wecom/*、legacy /webhooks/app*、/webhooks/wecom* 单独反代到 OpenClaw 网关端口 |
| 有 Gateway Auth / Zero Trust | 对上述 webhook 路径做认证豁免,不要求 Authorization/Cookie |
| 前端与网关共用域名 | 前端只接管 /ui、静态资源等路径,不要吞掉 /wecom/* |
| 最稳妥 | 单独给企微回调使用一个子域名,只代理到 OpenClaw |
最小验证
| 探测 | 预期 |
|---|---|
| curl -i http://127.0.0.1:8885/wecom/callback | 200 + wecom webhook ok |
| curl -i http://127.0.0.1:8885/wecom/bot/callback | 200 + wecom bot webhook ok |
| curl -i https://你的域名/wecom/callback | 与本机一致,不应返回 HTML、401/403 或跳转 |
| curl -i https://你的域名/wecom/bot/callback | 与本机一致,不应返回 HTML、401/403 或跳转 |
常见返回值的含义
| 现象 | 结论 | 处理 |
|---|---|---|
| 200 + wecom webhook ok / wecom bot webhook ok | 路由命中正常 | 继续做 URL 验证与企业微信后台配置 |
| 200 + HTML | 请求被前端/WebUI 接走 | 单独为 /wecom/* 配反代,不要落到前端 |
| 401/403 | 被 Gateway Auth / Zero Trust / 反代鉴权拦截 | 为 webhook 路径放行认证 |
| 301/302/307/308 | 被登录页、SSO 或前端路由重定向 | 取消 webhook 路径重定向,直接代理到网关 |
| 502/503/504 | OpenClaw 网关端口不可达 | 先修网关存活与 upstream |
| 404 | 路径写错或插件路由没注册 | 核对 webhookPath、插件启用状态和 legacy alias |
反代示例(Nginx)
server {
listen 443 ssl http2;
server_name wecom.example.com;
location /wecom/ {
proxy_pass http://127.0.0.1:8885;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /webhooks/app {
proxy_pass http://127.0.0.1:8885;
}
location /webhooks/wecom {
proxy_pass http://127.0.0.1:8885;
}
}Cloudflare Tunnel 示例
ingress:
- hostname: wecom.example.com
service: http://127.0.0.1:8885
- service: http_status:404建议把企微回调放到单独子域名,不要和前端登录页共用同一套路由规则。
自检建议
npm run wecom:selfcheck -- --all-accounts
npm run wecom:agent:selfcheck -- --all-accounts
npm run wecom:bot:selfcheck -- --all-accounts
npm run wecom:callback:matrix -- --agent-url https://你的域名/wecom/callback --bot-url https://你的域名/wecom/bot/callback现在自检会明确提示这些原因:
route-not-foundhtml-fallbackgateway-authredirect-authgateway-unreachable
如果你要把新路径和 legacy alias 一次跑完,直接用:
npm run wecom:callback:matrix -- \
--agent-url https://你的域名/wecom/callback \
--bot-url https://你的域名/wecom/bot/callback \
--agent-legacy-url https://你的域名/webhooks/app \
--bot-legacy-url https://你的域名/webhooks/wecomWebhook 与 Heartbeat 运维
适用场景
| 需求 | 推荐方式 |
|---|---|
| 手工发一条群通知 | openclaw message send --channel wecom --target webhook:<name> |
| 让 agent 处理后发到群 | openclaw agent --deliver --reply-channel wecom --reply-to webhook:<name> |
| 固定周期发摘要/巡检结果 | OpenClaw agents.defaults.heartbeat + target: "wecom" + to: "webhook:<name>" |
先配置命名 Webhook
{
"channels": {
"wecom": {
"webhooks": {
"ops": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx",
"dev": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=yyy"
}
}
}
}多账号时,也可以挂到 channels.wecom.accounts.<id>.webhooks。
直接发送
openclaw message send --channel wecom --target webhook:ops --message "服务已恢复正常"让 Agent 结果投递到群
openclaw agent \
--message "整理今天的告警摘要" \
--deliver \
--reply-channel wecom \
--reply-to webhook:ops用 Heartbeat 定时投递到群
当前机器上的 OpenClaw 2026.3.2 支持把 heartbeat 直接投递到指定渠道和目标。
对 WeCom Webhook 的推荐写法是:
{
"channels": {
"wecom": {
"webhooks": {
"ops": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
}
}
},
"agents": {
"defaults": {
"heartbeat": {
"every": "30m",
"target": "wecom",
"to": "webhook:ops",
"prompt": "检查网关状态、最近告警和企业微信通道健康;如果一切正常,以三行内摘要输出。",
"ackMaxChars": 300
}
}
}
}多账号 webhook 场景可以再加:
{
"agents": {
"defaults": {
"heartbeat": {
"target": "wecom",
"to": "webhook:ops",
"accountId": "sales"
}
}
}
}说明:
target: "wecom"指定投递到 WeCom 渠道to: "webhook:ops"指定 WeCom 渠道里的命名 webhook 目标accountId只在多账号场景需要- 如果不设
target,heartbeat 默认运行但不会向外发送消息
运维常用命令
openclaw system heartbeat last
openclaw config get agents.defaults.heartbeat
openclaw status --deep
openclaw logs --follow需要手工触发一次立即执行:
openclaw system event --mode now --text "立即执行下一轮运维心跳"与其他渠道并存建议
建议固定以下三点,减少“偶发无回复/冲突”风险:
- 配置
plugins.allow显式白名单(至少包含openclaw-wechat) - 各渠道使用独立 webhook path,不复用
- 同一台机器尽量只运行一个 OpenClaw gateway 进程
详细说明见:docs/troubleshooting/coexistence.md
故障排查
快速定位表
| 现象 | 先看什么 | 常见原因 | 处理建议 |
|---|---|---|---|
| 回调验证失败 | curl https://域名/wecom/callback | URL 不通、Token/AESKey 不一致 | 先通公网,再核对配置 |
| curl 到公网回调是 200,但企业微信后台仍提示 openapi回调地址请求不通过 | 企业微信后台校验 | 临时隧道域名、不受信任公网域名、企业侧域名策略或回调链路仍被中间层改写 | 优先换成稳定公网域名;不要把 trycloudflare.com 之类临时域名当正式 Agent 回调地址 |
| curl /wecom/callback 返回 WebUI 页面 | 反向代理路由与回调路径 | 域名把 /wecom/callback 转发到了前端/静态站点 | 单独为 /wecom/* 配置反向代理到 OpenClaw 网关端口 |
| curl https://域名/wecom/callback 返回 401/403 | Gateway Auth / Zero Trust / 反代鉴权 | webhook 路径被要求登录或带 Token | 对 /wecom/*、/webhooks/app*、/webhooks/wecom* 做认证豁免 |
| curl https://域名/wecom/callback 返回 301/302/307/308 | 登录跳转 / SSO / 前端路由 | webhook 被重定向到登录页或前端 | 让 webhook 路径直接反代到 OpenClaw 网关 |
| 能收到消息但不回复 | openclaw gateway status + openclaw logs --follow | 模型超时、会话排队、权限策略拦截 | 查看 dispatch/allowFrom/commands 日志 |
| 能收到消息但不回复(已确认本地日志正常) | 企业微信自建应用后台 -> 开发设置 | 未配置“可信 IP”,企业微信拒绝部分回调/发送链路 | 在应用里补充 OpenClaw 出网 IP 到可信 IP 列表(保存后重试) |
| Bot 图片识别失败 | wecom(bot): failed to fetch image url | URL 失效、返回非图像流 | 已支持 octet-stream+解密兜底,先升级到最新版本 |
| 语音转写失败 | wecom: voice transcription failed | 本地命令或模型路径错误 | 检查 command、modelPath、ffmpeg |
| 启动出现账号体检告警 | wecom: account diagnosis ... | 多账号 Token/Agent/路径存在冲突风险 | 按日志 code 与账户列表调整配置,优先处理 warn 级别 |
| wecom:selfcheck -- --all-accounts 提示 account '<id>' not found or incomplete | 账号配置结构 | 旧版本自检脚本没完全识别 agent 子块、legacy inline 账户,或账号字段确实缺失 | 升级到最新版本后重跑;再核对 channels.wecom.accounts.<id> 是否包含完整 Agent 凭据 |
| gettoken 失败 | 企业微信 API 返回码 | CorpId/Secret 错或网络受限 | 检查凭据/配置代理 |
推荐检查命令
openclaw gateway status
openclaw status --deep
openclaw logs --follow
npm run wecom:selfcheck -- --all-accounts
npm run wecom:agent:selfcheck -- --all-accounts
npm run wecom:bot:selfcheck -- --all-accounts开发与发布
常用命令
| 命令 | 作用 |
|---|---|
| npm test | 语法与单测 |
| WECOM_E2E_ENABLE=1 npm run test:e2e:remote | 运行远程 E2E 测试(默认跳过;支持 WECOM_E2E_* 与兼容 E2E_WECOM_* 两套变量) |
| WECOM_E2E_MATRIX_ENABLE=1 npm run test:e2e:matrix | 运行远程矩阵 E2E(签名验签/异常请求/stream refresh/去重链路) |
| npm run test:e2e:prepare-browser | 远程浏览器沙箱就绪检查(可选自动安装 Chromium) |
| npm run test:e2e:collect-pdf | 收集远端浏览器沙箱中的 PDF 产物到本地 |
| npm run wecom:selfcheck -- --all-accounts | 配置+网络体检 |
| npm run wecom:agent:selfcheck -- --account <id> | Agent 单账号端到端链路体检(URL 验证 + 加密 POST) |
| npm run wecom:agent:selfcheck -- --all-accounts | Agent 多账号端到端链路体检(逐账号跑 URL 验证 + 加密 POST) |
| npm run wecom:bot:selfcheck -- --account <id> | Bot 端到端链路体检(URL 验证/签名/加密/stream-refresh,支持多账户) |
| npm run wecom:callback:matrix -- --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 公网回调矩阵体检(可附带 legacy alias URL) |
| npm run wecom:remote:e2e -- --mode all --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 远端矩阵验证(Agent+Bot) |
| npm run wecom:remote:e2e -- --mode all --agent-url <公网Agent回调> --bot-url <公网Bot回调> --prepare-browser --collect-pdf | 远端矩阵验证(含浏览器沙箱检查与 PDF 回收) |
| WECOM_E2E_BOT_URL=<...> WECOM_E2E_AGENT_URL=<...> npm run wecom:remote:e2e -- --mode all | 用环境变量驱动远端 E2E(兼容旧 E2E_WECOM_*) |
| npm run wecom:e2e:scenario -- --scenario full-smoke --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 场景化 E2E(预置 smoke/queue 场景) |
| npm run wecom:e2e:scenario -- --scenario callback-matrix --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 只做公网回调矩阵检查 |
| npm run wecom:e2e:scenario -- --scenario compat-smoke --agent-url <新Agent回调> --agent-legacy-url <旧Agent回调> --bot-url <新Bot回调> --bot-legacy-url <旧Bot回调> | 兼容矩阵验证(新旧回调地址都跑一遍) |
| npm run wecom:e2e:scenario -- --scenario matrix-smoke --bot-url <公网Bot回调> | Bot 协议矩阵验证(验签/异常请求/stream-refresh/去重;需 WECOM_BOT_TOKEN/WECOM_BOT_ENCODING_AES_KEY) |
| npm run wecom:e2e:compat -- --agent-url <新Agent回调> --agent-legacy-url <旧Agent回调> --bot-url <新Bot回调> --bot-legacy-url <旧Bot回调> | 兼容矩阵快捷命令(等价 --scenario compat-smoke) |
| npm run wecom:e2e:full -- --agent-url <公网Agent回调> --bot-url <公网Bot回调> | 一键 full-smoke(默认带 --prepare-browser --collect-pdf) |
| GitHub Actions -> CI -> Run workflow | 在仓库 CI 手动触发远程 E2E:设置 run_remote_e2e=true,可选 e2e_scenario(含 compat-smoke)与浏览器参数 |
| npm run wecom:smoke | 升级后快速回归(Agent 主链路) |
| npm run wecom:smoke -- --with-bot-e2e | 升级后快速回归(含 Bot E2E) |
| openclaw gateway restart | 重启网关 |
发版建议流程
- 更新
CHANGELOG.md与版本号 - 运行
npm test与wecom:selfcheck - 打 tag 并发布 GitHub Release
- (可选)发布 npm 包
FAQ
Q1:Bot 模式回调一直失败?
通常是机器人创建成“标准模式”。请重建为 API 模式(JSON 回调)。
Q2:为什么图片偶发识别失败?
企业微信可能返回非标准 content-type 或加密媒体流。插件已增加类型识别与解密兜底;仍失败时请查看日志中的 header/下载错误。
Q3:能收消息但一直不回复,日志看起来也正常?
优先检查企业微信自建应用后台是否配置了可信 IP。如果可信 IP 缺失,企业微信可能在发送/回调链路上做安全拦截,表现为“能收到但不回”。
建议:把 OpenClaw 网关实际出网 IP 加入该应用的可信 IP 列表,保存后重试。
Q4:Telegram 和 WeCom 会互相影响吗?
理论上独立;实战中若复用 webhook 路径、多进程抢占、或 plugins.allow 未收紧,会出现干扰。按“并存建议”配置可大幅降低风险。
Q5:支持个人微信吗?
支持企业微信场景下的“微信插件入口”(个人微信扫码进入企业应用对话),不等同于“个人微信网页版协议”。
Q4.1:为什么 Bot 模式在“微信插件入口”里看不到机器人联系人?
这是企业微信产品形态差异,不是插件故障。
在很多租户里,“微信插件入口”主要对应**自建应用(Agent 回调)**可见,Bot 模式(智能机器人 API)不会以可直接会话的联系人形态出现。
建议:
- 需要稳定私聊入口:优先用自建应用(Agent 模式)
- 需要群聊通知/群内对话:优先用 Webhook Bot / Bot 模式
- 需要两者兼顾:并行启用 Agent(入口)+ Bot(群能力)
- 运行
npm run wecom:bot:selfcheck -- --account <id>(或--all-accounts)可看到bot.entry.visibility提示,用于快速确认该行为属于产品形态差异而非插件故障
Q5:为什么 curl https://域名/wecom/callback 返回的是 WebUI 页面?
这是路由层问题,不是插件正常行为。GET /wecom/callback(无 echostr)应返回纯文本 wecom webhook ok。
若返回 WebUI,说明你的反向代理把该路径转发到了前端服务而不是 OpenClaw 网关。
建议按顺序排查:
- 本机验证:
curl http://127.0.0.1:8885/wecom/callback(应返回wecom webhook ok) - 公网验证:
curl -i https://你的域名/wecom/callback - 代理配置:为
/wecom/*单独反代到 OpenClaw 网关端口,不要落到 WebUI 路由
Q5.1:为什么本机和公网 curl 都是 200 wecom webhook ok,企业微信后台仍提示 openapi回调地址请求不通过?
这说明“你的路由打通了”,但还不能证明企业微信后台会接受这条回调地址。
常见根因:
- 用了临时公网域名,例如
trycloudflare.com - 企业侧要求更稳定/更受信任的公网域名
- 你的回调链路虽然
curl是200,但企业微信实际校验时仍遇到了中间层改写
明确建议:
- 自建应用正式回调地址优先用你自己的稳定公网域名
- 不要把
trycloudflare.com这类临时隧道域名当正式 Agent 回调地址 - 继续确认该域名的
/wecom/callback没有鉴权、跳转、前端兜底和缓存层干扰 - 如果只是想快速群聊验证,Bot/Webhook 路径通常比自建应用回调更容易先跑通
Q6:自建应用群聊怎么开?为什么群里不 @ 就不触发?
先区分两种通道能力:
- 群机器人(Webhook Bot):可直接添加到企微群,天然适合群聊收发;但群聊通常仅
@机器人时才会回调。 - 自建应用(Agent 回调):插件支持处理
ChatId群消息;但是否能收到“普通群消息”取决于企业微信实际下发能力(很多租户里普通群只能加机器人,无法像成员一样加自建应用)。
如果你的场景是“普通群里稳定对话”,优先用 Webhook Bot 模式(注意通常仍需 @机器人 才触发)。
如果你确认企业微信会把群消息回调到自建应用(日志里有 chatId=...),再配置触发模式:
{
"channels": {
"wecom": {
"groupPolicy": "open",
"groupChat": {
"enabled": true,
"triggerMode": "direct"
}
}
}
}如果还要限制“只有指定群成员能触发”,可以再加一层群聊成员授权:
{
"channels": {
"wecom": {
"groupPolicy": "allowlist",
"groupAllowFrom": ["alice", "bob"],
"groups": {
"wr9N1x...": {
"policy": "allowlist",
"allowFrom": ["ops_lead"],
"rejectMessage": "当前群仅限值班同学触发。"
}
}
}
}
}如果你要“一刀切关闭群聊处理”,直接用:
{
"channels": {
"wecom": {
"groupPolicy": "deny"
}
}
}同时确认企业微信侧前提:
- 自建应用已开启“接收消息”并完成 URL 验证
- 应用可见范围包含该群成员
- 日志里能看到
chatId=...(若没有chatId,说明企业微信没有把群消息推送到该回调)
若你在企微侧只能给群添加“机器人”而不能添加“自建应用”,这不是插件配置问题,属于企微产品形态差异;建议走 Bot 模式承载群聊,自建应用用于私聊/应用会话/主动推送。
Q7:多账号创建了两个 agent,但只有一个回复,或者会话串了?
这是多账号隔离问题,不是“企微互相干扰”。
从当前版本开始:
- Agent 会话 key 已按账号隔离
wecom:selfcheck -- --all-accounts会识别accounts.<id>、agent子块、legacy inline 账户bindings.match.channel=wecom + accountId=<id>可以把不同账号稳定路由到不同 Agent
建议排查顺序:
- 跑
npm run wecom:selfcheck -- --all-accounts - 确认每个账号
config.account都是OK - 在
openclaw.json中为多账号配置bindings - 确认会话 key 形态符合预期:默认账号为
wecom:<userid>;非默认账号为wecom:<accountId>:<userid>
版本与贡献
- 版本记录:
CHANGELOG.md - 渠道文档:
docs/channels/wecom.md - 问题排查:
docs/troubleshooting/coexistence.md - 许可证:MIT
欢迎提交 Issue / PR。
