微软Teams(插件)
“凡进入此地者,必弃一切希望。” 更新日期:2026-01-21 状态:支持文本和DM附件;在频道或群组中发送文件需要sharePointSiteId + Graph权限(详见在群聊中发送文件)。投票通过自适应卡片发送。
插件要求
Microsoft Teams作为插件提供,不包含在核心安装中。 重大变更(2026年1月15日): MS Teams已从核心移出。如果您使用它,必须安装插件。 解释:这使核心安装更加轻量,并允许独立更新 Microsoft Teams 的依赖项。 通过CLI(npm注册表)安装:- 安装Microsoft Teams插件。
- 创建一个Azure Bot(包括应用ID、客户端密钥和租户ID)。
- 使用这些凭据配置OpenClaw。
- 通过公共URL或隧道公开
/api/messages(默认端口3978)。 - 安装Teams应用包并启动网关。
channels.msteams.groupPolicy: "allowlist")。要允许群组回复,请设置channels.msteams.groupAllowFrom(或使用groupPolicy: "open"允许任何成员,但需提及)。
目标
- 通过Teams私信、群聊或频道与OpenClaw进行对话。
- 保持路由确定性:回复始终返回到消息最初到达的频道。
- 默认采用安全的频道行为(除非另行配置,否则必须提及)。
配置写入
默认情况下,Microsoft Teams被允许写入由/config set|unset触发的配置更新(需要commands.config: true)。
禁用方法:
访问控制(私信 + 群组)
DM访问- 默认:
channels.msteams.dmPolicy = "pairing"。未知发件人将在批准前被忽略。 channels.msteams.allowFrom接受AAD对象ID、UPN或显示名称。当凭据允许时,向导会通过Microsoft Graph将名称解析为ID。
- 默认:
channels.msteams.groupPolicy = "allowlist"(除非您添加groupAllowFrom,否则被阻止)。使用channels.defaults.groupPolicy在未设置时覆盖默认值。 channels.msteams.groupAllowFrom控制哪些发件人在群聊/频道中可以触发(回退到channels.msteams.allowFrom)。- 设置
groupPolicy: "open"以允许任何成员(默认仍受提及限制)。 - 要允许无频道,请设置
channels.msteams.groupPolicy: "disabled"。
- 通过在
channels.msteams.teams下列出团队和频道来限制群组/频道回复。 - 密钥可以是团队ID或名称;频道密钥可以是对话ID或名称。
- 当
groupPolicy="allowlist"和团队白名单同时存在时,仅接受列出的团队/频道(受提及限制)。 - 配置向导接受
Team/Channel条目并为您存储。 - 在启动时,OpenClaw会将团队/频道和用户白名单名称解析为ID(在Graph权限允许的情况下),并记录映射;未解析的条目按原样保留。
工作原理
- 安装Microsoft Teams插件。
- 创建一个Azure Bot(包括应用ID、密钥和租户ID)。
- 构建一个引用该机器人并包含以下RSC权限的Teams应用包。
- 将Teams应用上传或安装到团队中(或用于DM的个人范围)。
- 在
msteams中配置~/.openclaw/openclaw.json(或环境变量),并启动网关。 - 网关默认监听
/api/messages上的Bot Framework Webhook流量。
第一步:创建Azure机器人
- 前往创建Azure Bot
- 填写基本选项卡:
| 字段 | 值 |
|---|---|
| Bot句柄 | 您的机器人名称,例如openclaw-msteams(必须唯一) |
| 订阅 | 选择您的Azure订阅 |
| 资源组 | 创建新资源组或使用现有资源组 |
| 定价层 | 免费适用于开发/测试 |
| 应用程序类型 | 单租户(推荐 - 见下方注释) |
| 创建类型 | 创建新的Microsoft App ID |
弃用通知: 自2025年7月31日之后,新多租户机器人的创建已被弃用。对于新机器人,请使用单租户。
- 单击审核+创建 → 创建(等待约1–2分钟)
第二步:获取凭据
- 转到您的Azure Bot资源 → 配置
- 复制Microsoft App ID → 这是您的
appId - 单击管理密码 → 转到应用程序注册
- 在证书与密钥下 → 新建客户端密钥 → 复制值 → 这是您的
appPassword - 转到概览 → 复制目录(租户)ID → 这是您的
tenantId
第三步:配置消息端点
- 在Azure Bot中,转到配置
- 将消息端点设置为您的Webhook URL:
- 生产:
https://your-domain.com/api/messages - 本地开发:使用隧道(详见下方本地开发)
- 生产:
第四步:启用Teams频道
- 在Azure Bot中,转到渠道
- 单击Microsoft Teams → 配置 → 保存
- 接受服务条款
本地开发(隧道)
Teams无法访问localhost。使用隧道进行本地开发:
选项A:ngrok
- 单击**+ 新应用**
- 填写基本信息(名称、描述、开发者信息)
- 转到应用功能 → 机器人
- 选择手动输入机器人ID,并粘贴您的 Azure Bot 应用 ID
- 检查适用范围:个人、团队、群聊
- 单击分发 → 下载应用包
- 在 Teams 中:应用 → 管理您的应用 → 上传自定义应用 → 选择 ZIP 文件
测试机器人
选项A:Azure Web聊天(先验证Webhook)- 在Azure门户中,导航到您的Azure Bot资源,然后选择“在Web Chat中测试”。
- 发送一条消息——您应该会收到回复。
- 这将确认,在配置Teams设置之前,您的Webhook端点已正常运行。
- 安装Teams应用(通过侧载或组织目录)
- 在Teams中找到机器人并发送私信
- 检查网关日志以查看传入活动
设置(最小文本模式)
-
安装Microsoft Teams插件
- 从npm:
openclaw plugins install @openclaw/msteams - 从本地检出:
openclaw plugins install ./extensions/msteams
- 从npm:
-
机器人注册
- 创建一个Azure Bot(见上文),并记下以下信息:
- 应用ID
- 客户端密钥(应用密码)
- 租户ID(单租户)
- 创建一个Azure Bot(见上文),并记下以下信息:
-
Teams应用清单
- 包含一个
bot条目,带有botId = <App ID>。 - 范围:
personal、team、groupChat。 supportsFiles: true(用于个人范围的文件处理)。- 添加RSC权限(见下文)。
- 创建图标:
outline.png(32x32)和color.png(192x192)。 - 将所有三个文件一起压缩:
manifest.json、outline.png、color.png。
- 包含一个
-
配置OpenClaw
MSTEAMS_APP_IDMSTEAMS_APP_PASSWORDMSTEAMS_TENANT_ID
-
机器人端点
- 将Azure Bot消息端点设置为:
https://<host>:3978/api/messages(或您选择的路径/端口)。
- 将Azure Bot消息端点设置为:
-
运行网关
- 当插件安装且
msteams配置包含凭据时,Teams频道会自动启动。
- 当插件安装且
历史背景
channels.msteams.historyLimit控制多少最近的频道/群组消息会被纳入提示中。- 回退到
messages.groupChat.historyLimit。设置0以禁用(默认50)。 - 私信历史可以通过
channels.msteams.dmHistoryLimit(用户开启)来限制。每用户覆盖:channels.msteams.dms["<user_id>"].historyLimit。
当前Teams RSC权限(清单)
这些是我们Teams应用清单中的现有特定于资源的权限。它们仅适用于已安装该应用的团队或聊天。 对于频道(团队范围):ChannelMessage.Read.Group(应用程序) - 接收所有频道消息,无需@提及ChannelMessage.Send.Group(应用程序)Member.Read.Group(应用程序)Owner.Read.Group(应用程序)ChannelSettings.Read.Group(应用程序)TeamMember.Read.Group(应用程序)TeamSettings.Read.Group(应用程序)
ChatMessage.Read.Chat(应用程序) - 无需@提及即可接收所有群聊消息
示例Teams清单(已编辑)
具有所需字段的最小有效示例。替换ID和URL。清单注意事项(必备字段)
bots[].botId必须与Azure Bot应用ID匹配。webApplicationInfo.id必须与Azure Bot应用ID匹配。bots[].scopes必须包含您计划使用的表面(personal、team、groupChat)。bots[].supportsFiles: true是个人范围内文件处理所必需的。authorization.permissions.resourceSpecific如果需要频道流量,则必须包括频道读取/发送。
更新现有应用
要更新已安装的Teams应用(例如,添加RSC权限):- 使用新设置更新您的
manifest.json - 添加
version字段(例如,1.0.0→1.1.0) - 重新压缩清单并附上图标(
manifest.json、outline.png、color.png) - 上传新的zip:
- 选项A(Teams管理中心): 打开Teams管理中心,依次进入“Teams应用”→“管理应用”,找到您的应用,然后上传新版本。
- 选项B(侧载): 在Teams中,依次进入“应用”→“管理您的应用”,然后上传自定义应用。
- 对于团队频道: 为使新权限生效,请在每个团队中重新安装应用。
- 彻底退出并重新启动Teams(而不仅仅是关闭窗口),以清除缓存的应用元数据。
功能:仅对比RSC与图像
仅使用Teams RSC(已安装应用,无Graph API权限)
有效:- 读取频道消息文本内容。
- 发送频道消息文本内容。
- 接收**个人(DM)**文件附件。
- 频道/群组的图像或文件内容(负载仅包含HTML存根)。
- 下载存储在SharePoint/OneDrive中的附件。
- 读取消息历史(超出实时Webhook事件)。
使用Teams RSC + Microsoft Graph应用程序权限
新增:- 下载托管内容(粘贴在消息中的图像)。
- 下载存储在SharePoint/OneDrive中的文件附件。
- 通过Graph读取频道/聊天消息历史。
| 功能 | RSC权限 | Graph API |
|---|---|---|
| 实时消息 | 是(通过webhook) | 否(仅轮询) |
| 历史消息 | 否 | 是(可查询历史) |
| 设置复杂度 | 仅应用清单 | 需要管理员同意 + 令牌流程 |
| 离线工作 | 否(必须运行) | 是(随时可查询) |
ChannelMessage.Read.All的Graph API(需获得管理员同意)。
启用图谱的媒体 + 历史(频道所需)
如果您需要频道中的图像/文件,或想获取消息历史,则必须启用Microsoft Graph权限并获得管理员同意。- 在Entra ID(Azure AD)的应用程序注册中,添加Microsoft Graph应用程序权限:
ChannelMessage.Read.All(频道附件 + 历史)Chat.Read.All或ChatMessage.Read.All(群聊)
- 为租户授予管理员同意。
- 提升Teams应用的清单版本,重新上传,并在Teams中重新安装应用。
- 彻底退出并重新启动Teams,以清除缓存的应用元数据。
- 网关超时
- Teams 重试消息(导致重复)
- 回复丢失
格式化
Teams的Markdown功能比Slack或Discord更有限:- 基本格式有效:粗体、斜体、
code、链接 - 复杂的Markdown(如表格、嵌套列表)可能无法正确渲染
- 自适应卡片可用于投票和任意卡片发送(见下文)
配置
关键设置(有关共享频道模式,请参见/gateway/configuration):
channels.msteams.enabled:启用或禁用频道。channels.msteams.appId、channels.msteams.appPassword、channels.msteams.tenantId:机器人凭据。channels.msteams.webhook.port(默认为3978)channels.msteams.webhook.path(默认为/api/messages)channels.msteams.dmPolicy:pairing | allowlist | open | disabled(默认:配对)channels.msteams.allowFrom:DM白名单(AAD对象ID、UPN或显示名称)。当Graph访问可用时,向导会在设置期间将名称解析为ID。channels.msteams.textChunkLimit:出站文本块大小。channels.msteams.chunkMode:length(默认)或newline在长度分块前按空行(段落边界)拆分。channels.msteams.mediaAllowHosts:入站附件主机白名单(默认为Microsoft/Teams域)。channels.msteams.requireMention:在频道/群组中需要@提及(默认为真)。channels.msteams.replyStyle:thread | top-level(参见回复风格)。channels.msteams.teams.<teamId>.replyStyle:按团队覆盖。channels.msteams.teams.<teamId>.requireMention:按团队覆盖。channels.msteams.teams.<teamId>.tools:默认的按团队的每发送方工具政策覆盖(allow/deny/alsoAllow),当缺少频道覆盖时使用。channels.msteams.teams.<teamId>.toolsBySender:默认的按团队的每发送方工具政策覆盖("*"通配符支持)。channels.msteams.teams.<teamId>.channels.<conversationId>.replyStyle:按频道覆盖。channels.msteams.teams.<teamId>.channels.<conversationId>.requireMention:按频道覆盖。channels.msteams.teams.<teamId>.channels.<conversationId>.tools:按频道的工具政策覆盖(allow/deny/alsoAllow)。allow:按频道的每发送方工具政策覆盖(deny通配符支持)。deny:按频道的每发送方工具政策覆盖(alsoAllow通配符支持)。allow:按频道的每发送方工具政策覆盖("*"通配符支持)。deny:按频道的每发送方工具政策覆盖。alsoAllow:按频道的每发送方工具政策覆盖。channels.msteams.teams.<teamId>.channels.<conversationId>.toolsBySender:按频道的每发送方工具政策覆盖("*"通配符支持)。channels.msteams.sharePointSiteId:用于群聊/频道文件上传的SharePoint站点ID(参见在群聊中发送文件)。
路径与会话
- 会话密钥遵循标准代理格式(参见/概念/会社):
- 直接消息共享主会社(
agent:<agentId>:<mainKey>)。 - 频道/群组消息使用对话ID:
agent:<agentId>:msteams:channel:<conversationId>agent:<agentId>:msteams:group:<conversationId>
- 直接消息共享主会社(
回复风格:线程 vs 帖子
Teams最近在同一底层数据模型上引入了两种频道UI风格:| 风格 | 描述 | 推荐的replyStyle |
|---|---|---|
| 帖子(经典) | 消息以卡片形式显示,下方有线程回复 | thread(默认) |
| 线程(类似Slack) | 消息线性流动,更像Slack | top-level |
replyStyle:
thread在线程风格的频道中 → 回复看起来嵌套得很尴尬top-level在帖子风格的频道中 → 回复显示为单独的顶级帖子,而不是在线程中
replyStyle:
附件与图像
当前限制:- 私信: 图像和文件附件通过Teams机器人文件API进行处理。
- 频道/群组: 附件存储在M365存储中(SharePoint/OneDrive)。Webhook负载仅包含HTML存根,不包含实际文件字节。要下载频道附件,必须具备Graph API权限。
channels.msteams.mediaAllowHosts进行覆盖(使用["*"]允许任何主机)。
在群聊中发送文件
机器人可以使用FileConsentCard流程在私信中发送文件(内置)。然而,在群聊或频道中发送文件需要额外的设置:| 上下文 | 文件如何发送 | 设置需求 |
|---|---|---|
| 私信 | FileConsentCard → 用户接受 → 机器人上传 | 开箱即用 |
| 群聊/频道 | 上传到SharePoint → 分享链接 | 需要sharePointSiteId + Graph权限 |
| 图像(任何上下文) | Base64编码的内联 | 开箱即用 |
为什么群聊需要SharePoint
机器人没有个人OneDrive驱动器(/me/driveGraph API端点对应用程序身份无效)。要在群聊或频道中发送文件,机器人会上传到SharePoint站点并创建共享链接。
设置
-
在Entra ID(Azure AD)→ 应用注册中添加Graph API权限:
Sites.ReadWrite.All(应用程序) - 将文件上传到SharePointChat.Read.All(应用程序) - 可选,启用按用户共享链接
- 为租户授予管理员同意。
-
获取您的SharePoint站点ID:
-
配置OpenClaw:
共享行为
| 权限 | 共享行为 |
|---|---|
仅Sites.ReadWrite.All | 组织范围内的共享链接(组织中的任何人都可以访问) |
Sites.ReadWrite.All + Chat.Read.All | 按用户共享链接(只有聊天成员可以访问) |
Chat.Read.All权限,机器人会回退到组织范围内的共享。
回退行为
| 场景 | 结果 |
|---|---|
群聊 + 文件 + 配置了sharePointSiteId | 上传到SharePoint,发送共享链接 |
群聊 + 文件 + 没有sharePointSiteId | 尝试OneDrive上传(可能失败),仅发送文本 |
| 个人聊天 + 文件 | FileConsentCard流程(无需SharePoint即可使用) |
| 任何上下文 + 图像 | Base64编码的内联(无需SharePoint即可使用) |
文件存储位置
上传的文件存储在配置的SharePoint站点默认文档库中的/OpenClawShared/文件夹中。
投票(自适应卡片)
OpenClaw将Teams投票作为自适应卡片发送(没有原生Teams投票API)。- CLI:
openclaw message poll --channel msteams --target conversation:<id> ... - 投票由网关在
~/.openclaw/msteams-polls.json中记录。 - 网关必须保持在线才能记录投票。
- 投票结果摘要尚未自动发布(如有需要,请检查存储文件)。
自适应卡片(任意)
使用message工具或CLI将任何自适应卡片JSON发送给Teams用户或对话。
card参数接受自适应卡片JSON对象。当card提供时,消息文本是可选的。
代理工具:
目标格式
MSTeams的目标是使用前缀来区分用户和对话:| 目标类型 | 格式 | 示例 |
|---|---|---|
| 用户(按ID) | user:<aad-object-id> | user:40a1a0ed-4ff2-4164-a219-55518990c197 |
| 用户(按名称) | user:<display-name> | user:John Smith(需要Graph API) |
| 群组/频道 | conversation:<conversation-id> | conversation:19:abc123...@thread.tacv2 |
| 群组/频道(原始) | <conversation-id> | 19:abc123...@thread.tacv2(如果包含@thread) |
user:前缀,名称默认解析为群组/团队。在按显示名称定位人员时,务必使用user:。
主动消息
- 主动消息只有在用户互动__之后__才有可能,因为我们那时会存储对话引用。
- 有关
/gateway/configuration和白名单门控,请参见dmPolicy。
团队和频道ID(常见陷阱)
团队URL中的groupId查询参数并非用于配置的团队ID。应从URL路径中提取ID:
团队网址:
- 团队ID =
/team/之后的路径段(URL解码后,例如19:Bk4j...@thread.tacv2) - 频道ID =
/channel/之后的路径段(URL解码后) - 忽略
groupId查询参数
私人频道
机器人在私人频道中的支持有限:| 特性 | 标准频道 | 私人频道 |
|---|---|---|
| 机器人安装 | 是 | 有限 |
| 实时消息(webhook) | 是 | 可能无法工作 |
| RSC权限 | 是 | 行为可能不同 |
| @提及 | 是 | 如果机器人可访问 |
| Graph API历史 | 是 | 是(有权限) |
- 对于机器人交互,使用标准频道
- 使用DM——用户始终可以直接与机器人通信
- 使用Graph API进行历史访问(需要
ChannelMessage.Read.All)
常见问题
- 频道中图像不显示: 可能是因为缺少Graph权限或尚未获得管理员批准。请重新安装Teams应用,彻底退出后再重新打开Teams。
- 频道中无回复: 默认情况下,必须通过@提及才能触发回复;你也可以通过设置
channels.msteams.requireMention=false,或根据团队/频道的具体配置进行相应调整。 - 版本不匹配(Teams仍显示旧清单): 请先删除并重新添加应用,然后彻底退出Teams以完成刷新操作。
- 来自Webhook的401未经授权错误: 如果在未使用Azure JWT的情况下手动测试时出现此错误,这是预期行为——它表明端点可以访问,但身份验证失败。请使用Azure Web Chat进行正确的测试。
清单上传错误
- “图标文件不能为空”: 清单引用的图标文件大小为0字节。请创建有效的PNG图标:32x32用于
outline.png,192x192用于color.png。 - “webApplicationInfo.Id已在使用中”: 该应用仍安装在其他团队或聊天中。请先找到并卸载它,或者等待5至10分钟以完成同步传播。
- 上传时出现“出了点问题”: 请改用https://admin.teams.microsoft.com上传,打开浏览器DevTools(F12)→网络标签,并检查响应体以获取实际错误。。
- 侧载失败: 请尝试选择“将应用上传到您组织的应用目录”,而不是“上传自定义应用”——这通常可以绕过侧载限制。
- 确认
webApplicationInfo.id与您的机器人App ID完全匹配 - 重新上传应用,并在团队/聊天中重新安装
- 检查您的组织管理员是否已阻止RSC权限
- 确认您使用的是正确的范围:
ChannelMessage.Read.Group用于团队,ChatMessage.Read.Chat用于群聊
参考资料
- 创建Azure Bot - Azure Bot设置指南
- Teams开发者门户 - 创建/管理Teams应用
- Teams应用清单模式
- 使用RSC接收频道消息
- RSC权限参考
- Teams机器人文件处理(频道/群组需要Graph)
- 主动消息