OpenClaw接入钉钉机器人
钉钉企业内部机器人 Channel 插件,使用 Stream 模式(无需公网 IP)。
功能特性
- ✅ Stream 模式 — WebSocket 长连接,无需公网 IP 或 Webhook
- ✅ 私聊支持 — 直接与机器人对话
- ✅ 群聊支持 — 在群里 @机器人
- ✅ 多种消息类型 — 文本、图片、语音(自带识别)、视频、文件
- ✅ Markdown 回复 — 支持富文本格式回复
- ✅ 互动卡片 — 支持流式更新,适用于 AI 实时输出
- ✅ 完整 AI 对话 — 接入 Clawdbot 消息处理管道
安装
方法 A:通过 npm 包安装 (推荐)
手动通过 npm 包名安装:
openclaw plugins install @soimy/dingtalk
方法 B:通过本地源码安装
如果你想对插件进行二次开发,可以先克隆仓库:
1. 克隆仓库
git clone github.com/soimy/openc… cd openclaw-channel-dingtalk
2. 安装依赖 (必需)
npm install
3. 以链接模式安装 (方便修改代码后实时生效)
openclaw plugins install -l .
方法 C:手动安装
- 将本目录下载或复制到
~/.openclaw/extensions/dingtalk。 - 确保包含
index.ts,openclaw.plugin.json和package.json。 - 运行
openclaw plugins list确认dingtalk已显示在列表中。
安装后必做:配置插件信任白名单(plugins.allow)
从 OpenClaw 新版本开始,如果发现了非内置插件且 plugins.allow 为空,会提示:
[plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load ...
这是一条安全告警(不是安装失败),建议显式写入你信任的插件 id。
步骤 1:确认插件 id
本插件 id 固定为:dingtalk(定义于 openclaw.plugin.json)。
也可用下面命令查看已发现插件:
步骤 2:在 ~/.openclaw/openclaw.json 添加 plugins.allow
{ "plugins": { "enabled": true, "allow": ["dingtalk"] } }
如果你还有其他已安装且需要启用的插件,请一并加入,例如:
{ "plugins": { "allow": ["dingtalk", "telegram", "voice-call"] } }
步骤 3:重启 Gateway
注意:如果你之前已经配置过
plugins.allow,但没有dingtalk,那么插件不会被加载。请把dingtalk加入该列表。
更新
openclaw plugins update 使用插件 id(不是 npm 包名),并且仅适用于 npm 安装来源。
如果你是通过 npm 安装本插件:
openclaw plugins update dingtalk
如果你是本地源码/链接安装(openclaw plugins install -l .),请在插件目录更新代码后重启 Gateway:
git pull openclaw gateway restart
配置
OpenClaw 支持交互式配置和手动配置文件两种方式。
方法 1:交互式配置(推荐)
使用 OpenClaw 命令行向导式配置插件参数:
方式 A:使用 onboard 命令
openclaw onboard
方式 B:直接配置 channels 部分
openclaw configure --section channels
交互式配置流程:
- 选择插件 — 在插件列表中选择
dingtalk或DingTalk (钉钉) - Client ID — 输入钉钉应用的 AppKey
- Client Secret — 输入钉钉应用的 AppSecret
- 完整配置 — 可选配置 Robot Code、Corp ID、Agent ID(推荐)
- 卡片模式 — 可选启用 AI 互动卡片模式
- 如启用,需输入 Card Template ID 和 Card Template Key
- 私聊策略 — 选择
open(开放)或allowlist(白名单) - 群聊策略 — 选择
open(开放)或allowlist(白名单)
所有的参数参考下文中的钉钉开发者平台配置指南
配置完成后会自动保存并重启 Gateway。
钉钉开发者平台配置指南
1. 创建钉钉应用
- 访问 钉钉开发者后台
- 创建企业内部应用
- 添加「机器人」能力
- 配置消息接收模式为 Stream 模式
- 发布应用
2. 配置权限管理
在应用的权限管理页面,需要开启以下权限:
- ✅ Card.Instance.Write — 创建和投放卡片实例
- ✅ Card.Streaming.Write — 对卡片进行流式更新
步骤:
- 进入应用 → 权限管理
- 搜索「Card」相关权限
- 勾选上述两个权限
- 保存权限配置
3. 建立卡片模板(可选)
步骤:
- 访问 钉钉卡片平台
- 进入「我的模板」
- 点击「创建模板」
- 卡片模板场景选择 「AI 卡片」
- 按需设计卡片排版,点击保存并发布
- 记下模板中定义的内容字段名称
- 复制模板 ID(格式如:
xxxxx-xxxxx-xxxxx.schema) - 将 templateId 配置到
openclaw.json的cardTemplateId字段 - 或在OpenClaw控制台的Channel标签->Dingtalk配置面板-> Card Template Id填入
- 将记下的内容字段变量名配置到
openclaw.json的cardTemplateKey字段 - 或在OpenClaw控制台的Channel标签->Dingtalk配置面板-> Card Template Key填入
说明:
- 使用 DingTalk 官方 AI 卡片模板时,
cardTemplateKey默认为'msgContent',无需修改 - 如果您创建自定义卡片模板,需要确保模板中包含相应的内容字段,并将
cardTemplateKey配置为该字段名称
4. 获取凭证
从开发者后台获取:
- Client ID (AppKey)
- Client Secret (AppSecret)
- Robot Code (与 Client ID 相同)
- Corp ID (企业 ID)
- Agent ID (应用 ID)
方法 2:手动配置文件
在 ~/.openclaw/openclaw.json 中添加(仅作参考,交互式配置会自动生成):
至少包含
plugins.allow和channels.dingtalk两部分,内容参考上文钉钉开发者配置指南
{ "plugins": { "enabled": true, "allow": ["dingtalk"] },
... "channels": { "telegram": { ... },
"dingtalk": {
"enabled": true,
"clientId": "dingxxxxxx",
"clientSecret": "your-app-secret",
"robotCode": "dingxxxxxx",
"corpId": "dingxxxxxx",
"agentId": "123456789",
"dmPolicy": "open",
"groupPolicy": "open",
"debug": false,
"messageType": "markdown", // 或 "card"
// 仅card需要配置
"cardTemplateId": "你复制的模板ID",
"cardTemplateKey": "你模板的内容变量"
}
}, ... }
最后重启 Gateway
使用交互式配置时,Gateway 会自动重启。使用手动配置时需要手动执行:
配置选项
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | boolean | true | 是否启用 |
clientId | string | 必填 | 应用的 AppKey |
clientSecret | string | 必填 | 应用的 AppSecret |
robotCode | string | - | 机器人代码(用于下载媒体和发送卡片) |
corpId | string | - | 企业 ID |
agentId | string | - | 应用 ID |
dmPolicy | string | "open" | 私聊策略:open/pairing/allowlist |
groupPolicy | string | "open" | 群聊策略:open/allowlist |
allowFrom | string[] | [] | 允许的发送者 ID 列表 |
messageType | string | "markdown" | 消息类型:markdown/card |
cardTemplateId | string | AI 互动卡片模板 ID(仅当 messageType=card) | |
cardTemplateKey | string | "content" | 卡片模板内容字段键(仅当 messageType=card) |
debug | boolean | false | 是否开启调试日志 |
maxConnectionAttempts | number | 10 | 最大连接尝试次数 |
initialReconnectDelay | number | 1000 | 初始重连延迟(毫秒) |
maxReconnectDelay | number | 60000 | 最大重连延迟(毫秒) |
reconnectJitter | number | 0.3 | 重连延迟抖动因子(0-1) |
连接鲁棒性配置
为提高连接稳定性,插件支持以下高级配置:
- maxConnectionAttempts: 连接失败后的最大重试次数,超过后将停止尝试并报警。
- initialReconnectDelay: 第一次重连的初始延迟(毫秒),后续重连会按指数增长。
- maxReconnectDelay: 重连延迟的上限(毫秒),防止等待时间过长。
- reconnectJitter: 延迟抖动因子,在延迟基础上增加随机变化(±30%),避免多个客户端同时重连。
重连延迟计算公式:delay = min(initialDelay × 2^attempt, maxDelay) × (1 ± jitter)
示例延迟序列(默认配置):~1s, ~2s, ~4s, ~8s, ~16s, ~32s, ~60s(达到上限)
更多详情请参阅 CONNECTION_ROBUSTNESS.md。
安全策略
私聊策略 (dmPolicy)
open— 任何人都可以私聊机器人pairing— 新用户需要通过配对码验证allowlist— 只有 allowFrom 列表中的用户可以使用
群聊策略 (groupPolicy)
open— 任何群都可以 @机器人allowlist— 只有配置的群可以使用
消息类型支持
接收
| 类型 | 支持 | 说明 |
|---|---|---|
| 文本 | ✅ | 完整支持 |
| 富文本 | ✅ | 提取文本内容 |
| 图片 | ✅ | 下载并传递给 AI |
| 语音 | ✅ | 使用钉钉语音识别结果 |
| 视频 | ✅ | 下载并传递给 AI |
| 文件 | ✅ | 下载并传递给 AI |
发送
| 类型 | 支持 | 说明 |
|---|---|---|
| 文本 | ✅ | 完整支持 |
| Markdown | ✅ | 自动检测或手动指定 |
| 互动卡片 | ✅ | 支持流式更新,适用于 AI 实时输出 |
| 图片 | ⏳ | 需要通过媒体上传 API |
API 消耗说明
Text/Markdown 模式
| 操作 | API 调用次数 | 说明 |
|---|---|---|
| 获取 Token | 1 | 共享/缓存(60 秒检查过期一次) |
| 发送消息 | 1 | 使用 /v1.0/robot/oToMessages/batchSend 或 /v1.0/robot/groupMessages/send |
| 总计 | 2 | 每条回复 1 次 |
Card(AI 互动卡片)模式
| 阶段 | API 调用 | 说明 |
|---|---|---|
| 创建卡片 | 1 | POST /v1.0/card/instances/createAndDeliver |
| 流式更新 | M | M = 回复块数量,每块一次 PUT /v1.0/card/streaming |
| 完成卡片 | 包含在最后一次流更新中 | 使用 isFinalize=true 标记 |
| 总计 | 1 + M | M = Agent 产生的回复块数 |
典型场景成本对比
| 场景 | Text/Markdown | Card | 节省 |
|---|---|---|---|
| 简短回复(1 块) | 2 | 2 | ✓ 相同 |
| 中等回复(5 块) | 6 | 6 | ✓ 相同 |
| 长回复(10 块) | 12 | 11 | ✓ 1 次 |
优化策略
降低 API 调用的方法:
- 合并回复块 — 通过调整 Agent 输出配置,减少块数量
- 使用缓存 — Token 自动缓存(60 秒),无需每次都获取
- Buffer 模式 — 使用
dispatchReplyWithBufferedBlockDispatcher合并多个小块
成本建议:
- ✅ 推荐 — Card 模式:流式体验更好,成本与 Text/Markdown 相当或更低
- ⚠️ 谨慎 — 频繁调用需要监测配额,建议使用钉钉开发者后台查看 API 调用量
消息类型选择
插件支持两种消息回复类型,可通过 messageType 配置:
1. markdown(Markdown 格式)【默认】
- 支持富文本格式(标题、粗体、列表等)
- 自动检测消息是否包含 Markdown 语法
- 适用于大多数场景
2. card(AI 互动卡片)
- 支持流式更新(实时显示 AI 生成内容)
- 更好的视觉呈现和交互体验
- 支持 Markdown 格式渲染
- 通过
cardTemplateId指定模板 - 通过
cardTemplateKey指定内容字段 - 适用于 AI 对话场景
- 支持在卡片中实时显示 AI 思考过程(推理流)和工具执行结果
AI Card API 特性: 当配置 messageType: 'card' 时:
- 使用
/v1.0/card/instances/createAndDeliver创建并投放卡片 - 使用
/v1.0/card/streaming实现真正的流式更新 - 自动状态管理(PROCESSING → INPUTING → FINISHED)
- 更稳定的流式体验,无需手动节流
AI 思考过程与工具执行显示(AI Card 模式)
当 messageType 为 card 时,插件可以在卡片中实时展示 AI 的推理过程(🤔 思考中)和工具调用结果(🛠️ 工具执行)。这两项功能通过对话级命令控制,无需修改配置文件:
| 功能 | 对话命令 | 说明 |
|---|---|---|
| 显示 AI 推理流 | /reasoning stream | 开启后,AI 思考内容实时更新到卡片 |
| 显示工具执行结果 | /verbose on | 开启后,工具调用结果实时更新到卡片 |
| 关闭 AI 推理流 | /reasoning off | 关闭推理流显示 |
| 关闭工具执行显示 | /verbose off | 关闭工具执行结果显示 |
显示格式:
- 思考内容以
🤔 **思考中**为标题,正文以>引用块展示,最多显示前 500 个字符 - 工具结果以
🛠️ **工具执行**为标题,正文以>引用块展示,最多显示前 500 个字符
注意: 推理流和工具执行均会产生额外的卡片流式更新 API 调用,在 AI 推理步骤较多时可能显著增加 API 消耗,建议按需开启。
配置示例:
{ messageType: 'card', // 启用 AI 互动卡片模式 cardTemplateId: '382e4302-551d-4880-bf29-a30acfab2e71.schema', // AI 卡片模板 ID(默认值) cardTemplateKey: 'msgContent', // 卡片内容字段键(默认值:msgContent) }
注意:
cardTemplateKey应与您的卡片模板中定义的字段名称一致。默认值为'msgContent',适用于 DingTalk 官方 AI 卡片模板。如果您使用自定义模板,请根据模板定义的字段名称进行配置。
使用示例
配置完成后,直接在钉钉中:
- 私聊机器人 — 找到机器人,发送消息
- 群聊 @机器人 — 在群里 @机器人名称 + 消息
故障排除
收不到消息
- 确认应用已发布
- 确认消息接收模式是 Stream
- 检查 Gateway 日志:
openclaw logs | grep dingtalk
群消息无响应
- 确认机器人已添加到群
- 确认正确 @机器人(使用机器人名称)
- 确认群是企业内部群
连接失败
- 检查 clientId 和 clientSecret 是否正确
- 确认网络可以访问钉钉 API
错误 payload 日志规范([ErrorPayload])
为便于快速定位 4xx/5xx 参数问题,插件会在 API 错误分支输出统一格式日志:
- 通用前缀:
[DingTalk][ErrorPayload][<scope>] - AI Card 前缀:
[DingTalk][AICard][ErrorPayload][<scope>] - 内容格式:
code=<...> message=<...> payload=<...>(同时保留脱敏后的完整 payload)
常见 scope 示例:
send.proactiveMessage/send.proactiveMedia/send.messageoutbound.sendText/outbound.sendMediainbound.downloadMedia/inbound.cardFinalizecard.create/card.stream/card.stream.retryAfterRefreshretry.beforeDecision
排查建议:
openclaw logs | grep "\[ErrorPayload\]"
如果你看到 code=invalidParameter,通常优先检查请求 payload 的必填字段(例如 robotCode、userIds、msgKey、msgParam)是否完整且格式正确。