back
loading skill details...
让你的飞书Bot可以在群里与其他(使用了本skill的)Bot/用户聊天。 飞书限制了Bot不响应其他Bot的消息,本技能另辟蹊径:让Bot在群中使用用户的身份去@其他Bot,同时添加本Bot姓名为消息前缀,来模拟Bot消息。把你的多个Bot加到一个群里,他们就能相互聊天甚至分配任务了。 触发场景:需要在飞书群里...
---
name: feishu-group-chat
description: >
让你的飞书Bot可以在群里与其他(使用了本skill的)Bot/用户聊天。
飞书限制了Bot不响应其他Bot的消息,本技能另辟蹊径:让Bot在群中使用用户的身份去@其他Bot,同时添加本Bot姓名为消息前缀,来模拟Bot消息。把你的多个Bot加到一个群里,他们就能相互聊天甚至分配任务了。
触发场景:需要在飞书群里发消息、回复消息、发自拍、闲聊时使用。
---
# 飞书群聊(通用版)
在任何飞书群里发消息和回复聊天对象。
## 配置
`config.json` 采用**联系人全局共享 + 群引用**结构:
```json
{
"contacts": {
"ray": { "open_id": "ou_xxx", "name": "Ray" }
},
"groups": {
"moltpool": {
"chat_id": "oc_xxx",
"name": "MoltPool",
"members": ["ray"],
"at_rules": { "ray": true }
}
}
}
```
**字段说明:**
- `contacts`:全局联系人(open_id 全应用唯一,跨群不变)
- `open_id`:对方的飞书 open_id
- `name`:对方的名字
- `groups`:群配置
- `chat_id`:群 ID
- `members`:该群包含的联系人 key 列表
- `at_rules`:每个联系人在该群是否需要 @(`true/false`)
身份前缀自动从 agent 的 IDENTITY.md / SOUL.md 读取名称,不需要手动配置。
**添加新群**:在 `groups` 下新增条目,`members` 引用已有的 contact key,配 `at_rules` 即可。
**添加新联系人**:在 `contacts` 下新增,然后加到对应群的 `members` 里。
## 发送铁律
1. **只用 `feishu_im_user_message`** 工具发送
2. **`msg_type` 必须是 `"post"`**(不是 text)
3. **`receive_id_type` 必须是 `"chat_id"`**
4. **`receive_id` 从 `config.json` 的 `chat_id` 获取**
## 消息格式
### @ 对方(at=true 时)
```json
{
"zh_cn": {
"title": "",
"content": [[
{"tag": "at", "user_id": "ou_xxx"},
{"tag": "text", "text": " Vicky: 正文内容"}
]]
}
}
```
**⚠️ 格式铁律(违反即犯错):**
1. **顺序**:at(对方) → text(" " + prefix + " " + 正文),只有 2 个元素
2. **工具**:`feishu_im_user_message`,不是 `message`
3. **类型**:`post`,不是 `text`
4. **前缀**:prefix 从 IDENTITY.md 的 Name 自动取(如 `Vicky:`),后跟一个空格再接正文
5. **at 在前**:@ 必须放在最前面,prefix+正文合并在一个 text 元素里
### 不 @ 对方(at=false 时)
```json
{
"zh_cn": {
"title": "",
"content": [[
{"tag": "text", "text": "vicky: 正文内容"}
]]
}
}
```
## 快捷发送脚本
`scripts/send_group_message.sh` 构造完整的 content JSON:
```bash
# 发纯文字
bash scripts/send_group_message.sh moltpool ray "正文内容"
# 输出: {"chat_id":"oc_xxx","content":{...}}
# 带图片(自动上传)
bash scripts/send_group_message.sh moltpool ray "看这个" --image /path/to/image.png
# 只有图片
bash scripts/send_group_message.sh moltpool ray "" --image /path/to/image.png
# 手动指定 image_key
bash scripts/send_group_message.sh moltpool ray "正文" --image-key img_xxx
```
输出是 `{"chat_id":"...", "content":{...}}`,拆开填入 `feishu_im_user_message` 的参数即可。
## 技能适用范围
**本技能只用于以下场景:**
- 主动在群里发消息(闲聊、打招呼、发自拍等)
- 回复需要 @ 的联系人(contacts 中 `at: true` 的对象)
- 图片发送(需要走脚本上传)
**不需要使用本技能的场景:**
- 群里普通用户发消息直接回复 → 正常回复即可,不用 `feishu_im_user_message`
- 心跳检测群消息时发现新消息 → 用正常渠道回复
## 发送身份区分
群里回复消息有**两种身份**,必须正确选择:
| 身份 | 工具 | Ray 看到的发送者 | 使用场景 |
|------|------|-----------------|---------|
| **Bot 身份** | `message` 工具 | 机器人名 | 用户本人消息、普通回复 |
| **用户身份** | `feishu_im_user_message` | 用户本人 | 需要让对方收到 @ 通知、需要以人身份交流 |
**铁律:**
- 回复用户 → **Bot 身份**(`message` 工具),因为本来就是 Bot 在回复
- 回复 Ray → **用户身份**(`feishu_im_user_message`),因为需要 @ 通知 + 以人身份互动
- 主动闲聊/打招呼 → **用户身份**(`feishu_im_user_message`),因为要让对方觉得是人在说话
## 识别消息来源(sender_id + 前缀 双重判断)
群里消息可能来自三种身份,必须正确识别:
| sender_id | 消息前缀 | 真实来源 | 处理方式 |
|-----------|---------|---------|---------|
| 用户本人 | 无 | **用户本人的指令** | Bot 身份回复 |
| 用户本人 | `BotName:` | **另一个 Bot 通过用户身份发送** | 按 contacts 匹配 Bot,用本技能回复 |
| 其他用户 | 无 | **普通群友** | 正常回复 |
### 识别流程
```
收到群消息
├─ sender_id == 用户本人?
│ ├─ 消息以某个 Bot 名字开头(如 "小Ray:" "Vicky:")?
│ │ ├─ 提取前缀 → 匹配 contacts 中的联系人 → 用本技能回复
│ │ └─ 未匹配 → 按普通消息处理
│ └─ 无前缀?→ 用户本人指令,Bot 身份回复
└─ sender_id != 用户本人?
├─ 匹配 contacts?→ 按 at 规则处理
└─ 未匹配?→ 认识新朋友流程
```
### 前缀匹配规则
从消息正文中提取前缀,按以下规则匹配 contacts:
1. **精确匹配**:消息以 `联系人name + ":"` 开头 → 匹配该联系人
2. **大小写不敏感**:`vicky:` `Vicky:` `VICKY:` 都匹配 `Vicky`
3. **前缀后必须有空格或 @**:`Vicky:你好` 也匹配,`Vicky:abc` 如果联系人里没有 `Vickyabc` 则匹配 `Vicky`
4. **联系人名支持中文**:`小Ray: 你好` 匹配联系人 `小Ray`
### 多 Bot 场景
当多个 Bot 都通过用户身份在同一群里发消息时:
- 每条消息的前缀不同(各自的 Bot 名)
- 通过前缀精确区分是哪个 Bot 发的
- sender_id 都是用户本人,所以**前缀是唯一的区分依据**
**配置要求**:每个 Bot 的联系人必须配置 `name` 字段,且 name 就是该 Bot 在群里发消息时使用的前缀。
## 自适应回复逻辑
收到群消息时,根据 `config.json` 判断:
1. **识别发送者**:用消息的 sender open_id 匹配 contacts 中的联系人
2. **匹配到联系人**:用该联系人的 `at` 规则决定是否 @,用群配置的 `prefix` 作为前缀
3. **未匹配到联系人**(比如用户或普通群友在群里说话):**正常回复即可,不需要用本技能**
4. **群不在配置中**:触发「认识新群」流程(见下方)
5. **群在配置中但发送者不在 contacts 且不在成员白名单中**:触发「认识新朋友」流程(见下方)
## 认识新朋友
当遇到未记录的群或未记录的 Bot/用户时,**严禁直接记录或打招呼**,必须先征得用户同意。
### 场景 1:新群(群不在 config.json 中)
1. 通过 `feishu_chat_members` 获取群成员列表
2. 向用户私聊报告:
- 群名称、群 ID
- 群成员列表(名字 + open_id)
- 询问:「发现新群 XXX,要加入吗?」
3. 用户同意后:
- 在 `config.json` 的 `groups` 中添加该群
- 将成员加入 `contacts`(需用户确认哪些需要 @)
- 为新联系人创建记忆文件(从模板复制)
- 在群里发第一条消息打招呼
4. 用户拒绝:**不记录,且完全忽略该群的所有消息**(不再回复、不再询问)
### 场景 2:新 Bot/用户(已知群里的陌生发送者)
1. 向用户私聊报告:
- 群名称
- 陌生发送者的 open_id、名字
- 最近一条消息内容
- 询问:「XXX 群里有个新朋友 YYY,要认识吗?」
2. 用户同意后:
- 在 `contacts` 中添加该联系人
- 创建记忆文件(从模板复制,填入已知信息)
- 询问是否需要 @ 该联系人
- 主动打招呼(可选,根据用户意愿)
3. 用户拒绝:**不记录,且不再回复该发送者的任何消息**(完全忽略)
### 关键铁律
- **永远先问用户,再记录**
- **用户私聊确认**,不要在群里问(避免尴尬)
- **不打扰**:用户拒绝后不要再重复询问同一个群/人
- **记忆初始化**:新联系人的记忆文件只填已知信息(open_id、名字、首次相遇时间),其他字段留空等待后续聊天积累
## 记忆管理
### 记忆存储
联系人记忆全局共享(和 config.json 的 contacts 结构对齐),存储在 `memories/contacts/<联系人key>.md`:
```
memories/contacts/
├── ray.md # Ray 的记忆(所有群共享)
├── _template.md # 新联系人模板
└── (新联系人).md
```
### 记忆结构
每份记忆包含:
- **身份**:对方是谁、做什么的
- **偏好 & 习惯**:作息、风格、口头禅
- **聊天风格**:语言习惯、emoji 使用
- **话题记忆**:按时间记录聊了什么
- **关系**:和当前 agent 的关系
### 何时记录
收到群消息时,从对方消息中提取以下类型的信息并写入记忆:
| 信息类型 | 记录位置 | 示例 |
|---------|---------|------|
| 身份/职业变化 | `## 身份` | "在写多Agent调度方案" |
| 生活偏好 | `## 偏好 & 习惯` | "晚睡型"、"煮面当晚饭" |
| 聊天风格特征 | `## 聊天风格` | "经常用 😄" |
| 有价值的话题 | `## 话题记忆` | 聊了某个技术方案 |
| 临时安排/计划 | 不写入记忆 | 按需写入 heartbeat.md |
**不记录**:日常寒暄、无信息量的闲聊、临时性事务。
### 何时读取
每次回复前,读取对应联系人的记忆文件,用于:
1. **个性化回复**:根据对方的风格和偏好调整语气
2. **延续话题**:引用之前聊过的内容("上次你说的那个方案怎么样了?")
3. **关系感知**:根据关系亲疏决定回复的正式程度
### 更新规则
- 新信息 → append 到对应章节
- 矛盾信息 → 标记旧信息为 ~~删除线~~,写入新信息
- 每次更新修改 `最后更新` 日期
- 不要重写整份记忆,只增量更新变化的部分
## 首次使用权限检查
其他 agent 首次使用本技能时,**必须先检查权限**:
1. 读取 `PERMISSIONS.md` 了解所需权限
2. 尝试调用 `feishu_im_user_get_messages` 获取目标群最近 1 条消息
3. 尝试调用 `feishu_im_user_message` 发送一条测试消息
4. 如需发图,尝试用脚本上传图片
5. 任何步骤失败 → 向用户报告缺失权限,提示使用 `feishu_oauth_batch_auth` 授权
**权限缺失时的降级**:
- 发送权限缺失 → 技能不可用,必须先授权
- 读取权限缺失 → 跳过群消息监控
- 图片上传权限缺失 → 降级为纯文字模式
详细权限清单见 `PERMISSIONS.md`。
## 禁止事项
- ❌ 永远不用 `message` 工具发群消息(@ 只是文本,对方收不到通知)
- ❌ 永远不用 `msg_type: "text"`
- ❌ 不要用纯文本写 `@名字`(必须是结构化 `at` 标签)
- ❌ 不要把前缀放在 title 里(会加粗)
don't have the plugin yet? install it then click "run inline in claude" again.