钉钉企业机器人对话
钉钉企业内部应用机器人能在群聊被 @ 或单聊时接收消息。本文主路径使用 Stream 模式,HTTP 回调作为已有公网入口时的替代方案;核验日期为 2026-09-14,未在真实组织发布应用。
- 自定义机器人 Webhook 是固定群通知入口,不等于企业机器人接收消息能力。
- 企业机器人接收消息支持 Stream 和 HTTP 两种模式。Stream 由客户端主动建立连接,不要求公网回调地址。
- 群聊通常由
@机器人触发;单聊需应用机器人和组织侧配置允许。 - AI Card、流式卡片是可选的展示增强,不是完成普通文本 AI 对话的前置条件。
- Stream 和 HTTP 模式只负责入站消息传递;确定性命令、业务 API 与 AI 回复应共享同一套权限、去重和会话层。
- 有权限在钉钉开放平台创建企业内部应用、添加机器人、申请权限并发布版本。
- 已准备同一应用的 AppKey(Client ID)、AppSecret(Client Secret)和测试组织。
- Stream 模式使用官方 Stream SDK;HTTP 模式准备公网 HTTPS 回调地址、原始请求体读取和验签能力。
- 明确 Bot 加群、单聊可见范围和组织管理员审批流程。
- 已准备事件去重存储、会话串行队列和模型超时后的非 AI 降级响应。
如何选择接收模式
Section titled “如何选择接收模式”| 条件 | Stream 模式 | HTTP 模式 |
|---|---|---|
| 公网地址 | 不需要,服务主动连接钉钉 | 需要稳定公网 HTTPS 地址 |
| 接入实现 | 使用官方 Stream SDK 处理鉴权、连接和确认 | 按官方协议验签并处理回调确认 |
| 扩缩容 | 控制连接实例和消息消费归属 | 可经 API 网关横向扩展,仍需消息 ID 去重 |
| 适用场景 | 本地开发、内网服务、快速接入 | 已有统一网关、WAF、队列和回调平台 |
不要同时让两个模式处理同一机器人消息,也不要自行拼装 Stream 协议代替官方 SDK。
1. 创建应用与机器人
Section titled “1. 创建应用与机器人”- 在钉钉开放平台选择正确组织并创建企业内部应用。
- 在应用能力中添加机器人,设置名称、图标和说明。
- 配置测试范围和机器人使用范围,申请接收与发送消息需要的最小权限。
2. 配置消息接收
Section titled “2. 配置消息接收”- 选择 Stream 模式时,用官方 SDK注册机器人消息处理器,并以 AppKey、AppSecret 建立连接。
- 选择 HTTP 模式时,填写公网回调 URL,按官方规则完成验签和地址校验。
- HTTP 入口完成验签、消息 ID 去重和入队后快速确认;不要在平台回调中等待业务 API 或模型生成。
- Stream 处理器按 SDK 协议快速确认,连接断开、重连和消费异常要有监控。
3. 发布并验证
Section titled “3. 发布并验证”- 创建并发布应用版本,需要管理员审批时完成审批。
- 把机器人添加到测试群,或从工作台进入机器人单聊。
- 启动接收服务,用
@机器人 /ping验证入站事件。 - 先通过
sessionWebhook返回固定pong,再测试主动发送和 AI 回复。
回调中常见字段包括消息 ID、会话 ID、会话类型、发送者 ID、文本内容和临时 sessionWebhook。字段会随消息类型和 SDK 封装变化,应以官方模型为准,不要用显示昵称建立身份。
{ "msgId": "msg_xxx", "conversationId": "cid_xxx", "conversationType": "2", "senderStaffId": "user_xxx", "text": { "content": " /ping" }, "sessionWebhook": "https://oapi.dingtalk.com/robot/sendBySession?..."}以官方消息 ID 做事件去重。会话键建议 dingtalk:{corpId}:{conversationId};单聊可加入 senderStaffId。显示名不能作为身份主键。Stream SDK 收到消息后仍要按 SDK 协议快速确认,避免平台因为处理超时而重投。
最小会话 Webhook 回复
Section titled “最小会话 Webhook 回复”sessionWebhook 来自入站消息,只能在其官方有效期与限制内用于当前会话。它不是长期凭据,也不要持久化到聊天历史。
curl -X POST 'SESSION_WEBHOOK' \ -H 'Content-Type: application/json' \ -d '{"msgtype":"text","text":{"content":"pong"}}'const response = await fetch(process.env.SESSION_WEBHOOK, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ msgtype: 'text', text: { content: 'pong' } }),});if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);import osimport requests
response = requests.post( os.environ["SESSION_WEBHOOK"], json={"msgtype": "text", "text": {"content": "pong"}}, timeout=15,)response.raise_for_status()普通 API 双向回复
Section titled “普通 API 双向回复”最小路径可使用消息携带的 sessionWebhook 回复当前会话。它属于临时敏感地址,只用于当前消息上下文,不进入长期凭据库。需要超出临时回复窗口、主动发起消息或精确控制接收人时,应按官方企业机器人 OpenAPI 获取访问令牌并调用相应群聊/单聊主动发送接口,不要长期缓存 sessionWebhook 代替正式身份凭据。
确定性命令处理建议优先:/ping 返回 pong,/status 查询业务 API。平台确认、业务执行和回复分开记录,失败重试前检查消息 ID 是否已经回复。权限或审批类命令必须在服务端根据 senderStaffId 和组织重新鉴权,不能相信消息文本声明的身份。
AI 对话扩展
Section titled “AI 对话扩展”const conversationKey = `dingtalk:${corpId}:${message.conversationId}`;const answer = await generateReply({ messages: await history.withUserMessage(conversationKey, message.text.content.trim()), signal: AbortSignal.timeout(20_000),});await replyWithSessionWebhook(message.sessionWebhook, answer);生成时间可能超过临时回复窗口时,改用正式主动发送 API,或使用钉钉当前支持的 AI Card/流式卡片方案。引入卡片前先完成普通文本一问一答,避免同时排查卡片模板、流式更新和模型问题。
模型开始处理前可以快速返回“已收到”状态,但不能对同一消息同时发送临时回复和最终主动回复而不做关联。保存消息 ID、会话 ID、模型任务 ID 和最终消息 ID,便于取消和去重。
安全与可靠性
Section titled “安全与可靠性”- AppSecret、访问令牌和
sessionWebhook都按敏感凭据处理,日志中只保留哈希或脱敏片段。 - Stream 模式使用官方 SDK管理鉴权、重连和确认;HTTP 模式按官方规范验签。
- 用消息 ID 做事件去重,对同一会话串行,忽略 Bot 自身消息。
- 只在
@机器人、单聊或明确命令时触发模型,设置输入长度、并发和预算上限。 - 模型工具调用需要按钉钉用户、组织和业务资源在服务端重新鉴权,防范提示词注入。
- HTTP 回调保留原始请求体完成验签;Stream 连接的 AppSecret 不输出到 SDK 调试日志。
- 对单一会话串行处理,限制输入长度、附件大小、并发和每日模型预算。
机器人可以发通知但收不到消息:确认使用的是企业内部应用机器人,而不是只有 Webhook 的自定义机器人。
Stream 已连接但群里不触发:检查机器人是否已入群、消息是否 @机器人、应用版本和可见范围是否已生效。
sessionWebhook 后来失效:它是临时回复地址。异步长任务应使用官方主动发送接口,不要把 URL 当长期 Token。
重复回复:消息处理前为消息 ID 建唯一键,并在 Stream/HTTP 重投时直接确认而不重复执行业务。
HTTP 回调校验通过但运行时超时:回调入口只做验签、去重和入队并快速确认;把模型和下游 API 移出请求线程。
需要延迟数分钟后回复:不要依赖已经过期的 sessionWebhook,使用应用访问令牌和正式主动发送接口,并保存接收目标。
主动发送提示无权限:核对机器人发送权限、应用版本、可见范围、机器人是否在群中,以及 Token 是否属于同一应用。