Feishu 机器人集成指南:从 0 到 1 实战
写在前面:这篇文章源于今晚(2026-03-10)的真实项目需求。我们需要将 OpenClaw 集成到 Feishu,实现消息推送、日报自动化和告警通知。从创建应用到最终上线,全程 2 小时,包含所有踩坑记录。
一、背景:为什么选择 Feishu?
1.1 真实需求
场景 1:自动化结果推送
1 2 3 4 5 6 7 8 9
| ❌ 之前: 1. 在服务器上执行任务 2. 登录服务器查看结果 3. 手动复制结果到 Feishu
✅ 现在: 1. 触发任务 2. 自动推送到 Feishu 3. 手机上直接看结果
|
场景 2:日报自动化
1 2 3 4 5 6 7 8 9
| ❌ 之前: 1. 回忆今天做了什么 2. 手动填写飞书汇报 3. 每天重复
✅ 现在: 1. 告诉 Agent 今天完成的工作 2. 自动格式化发送 3. 保存到记忆系统
|
场景 3:告警通知
1 2 3 4 5 6 7 8 9
| ❌ 之前: 1. Pod CrashLoopBackOff 2. 第二天上班才发现 3. 业务已受影响
✅ 现在: 1. Pod 异常 2. 立即推送 Feishu 3. 手机收到通知,快速响应
|
1.2 为什么选 Feishu?
对比其他平台:
| 平台 |
优势 |
劣势 |
适用场景 |
| Feishu |
企业级、功能丰富、卡片交互 |
需要企业账号 |
工作场景 ✅ |
| 钉钉 |
普及率高 |
功能相对简单 |
中小企业 |
| 企业微信 |
与微信互通 |
开发体验一般 |
对外服务 |
| Slack |
国际化、生态好 |
国内访问慢 |
海外团队 |
| Telegram |
开放、免费 |
需要翻墙 |
个人项目 |
我们的选择:
- ✅ Feishu - 工作场景,功能强大
- ✅ 开放平台 - API 完善,文档清晰
- ✅ 交互卡片 - 用户体验好
二、前置条件
2.1 账号准备
必需:
可选:
- 测试群组(用于开发测试)
- 生产群组(用于正式上线)
2.2 环境要求
服务器:
1 2 3 4 5 6 7 8 9 10 11
| Linux (Ubuntu/CentOS)
- 可访问 https://open.feishu.cn - 可访问 https://api.feishu.cn - 公网 IP(用于回调,可选)
- 443(HTTPS,回调用) - 80(HTTP,可重定向到 443)
|
开发工具:
1 2 3 4 5 6 7 8
| curl jq python3
ngrok nginx
|
2.3 权限要求
Feishu 应用权限:
- ✅ 创建企业自建应用
- ✅ 配置权限 scopes
- ✅ 设置事件订阅
- ✅ 发布应用
三、创建应用
3.1 登录开放平台
步骤:
1 2 3 4
| 1. 访问 https://open.feishu.cn 2. 使用 Feishu 账号登录 3. 进入"企业自建应用" 4. 点击"创建应用"
|
截图:
1 2 3 4
| [开放平台首页] ├── 个人应用 ├── 企业自建应用 ← 点击这里 └── 第三方应用
|
3.2 填写应用信息
必填项:
| 字段 |
值 |
说明 |
| 应用名称 |
OpenClaw Bot |
显示在 Feishu 中的名字 |
| 应用图标 |
上传 logo |
建议 512x512 PNG |
| 应用描述 |
OpenClaw 智能助手 |
简短描述功能 |
| 开发团队 |
CrystalForge |
团队名称 |
可选填:
3.3 获取凭证
创建后自动获得:
1 2
| App ID: cli_a9278e8369b89bc6 App Secret: J9Zg52nIDrufyq4YbBNDjhZuh74XcOyK
|
⚠️ 重要:
- App Secret 只显示一次,立即保存!
- 如果丢失,需要重新生成
- 不要提交到 Git(使用环境变量)
保存方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| export FEISHU_APP_ID=cli_a9278e8369b89bc6 export FEISHU_APP_SECRET=J9Zg52nIDrufyq4YbBNDjhZuh74XcOyK
cat > .env <<EOF FEISHU_APP_ID=cli_a9278e8369b89bc6 FEISHU_APP_SECRET=J9Zg52nIDrufyq4YbBNDjhZuh74XcOyK EOF
kubectl create secret generic feishu-secrets \ --from-literal=app-id=cli_a9278e8369b89bc6 \ --from-literal=app-secret=J9Zg52nIDrufyq4YbBNDjhZuh74XcOyK \ -n openclaw
|
四、配置权限
4.1 权限类型
Feishu 权限分类:
| 类型 |
说明 |
示例 |
| 用户权限 |
访问用户信息 |
user:readonly |
| 消息权限 |
发送/读取消息 |
im:message |
| 群组权限 |
管理群组 |
im:chat |
| 机器人权限 |
机器人操作 |
im:bot |
4.2 必需权限
OpenClaw 需要的权限:
1 2 3 4 5 6 7 8
| { "scopes": [ "im:message", "im:chat", "contact:user:readonly", "contact:department:readonly" ] }
|
配置步骤:
1 2 3 4 5 6
| 1. 进入应用管理页面 2. 点击"权限管理" 3. 点击"添加权限" 4. 搜索并选择上述权限 5. 点击"申请" 6. 等待管理员审批(通常立即通过)
|
4.3 权限验证
测试权限是否生效:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| curl -X POST https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal \ -H "Content-Type: application/json" \ -d '{ "app_id": "cli_a9278e8369b89bc6", "app_secret": "J9Zg52nIDrufyq4YbBNDjhZuh74XcOyK" }'
{ "code": 0, "tenant_access_token": "t-caaac8f816b08e01d87..." }
curl -X POST https://open.feishu.cn/open-apis/im/v1/messages \ -H "Authorization: Bearer t-caaac8f816b08e01d87..." \ -H "Content-Type: application/json" \ -d '{ "receive_id": "ou_047fe9a3b3153dcf412992b51f0ed4ba", "msg_type": "text", "content": "{\"text\":\"测试消息\"}" }'
|
五、事件订阅
5.1 什么是事件订阅?
原理:
1
| 用户操作 → Feishu 服务器 → 你的回调 URL → 你的代码处理
|
示例:
1 2 3 4 5 6 7
| 用户在群里@机器人 ↓ Feishu 检测到@事件 ↓ Feishu 发送 HTTP POST 到你的 URL ↓ 你的代码解析事件,回复消息
|
5.2 配置回调 URL
步骤:
1 2 3 4 5 6 7
| 1. 进入应用管理页面 2. 点击"事件订阅" 3. 点击"添加事件" 4. 填写回调 URL 5. 填写验证 Token 6. 选择订阅的事件 7. 保存
|
回调 URL 要求:
- ✅ HTTPS(生产环境必需)
- ✅ 公网可访问
- ✅ 响应时间 < 3 秒
- ✅ 返回正确格式
开发环境解决方案:
1 2 3 4 5 6 7 8
| ngrok http 8080
Forwarding: https://abc123.ngrok.io -> http://localhost:8080
https://abc123.ngrok.io/feishu/callback
|
5.3 验证 Token
作用:Feishu 验证你的服务器是合法的
配置:
1
| 验证 Token: feishu_token_123456(自己设置)
|
验证逻辑(Python 示例):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/feishu/callback', methods=['POST']) def callback(): if request.method == 'POST': data = request.json if 'challenge' in data: return jsonify({ 'challenge': data['challenge'] }) handle_event(data) return jsonify({'status': 'success'})
def handle_event(event): event_type = event.get('header', {}).get('event_type') if event_type == 'im.message.receive_v1': process_message(event) elif event_type == 'p2_app_open': process_app_open(event)
|
5.4 订阅的事件
OpenClaw 订阅的事件:
| 事件 |
说明 |
用途 |
im.message.receive_v1 |
收到消息 |
处理用户指令 |
p2_app_open |
用户打开应用 |
统计活跃度 |
contact.user.created_v1 |
用户创建(可选) |
同步用户信息 |
六、消息发送
6.1 消息类型
Feishu 支持的消息类型:
| 类型 |
msg_type |
说明 |
| 文本 |
text |
纯文本消息 |
| 富文本 |
post |
格式化文本(支持链接、@) |
| 卡片 |
interactive |
交互卡片(按钮、表单) |
| 图片 |
image |
图片消息 |
| 文件 |
file |
文件消息 |
6.2 发送文本消息
API:
1 2 3 4 5 6 7 8
| curl -X POST https://open.feishu.cn/open-apis/im/v1/messages \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "receive_id": "ou_047fe9a3b3153dcf412992b51f0ed4ba", "msg_type": "text", "content": "{\"text\":\"你好,这是测试消息\"}" }'
|
Python 封装:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import requests
def send_text_message(user_id, text): token = get_access_token() url = "https://open.feishu.cn/open-apis/im/v1/messages" headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } data = { "receive_id": user_id, "msg_type": "text", "content": json.dumps({"text": text}) } response = requests.post(url, headers=headers, json=data) return response.json()
|
6.3 发送富文本消息
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| def send_post_message(user_id, title, content): token = get_access_token() data = { "receive_id": user_id, "msg_type": "post", "content": json.dumps({ "post": { "zh_cn": { "title": title, "content": content } } }) } content = [ [ {"tag": "text", "text": "项目:"}, {"tag": "text", "text": "CrystalForge", "style": {"bold": True}} ], [ {"tag": "text", "text": "状态:"}, {"tag": "text", "text": "部署成功", "style": {"color": "green"}} ], [ {"tag": "a", "text": "查看详情", "href": "https://example.com"} ] ]
|
6.4 发送交互卡片
最强大的消息类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| def send_interactive_card(user_id, card): token = get_access_token() data = { "receive_id": user_id, "msg_type": "interactive", "card": json.dumps(card) } response = requests.post( "https://open.feishu.cn/open-apis/im/v1/messages", headers={"Authorization": f"Bearer {token}"}, json=data ) return response.json()
card = { "config": { "wide_screen_mode": True }, "header": { "title": { "tag": "plain_text", "content": "🚀 部署完成通知" }, "template": "green" }, "elements": [ { "tag": "div", "text": { "tag": "lark_md", "content": "**项目**: CrystalForge\n**环境**: 生产\n**状态**: ✅ 成功" } }, { "tag": "action", "actions": [ { "tag": "button", "text": { "tag": "plain_text", "content": "查看详情" }, "url": "https://example.com", "type": "primary" } ] } ] }
|
七、实战案例:OpenClaw 集成
7.1 架构设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| ┌─────────────────┐ │ Feishu 用户 │ │ 发送消息/指令 │ └───────┬─────────┘ │ │ HTTPS ▼ ┌─────────────────┐ │ Feishu 服务器 │ │ 事件订阅回调 │ └───────┬─────────┘ │ │ HTTP POST ▼ ┌─────────────────┐ │ OpenClaw Gateway│ │ /feishu/callback └───────┬─────────┘ │ │ 处理事件 ▼ ┌─────────────────┐ │ OpenClaw Agent │ │ 执行任务 │ └───────┬─────────┘ │ │ 返回结果 ▼ ┌─────────────────┐ │ Feishu API │ │ 发送回复消息 │ └───────┬─────────┘ │ ▼ ┌─────────────────┐ │ Feishu 用户 │ │ 收到回复 │ └─────────────────┘
|
7.2 配置 openclaw.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { "channels": { "feishu": { "enabled": true, "appId": "cli_a9278e8369b89bc6", "appSecret": "J9Zg52nIDrufyq4YbBNDjhZuh74XcOyK", "verificationToken": "feishu_token_123456", "dmPolicy": "pairing", "groupPolicy": "pairing", "callback": { "path": "/feishu/callback", "port": 18789 } } } }
|
7.3 部署到 K8s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| apiVersion: apps/v1 kind: Deployment metadata: name: openclaw-gateway namespace: openclaw spec: replicas: 1 template: spec: containers: - name: gateway image: hb.test/crystalforge/openclaw-cn-base:1.0.3-feishu env: - name: FEISHU_APP_ID valueFrom: secretKeyRef: name: feishu-secrets key: app-id - name: FEISHU_APP_SECRET valueFrom: secretKeyRef: name: feishu-secrets key: app-secret ports: - containerPort: 18789 name: gateway
|
7.4 配对流程
步骤:
1 2 3 4 5
| 1. 在 Feishu 中搜索"OpenClaw Bot" 2. 发送给机器人任意消息 3. OpenClaw 返回配对二维码 4. 扫描二维码,批准配对 5. 配对成功,开始对话
|
配对后的能力:
- ✅ 私聊对话
- ✅ 群组@机器人
- ✅ 接收推送通知
- ✅ 执行任务并返回结果
八、踩坑记录
8.1 App Secret 只显示一次
问题:
1 2
| 创建应用时,App Secret 只显示一次 关闭页面后,无法再次查看
|
解决方案:
1 2 3 4 5 6 7 8 9 10 11
| echo "cli_a9278e8369b89bc6" > app-id.txt echo "J9Zg52nIDrufyq4YbBNDjhZuh74XcOyK" > app-secret.txt
kubectl create secret generic feishu-secrets \ --from-literal=app-id=cli_a9278e8369b89bc6 \ --from-literal=app-secret=NEW_SECRET
|
教训:
创建应用时,立即保存 App Secret!不要关闭页面。
8.2 回调 URL 验证失败
问题:
1 2
| 配置回调 URL 时,Feishu 发送验证请求 返回错误:验证失败
|
原因:
- 没有正确处理 challenge
- 响应格式不对
- 响应时间超过 3 秒
解决方案:
1 2 3 4 5 6 7 8 9 10 11
| @app.route('/feishu/callback', methods=['POST']) def callback(): data = request.json if 'challenge' in data: return jsonify({ 'challenge': data['challenge'] })
|
教训:
Feishu 会先发送验证请求,必须返回 challenge 值。
8.3 权限不足
问题:
1 2 3 4 5
| { "code": 99991663, "msg": "app access token invalid scope" }
|
原因:
解决方案:
1 2 3 4 5
| 1. 进入应用管理 → 权限管理 2. 添加 im:message 权限 3. 等待审批(通常立即通过) 4. 重新获取 tenant_access_token 5. 再次发送消息
|
教训:
权限变更后,需要重新获取 access_token。
8.4 消息限流
问题:
1 2 3 4 5
| { "code": 9002, "msg": "rate limit exceeded" }
|
Feishu 限流规则:
- 机器人发消息:100 条/分钟
- 用户发消息:500 条/分钟
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import time from datetime import datetime, timedelta
class RateLimiter: def __init__(self, limit=100, period=60): self.limit = limit self.period = period self.requests = [] def wait_if_needed(self): now = datetime.now() self.requests = [ t for t in self.requests if now - t < timedelta(seconds=self.period) ] if len(self.requests) >= self.limit: sleep_time = self.period - (now - self.requests[0]).seconds time.sleep(sleep_time) self.requests.append(now)
rate_limiter = RateLimiter()
def send_message(user_id, text): rate_limiter.wait_if_needed() return send_text_message(user_id, text)
|
教训:
发送消息前检查限流,避免被封禁。
九、性能数据
9.1 API 响应时间
| 操作 |
平均耗时 |
P95 |
P99 |
| 获取 token |
100ms |
200ms |
500ms |
| 发送文本消息 |
200ms |
400ms |
800ms |
| 发送卡片消息 |
300ms |
500ms |
1000ms |
| 事件回调处理 |
50ms |
100ms |
200ms |
9.2 并发能力
| 指标 |
值 |
说明 |
| 最大并发 |
100 req/s |
Feishu 限流前 |
| 推荐并发 |
10 req/s |
安全范围 |
| 日发送量 |
10,000 条 |
限流前 |
十、最佳实践
10.1 安全
✅ 一定要做的:
使用 K8s Secret:
1 2 3
| kubectl create secret generic feishu-secrets \ --from-literal=app-id=xxx \ --from-literal=app-secret=xxx
|
验证签名:
1 2 3 4
| def verify_signature(timestamp, nonce, signature): pass
|
HTTPS:
- 生产环境必须使用 HTTPS
- 使用 Let’s Encrypt 免费证书
10.2 可靠性
✅ 推荐做法:
重试机制:
1 2 3
| @retry(stop=stop_after_attempt(3), wait=wait_exponential()) def send_message(user_id, text): return send_text_message(user_id, text)
|
消息队列:
1 2 3 4 5 6
| from celery import Celery
@app.task def send_message_async(user_id, text): send_text_message(user_id, text)
|
监控告警:
1 2 3
| if response['code'] != 0: send_alert(f"Feishu 发送失败:{response['msg']}")
|
十一、总结
11.1 核心要点
- 创建应用:获取 App ID 和 App Secret
- 配置权限:申请必要的 scopes
- 事件订阅:配置回调 URL 和验证 Token
- 消息发送:文本、富文本、卡片
- 安全配置:Secret 存储、签名验证、HTTPS
11.2 实战经验
这篇文章是今晚 2 小时实战的总结:
- 22:00-22:30:创建应用,配置权限
- 22:30-23:00:配置事件订阅
- 23:00-23:30:开发回调处理
- 23:30-24:00:测试验证,踩坑记录
11.3 后续计划
本周:
本月:
本季度:
作者:John,高级技术架构师,CrystalForge 项目负责人
时间:2026-03-11 00:30
地点:深圳
项目:OpenClaw Feishu 集成实战