如果你同时开着 AI 对话框和企业微信、钉钉的工作窗口,大概率会有一种很拧巴的感觉:AI 那边已经把数据分析完了、周报初稿写好了、排期方案理清楚了,但你还得手动把这些结果复制粘贴到 IM 里发给同事。一次两次还好,次数一多就忍不住想:能不能让 AI 直接住进企微 / 钉钉,让它在消息流里帮我把事儿干了?
这就是我这篇实战想解决的问题。我基于 OpenClaw 这个消息驱动的 AI Agent 运行时,把企业内部两个最常见的 IM 通道——企业微信和钉钉——完整接了进去。接完之后,团队同事直接在工作群里@机器人提问,OpenClaw 去调模型、查数据、执行脚本、整理结论,再把结果作为消息发回来。整个过程不需要打开浏览器、不需要切终端,IM 就是 AI 的工位。
这篇适合谁看?准备给团队内部接 AI 机器人但卡在平台配置环节的开发者,想搞清楚企微 / 钉钉回调机制的技术负责人,以及对 Agent 接入 IM 这件事还停留在"应该挺简单吧"阶段、想看看真实落地过程的人。我会把两个平台接入的每一步配置、签名验签逻辑、消息收发原理,以及我实际联调中踩过的坑全部讲清楚。
1. 为什么非要把 AI 塞进企微 / 钉钉:一个让人上头的场景
先说一个我自己的经历。当时我负责给某团队搭一套内部知识问答的 AI 助手,一开始做的是网页版的对话界面,模型调用、知识库检索、生成回答全部都能跑通。测的时候感觉还挺好,一上线就发现使用率极低——同事们根本不会主动打开那个网页,他们所有的日常协作都发生在企微群里。
后来我把 AI 挪进企微,变成群里一个可以被 @ 的机器人。使用率一下子就上来了,因为入口就是同事每天必开的工作软件,不需要新学任何东西,就像在群里喊一个新来的同事一样自然。这件事让我意识到一个很朴素的道理:在 IM 里能被 @ 到的 AI,才是大家愿意用的 AI。
把 OpenClaw 接入企微 / 钉钉,本质上是解决两件事:
- 消息入口问题。成员在群聊或单聊里发一句话,IM 平台通过事件回调把这句话推给 OpenClaw,OpenClaw 把消息转成 Agent 的输入。
- 消息出口问题。Agent 生成的结果通过 IM 平台的开放接口,以文本、图片、文件、链接卡片等形式发回聊天窗口。
听起来就是一个回调加一个 API,但真正做起来你会发现,企微和钉钉在消息收发机制上各有各的脾气。企业微信的强项是和企业组织架构、审批流程深度绑定,而钉钉对本地开发非常友好,Stream 模式可以让你不暴露公网 IP 就能接收消息。这两个平台的差异,直接影响了接入方案的设计思路。
我在接入过程中感受最深的一点是:IM 接入本身并不难,难的是把消息鉴权、加解密、回调验证、频率限制这些外围问题一次想清楚。如果一开始没有理解消息从 IM 到 Agent 的完整路径,后面的联调会变成一段痛苦的盲猜过程。
2. OpenClaw 与企微 / 钉钉的连接原理:消息从 IM 到 Agent 的完整路径
2.1 一切从事件开始:回调、长连接与消息通道
OpenClaw 的核心工作机制是事件驱动。它本身不主动去 IM 平台捞消息,而是等平台把消息"送上门"。这里的送的姿势有两种,对应的就是两个平台最本质的技术差异。
第一种是 HTTP 回调(Webhook)。企业微信采用的就是这种模式。你在企微后台配置一个接收消息的 URL,当有人给机器人发消息时,企微服务器会向这个 URL 发送一个 POST 请求,请求体里携带加密后的消息数据。OpenClaw 需要做的是:接收请求、验签、解密、解析消息、交给 Agent 处理、再通过 API 把结果发回去。
第二种是长连接(Stream 模式)。钉钉比较聪明,提供了一种 WebSocket 长连接的消息接收方式。OpenClaw 通过官方 SDK 主动连上钉钉的消息推送通道,钉钉有消息产生时直接通过这个长连接推给客户端。这种方式最大的好处是:不需要一个公网可达的回调地址,本地开发的时候不用折腾内网穿透,非常省心。
两种模式的对比可以看这个表:
| 对比项 | 企业微信 | 钉钉 |
|---|---|---|
| 消息接收模式 | HTTP 回调 | HTTP 回调 / Stream 长连接 |
| 是否需要公网回调地址 | 必须 | 用 Stream 则不需要 |
| 消息数据格式 | XML + AES 加密 | JSON + AES 加密 |
| 签名方式 | SHA1 签名 + AES 解密 | HMAC-SHA256 签名 + AES 解密 |
| 发送消息 API | 需要 access_token | 需要 access_token 或 Webhook 地址 |
2.2 权限模型:企微看部门、钉钉看应用
接入 IM 还有一个容易忽略但很重要的层面:权限模型。为什么用户 @ 了机器人之后,OpenClaw 知道该不该回、能回什么内容的权限?
企业微信的天然单位是"部门"和"成员"。你可以控制一个 AI 应用对哪些部门可见,OpenClaw 拿到的消息里是带发送者 UserID 的,这个 UserID 能直接映射到公司的组织架构。所以你可以很自然地做出这样的规则:市场部的同事问数据,AI 只回答公开信息;研发部的同事问 GitLab 状态,AI 才会去调用内部工具。
钉钉的权限模型更偏向"应用维度"。你创建一个企业内部应用,给它配机器人,然后通过应用的角色权限来约束它能调用什么接口。同时钉钉消息里面带的是 senderStaffId,如果你需要知道这个人属于哪个部门,得再用通讯录接口去查,比企微微稍绕一层。
在实际配置 OpenClaw 的时候,我建议先把权限想清楚再动手。你至少需要明确三个问题:
- 这个 AI 是给全公司用的,还是只给特定部门用的?
- 它能不能访问内部系统?能访问到哪一级?
- 它在群聊里是所有人 @ 它都回,还是只响应白名单成员?
这些不一定都要在 IM 后台一次配完,但一定要在消息处理逻辑里留好判断的入口,否则后面越用越乱。
3. 企业微信接入全流程:从自建应用到第一句对话
3.1 企微后台的自建应用与三件套凭证
企业微信接入的第一步是在管理后台创建一个自建应用。登录企业微信管理后台,进入"应用管理",在最下面找到"自建应用",点创建。这一步没什么复杂的,填个应用名称和 Logo,选择一个可见范围就行。创建完成后,进入应用详情页,你会看到两个关键的凭证信息:
- AgentId:这个应用的唯一标识,后续调用所有 API 都要带上。
- Secret:应用密钥,调用 access_token 时使用。
除了这两个,还需要到"我的企业"页面拿到 CorpID,这是企业本身的唯一 ID。这三样是企微接入的基础凭证,建议先存到一个安全的地方,后面配置 OpenClaw 时用。
3.2 配置接收消息服务器:URL 验证环节的第一次崩溃
接下来是最容易卡住新手的地方:配置"接收消息"。
在应用详情页里找到"接收消息"设置项,点击启用,会要求你填三个东西:
- URL:OpenClaw 接收企微回调的公网地址,比如
https://your-domain/openclaw/wecom/callback。 - Token:自定义的一个字符串,用于签名验证。
- EncodingAESKey:用于消息加解密,可以随机生成,也可以自己填一个 43 位字符串。
填完保存时,企微服务器会往你的 URL 发一个 GET 请求,带上msg_signature、timestamp、nonce、echostr四个参数。这其实是平台在验证这个 URL 到底是不是你控制的。你的服务需要做两件事:
- 用 Token、timestamp、nonce 计算 SHA1 签名,和 msg_signature 比对,确认请求确实来自企微。
- 如果签名通过,用 EncodingAESKey 对应的 AES 密钥解密 echostr,拿到明文后原样返回给企微。
这一步能顺利跑通,你的服务才算被企微信任。我见过太多人在这一步卡住,十有八九是签名算法写错,或者解密后的内容没有原样返回。
下面是一个简化的验证逻辑示例,我用 Python 写了个参考实现:
import hashlib import base64 import json from Crypto.Cipher import AES def verify_signature(token, timestamp, nonce, msg_signature): sort_list = sorted([token, timestamp, nonce]) calc_signature = hashlib.sha1(''.join(sort_list).encode('utf-8')).hexdigest() return calc_signature == msg_signature def decrypt_message(encoding_aes_key, msg_encrypt): aes_key = base64.b64decode(encoding_aes_key + '=') cipher = AES.new(aes_key, AES.MODE_CBC, aes_key[:16]) decrypted = cipher.decrypt(base64.b64decode(msg_encrypt)) # 去掉 PKCS#7 填充 pad_len = decrypted[-1] content = decrypted[:-pad_len] # 明文格式: 16字节随机串 + 4字节网络序长度 + 消息体 + CorpID msg_len = int.from_bytes(content[16:20], 'big') msg = content[20:20 + msg_len].decode('utf-8') return msg这里有一个非常重要的细节:加密用的 AES Key 不是把 EncodingAESKey 原样拿去做解密的,而是要先做一次 Base64 解码得到 32 字节的密钥,CBC 模式的 IV 取的是这个密钥的前 16 字节。很多同学把 EncodingAESKey 当成字符串直接放进加密库,导致初始化失败,这是非常典型的错误。
3.3 OpenClaw 侧配置:把企微通道接进来
企微后台配好之后,回到 OpenClaw 的配置文件。OpenClaw 支持多种消息通道,企微是其中一个原生类型。我当时的配置文件大概是这样的:
channels: wecom: type: wecom corp_id: "your_corp_id" agent_id: "your_agent_id" secret: "your_agent_secret" token: "your_callback_token" encoding_aes_key: "your_encoding_aes_key" callback_url: "https://your-domain/openclaw/wecom/callback" enabled: true启动 OpenClaw,看到日志里出现类似wecom callback server started at :8787的字样,就说明回调服务已经监听起来了。这时候再去企微后台保存接收消息配置,如果一切正常,配置会一次性保存成功。
有一点要提醒:OpenClaw 跑在本机时,your-domain不能是localhost,因为企微服务器无法访问你本机。我当时是用了一个内网穿透工具把本机的 8787 端口映射到一个公网临时域名。不过这只适合开发阶段,生产环境还是应该把 OpenClaw 部署在公司有固定公网 IP 的服务器上。
3.4 跑通第一句对话:从 @ 机器人到收到回复
配置验证通过后,就可以在企微里和机器人对话了。有两种方式触发:
- 单聊:直接给机器人发消息。
- 群聊:在群里 @ 机器人,然后输入内容。
在群里@机器人,需要先在企微后台把机器人添加到群里。你在应用详情页的"群机器人"区域可以创建一个群机器人,拿到 Webhook 地址。但要注意,群 Webhook 只能主动发消息,不能接收群聊里 @ 机器人的消息。要接收群里的 @ 消息,必须通过刚才配置的"接收消息"回调。
这其实是企微比较容易搞混的一个点:接收消息和群机器人 Webhook 是两套不同的机制。
消息发出来之后,OpenClaw 收到的回调数据大概是这样一份 XML:
<xml> <ToUserName><![CDATA[corp_id]]></ToUserName> <FromUserName><![CDATA[user_id]]></FromUserName> <CreateTime>1717157892</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你好,帮我总结今天的周报]]></Content> <MsgId>1234567890</MsgId> <AgentID>1000002</AgentID> </xml>OpenClaw 会把<Content>的内容作为用户的输入交给 Agent 处理,处理完再调用发送消息 API 回复。发送消息需要先获取 access_token:
curl "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=YOUR_CORP_ID&corpsecret=YOUR_SECRET"拿到 access_token 后,调用消息发送接口:
curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{ "touser": "user_id", "msgtype": "text", "agentid": 1000002, "text": { "content": "这是 OpenClaw 的回复" } }'第一次跑通这个流程的时候,我盯着企微对话框里 AI 返回的那行字看了好一会儿,感觉整个协作方式都被改变了。
3.5 进阶能力:图片、文件与链接卡片消息
文本对话只是第一步。实际使用中,AI 的输出远不止文字:数据分析结果要用表格展示,生成的报告要作为文件发送,系统状态页面需要以链接的形式呈现。企微的消息 API 对这些场景的支持都挺完善。
发送图片消息相对特殊,你不能直接把本地图片推给企微,而是先把图片素材上传到企微的临时素材接口,拿到 media_id,再通过消息接口发送。这里有一个容易被坑的地方:临时素材有效期只有 3 天,如果你把 media_id 缓存到本地第二天再用,大概率会报错。建议发送前实时上传,不要做长期缓存。
链接卡片消息是我用得比较多的一种形式。当 OpenClaw 执行完一个复杂任务,比如生成了某份数据报表,我会让它返回一个带有标题、描述和跳转链接的卡片消息,同事点击卡片就能直达报表页面。卡片消息发送的 JSON 结构大概是:
{ "touser": "user_id", "msgtype": "news", "agentid": 1000002, "news": { "articles": [ { "title": "数据报表已生成", "description": "点击查看本周各渠道数据汇总", "url": "https://your-report-page", "picurl": "https://your-image-url" } ] } }这样消息呈现就从"一句干巴巴的文本"升级成了"一个完整的工作卡片",同事看到就知道点进去能看到什么。
4. 钉钉接入全流程:Stream 模式更省心,但避坑也不含糊
4.1 创建钉钉企业内部应用与机器人
钉钉的接入第一步是登录钉钉开放平台,进入"企业内部应用",创建一个应用。创建完成后在应用详情里能看到 AppKey 和 AppSecret,这是钉钉侧的凭证基础。接着在应用内添加一个机器人,设置机器人的名称和头像。
这里你会遇到第一个选择:机器人的消息接收模式。钉钉提供了两种方式,我在 2.1 节提过,一个是 HTTP 回调,一个是 Stream 模式。我当时毫不犹豫选了 Stream 模式,原因很简单:OpenClaw 跑在一台内网服务器上,如果用 HTTP 回调,我需要再配一个内网穿透,多一个环节就多一个可能的故障点。而 Stream 模式只需要 OpenClaw 主动向外建立一个 WebSocket 长连接,稳定且不需要暴露任何端口。
4.2 Stream 模式配置:省掉公网回调,但不是零配置
钉钉的 Stream 模式虽然不需要公网回调地址,但它对连接本身的安全性有要求。在后台配置 Stream 模式时,你需要设置:
- 加签密钥(通常叫做 Secret / Signing Key):用于对连接请求做签名认证。
- AES 密钥(通常叫 aes_key):用于消息体的加解密。
这两个密钥在建立 Stream 连接时都会被用到。OpenClaw 侧的配置如下:
channels: dingtalk: type: dingtalk app_key: "your_app_key" app_secret: "your_app_secret" mode: stream stream_client_id: "your_stream_client_id" stream_client_secret: "your_stream_client_secret" aes_key: "your_aes_key" sign_secret: "your_sign_secret" enabled: true启动 OpenClaw 后,它会用 Stream 客户端 SDK 主动连接钉钉消息通道,连接成功后日志里能看到类似stream client connected的信息。从这一刻起,钉钉平台已经把 OpenClaw 当成一个"在线"的机器人了。
钉钉 Stream 的另一个好处是:长连接是双向的,消息推送延迟非常低。实测下来,群聊里 @ 机器人,基本是秒级收到消息,不需要像 HTTP 轮询那样靠请求频率换取实时性。
4.3 事件订阅:不要漏掉"机器人接收消息"这个开关
这是我在钉钉接入时踩过的一个不大不小的坑。
我在开放平台把机器人和 Stream 模式都配好之后,OpenClaw 也显示 Stream 连接成功了,但在钉钉群里 @ 机器人,却完全没有任何反应。排查了很久,发现原因不在代码,而在"事件订阅"配置。
钉钉的消息推送不是默认全开的,你需要在后台明确订阅"机器人接收消息"这个事件,平台才会把 @ 机器人的消息通过 Stream 推过来。我最初以为创建了机器人就自动具备了消息接收能力,结果漏了这一步。
正确的操作路径是:进入应用详情 → 事件与回调 → 订阅管理,在事件列表里找到"机器人接收消息"或者类似的选项,勾选订阅,然后保存。保存的时候钉钉会要求进行配置校验,这个校验用的也是加签和 AES 解密流程,OpenClaw 已经内置了处理逻辑,直接让它参与校验即可。
用表格说一下 HTTP 回调和 Stream 在事件订阅上的区别:
| 步骤 | HTTP 回调模式 | Stream 模式 |
|---|---|---|
| 配置回调 URL | 需要,且要通过 URL 验证 | 不需要 |
| 配置加签/AES | 需要 | 需要 |
| 订阅事件 | 需要 | 需要 |
| 内网穿透 | 通常需要 | 不需要 |
| 调试便利性 | 需要公网访问,较弱 | 本地直接可跑,很强 |
4.4 群聊 @ 触发与单聊消息的两种入口
钉钉群里 @ 机器人和企微逻辑类似,但细节上有个区别需要适应。企微里机器人被 @ 后,回调里的 Content 会包含 @ 的语义符。而钉钉的消息体里会区分消息类型和触发场景,OpenClaw 需要从 JSON 里取text.content并清洗掉 @ 产生的噪音内容。
我举个例子。钉钉推送的机器人消息 JSON 结构大致如下:
{ "senderNick": "张三", "senderStaffId": "user123", "conversationType": "group", "msgtype": "text", "text": { "content": " @机器人 帮我查一下最近的订单状态" }, "msgId": "msg456", "robotCode": "robot_code" }OpenClaw 在处理时会做两件事:第一步判断conversationType是 group 还是 single,来决定回复策略;第二步清理content里的 @ 提及内容,因为那段内容对模型来说是噪声。如果不做清洗,把 "@机器人帮我查订单" 原封不动丢给模型,虽然模型一般也能理解,但偶尔会在回答里复述出 @ 内容,观感很差。
钉钉回复消息有两个途径。如果是群聊里 @ 触发的,OpenClaw 可以调用机器人 Webhook 往群里发消息,这个 Webhook 可以在机器人设置页面获取,使用起来最直接。如果需要给某个具体用户发单聊消息,那就得调用工作通知接口,后者可以发文本、图片、链接、Markdown 等多种格式,而且不受群聊范围的限制。
我在实际使用中给钉钉通道加了一个小能力:当用户在单聊里向机器人提问时,OpenClaw 会把消息上下文保存到本地会话记录中,这样用户隔了几个小时再回来追问,AI 仍然记得之前聊过什么。这个功能在企业微信里我没有启用,因为企微的单聊入口更多会被内部 OA 类机器人占用,场景逻辑不同。
5. 联调实战:验签失败、消息重复、图片失效的完整排查链路
5.1 验签失败的根因:签名串拼接顺序的"正确性陷阱"
在一次联调中,我配置好企业微信的接收消息服务器之后,点击保存,后台立刻提示"URL 验证失败"。我第一反应是内网穿透的地址没写对,于是打开日志,看到 OpenClaw 确实收到了请求,并且打印出了 msg_signature。这说明 URL 是通的,问题出在签名验证或解密环节。
我把签名计算逻辑打开,一行一行对照。问题很快就浮出水面:我最初的代码把 Token、timestamp、nonce 三个字符串直接做了拼接,但企微要求的是先按字典序排序,再拼接成字符串,然后做 SHA1。我的代码里排序写成了按字符串长度排序,这样算出来的签名和企微传过来的 msg_signature 永远对不上。
这种错其实很隐蔽,因为签名结果看起来都是 40 位的十六进制字符串,不仔细比对根本发现不了。修复后的代码:
sort_list = sorted([token, timestamp, nonce]) # 必须按字典序 raw = ''.join(sort_list) signature = hashlib.sha1(raw.encode('utf-8')).hexdigest()验证通过之后,又遇到解密失败。这次的原因更让人无语:企微后台生成的 EncodingAESKey 是 43 位字符串,而我的解密代码在 Base64 解码时少补了一个等号。AES-256 的 Key 需要 32 字节,Base64 解码 43 位字符串后只有 31 字节,必须手动补一个=凑成 44 位再解码。补上之后,解密立刻正常。
这个排查过程的完整链路是:
- 确认回调 URL 能收到请求 -> 说明网络链路通
- 检查签名算法 -> 发现排序逻辑写错 -> 修复
- 检查 AES 解密 -> 发现 Base64 缺等号 -> 修复
- 后台重新保存配置 -> 成功
排错的核心思路就是逐层确认:网络通不通,签名对不对,解密能不能出明文。每一步都独立验证,不要跳步。
5.2 消息重复推送:IM 平台的 at-least-once 语义
联调通过之后,接踵而来的第二个问题是:OpenClaw 偶尔会重复回复同一条消息。用户发一句"查一下今天的天气",机器人回了两次几乎一样的天气结果。
查证后发现,这是 IM 平台的消息投递机制导致的。企微和钉钉的消息回调都遵循 at-least-once 语义:如果平台收到服务端的响应超时,或者响应编码不对,它会认为消息没有成功送达,于是重新推送同一条回调。OpenClaw 处理回调用了较长时间,超过平台默认超时时长,平台就重试了一次。
解决思路很简单:消息幂等。OpenClaw 内部维护一个最近处理过的消息 ID 列表,收到消息时先判断这个消息 ID 是否已经处理过,处理过就直接忽略。我在配置里开了幂等开关,消息 ID 的缓存窗口设置为 10 分钟,完全够用。
幂等处理的关键是消息 ID 的选取。企微用<MsgId>,钉钉用msgId,这两个 ID 在平台内是唯一的,直接拿来做幂等键没有风险。这里有个小坑:不要用发送时间加发送人的组合作为幂等键,因为同一个用户在同一秒发两条不同内容,会被误判成重复消息。
5.3 调用频率限制:感知不到的隐形天花板
消息收发本身跑通之后,高频测试时遇到了第三个问题:OpenClaw 发送消息的接口开始报错,错误码提示调用频率超出限制。
企微的主动发送消息接口、钉钉的工作通知接口都有明确的频率限制。企微对单个应用发送消息的限制大概是每分钟几万次,听起来很多,但如果你的 AI 在群里高频回复,或者批量给多个人推送消息,很快就会触碰限制。
我当时做的优化有两点:
- 在 OpenClaw 侧对 API 调用加上限流,固定一个时间窗口内最多发送 N 条消息,多余的排队。
- 对同一条回复的多个接收人做批量聚合,比如一条公告要发 30 个人,不要循环 30 次单发,而是看接口是否支持批量收件人。企微的 touser 支持多个 UserID 用竖线分隔,一批就能发完,能省下大量 API 调用次数。
钉钉那边,群机器人 Webhook 的频率限制更严格,大概每分钟只能发 20 条左右。如果你的群消息量很大,建议把高频的即时通知用群机器人发,低频的工作通知走应用接口,两条通道搭配使用。
5.4 图片素材有效期:media_id 缓存引发的幽灵故障
还有一个我要重点说的坑,发生在企微通道上线运行第三天的早上。同事反馈 AI 发送的图片打不开了,我查了日志发现发送接口返回成功,但企微客户端里图片一直显示加载失败。
排查了半天,根因在 media_id 的缓存逻辑。OpenClaw 首次上传图片到企微临时素材,拿到一个 media_id 并缓存到了本地。我原本以为企微的临时素材有效期和微信一样有 3 天,于是设了 72 小时缓存。实际上,企微临时素材的可用窗口没那么长,过期后再用它发消息,接口虽然不报错,但图片实际无法显示。
之后我把策略改成:每次发送图片前实时调用素材上传接口,不再做缓存。虽然多了一次 API 往返,但彻底杜绝了失效问题。现在线上运行了几个月,再没出现过图片打不开的情况。
这类"接口返回成功但实际不可用"的故障是最难排查的,因为报错日志是绿的,但业务是坏的。遇到这种诡异现象,优先怀疑素材类的临时凭证是否过期,不要只看接口的返回码。
6. 组织与扩展:从单机器人到一整个 AI 作战小队
6.1 用消息会话隔离,让多个 Agent 共享一个通道
当我成功把企微和钉钉都接入 OpenClaw 之后,很快又遇到了一个新问题:团队的诉求不是一个 AI,而是很多个 AI。
有人希望有一个专门做数据分析的机器人,有人需要一个会查财务流程的助手,还有人想让 AI 定时推送舆情监控。如果每来一个需求就创建一个新的 IM 应用,后台会越来越乱,回调配置、权限管理、凭证维护的成本都会翻倍。
更优雅的做法是:在 OpenClaw 这一个通道下,用会话和路由规则做Agent 隔离。每个用户或每个群聊对应一个会话,消息进入后,OpenClaw 根据发送人、群组、消息关键词,决定把请求路由给哪个 Agent。
我在企微侧是这么设计的:单个应用下,同一个机器人在不同群里,OpenClaw 为每个群分配一个独立的会话上下文。A 群里聊数据,B 群里聊流程,彼此互不干扰。这种方式对用户来说感知不到背后的路由逻辑,他们只觉得"这个群里的 AI 好懂我"。
6.2 企业微信的部门隔离与钉钉的应用级权限
组织多 Agent 的时候,权限控制比功能开发更重要。我的两个通道做了不同的权限策略。
企业微信侧,因为消息里天然带 UserID,我配置了别名表,把部门映射到 Agent 的访问范围。某部门的成员提问时,只路由到该部门允许使用的 Agent;不在范围内的成员提问,机器人会礼貌地回复"暂未开放权限"。这个判断逻辑完全在 OpenClaw 里完成,企微后台只需要把应用可见范围设为全公司即可。
钉钉侧则利用应用本身的角色权限。钉钉后台可以为应用设置不同的权限范围,比如数据应用只能调用特定 API,财务应用只能调用另一些 API。OpenClaw 在钉钉通道上接入了多个机器人,不同机器人绑定不同的钉钉应用,天然实现了应用级隔离。
这两种策略各有优劣。企微的方案灵活,改权限不用动后台;钉钉的方案更安全,因为权限在平台侧就硬隔离了,即使消息被非法构造,也调不到超出范围的接口。
6.3 从被动应答到主动推送:让 AI 自己找活干
接入 IM 的另一个想象力空间是主动推送。OpenClaw 不完全是一个"你问我答"的被动服务,它也可以定时执行任务,然后把结果推送到群里。
我实现了两个典型用法。第一个是每日早报:每天早上 9 点,OpenClaw 抓取内部系统的核心数据,自动生成摘要,通过钉钉群 Webhook 发到管理层群。第二个是异常预警:当 AI 监控到某个服务的日志中出现错误率升高,它会自动在企微群里发起一条告警卡片。
主动推送的意义在于,把 AI 从"被调用的工具"变成了"主动工作的员工",这才是 AI 融入协作场景最有价值的方向。
收尾:接入之后的几点坦白
把企微和钉钉都接入 OpenClaw 之后,我自己最大的感受是:技术上的难点从来不是某一个环节有多复杂,而是要在一个系统里把很多个环节稳定连接起来。回调、验签、解密、消息路由、幂等、限流、素材管理,每一个点单拆出来都不难,但组合在一起,任何一个环节掉链子,整体体验都会崩。
最后分享一个经验,给所有准备做这件事的人:先用自己的账号把单聊跑通,再用小群测试 @ 消息,最后才开放给全团队使用。把第一句对话的时间控制在半小时内,跑通之后再一点点加功能。不要一开始就想把图片、文件、卡片全部接好,那只会让你在联调阶段淹没在问题里。IM 接入这件事,先通后顺,先窄后宽,是最稳妥的节奏。