跳到主内容
快讯直播
AI智模界
教程

把团队 Agent 拉进飞书群:用豆包工作搭群聊协作智能体

这篇能做出什么

做完之后,你的飞书项目群里会多一个机器人。同事在群里 @ 它,它会:

  • 接得住问题:基于你上传的项目文档、排期表、规范手册回答,答不上来会直说"不确定",而不是编。
  • 分得清任务:有人说"这活儿谁接",它输出一张"任务 / 负责人 / 建议时间 / 验收标准"的表格,并 @ 到具体的人。
  • 记得住上下文:同一群里前 20 条对话它都看得见,@ 它说"就按刚才说的改",它知道"刚才"指什么。
  • 扛得住多人并发:5 个人同时跟它说话不会串台,A 问的问题不会回到 B 头上。
  • 收得到口子:每天固定时间在群里汇总当天结论、待办和风险。

整条链路是这样的:

```

飞书群消息 → 飞书事件回调 → 你的中转服务 → 豆包工作智能体 → 回到飞书群

```

路径有两种。如果豆包工作后台提供了飞书渠道/连接器,可以直接授权绑定,零代码;如果没有或你想自己控上下文、控权限,就走下面的中转服务方案。具体是否提供飞书渠道、叫什么名字,以豆包工作官方页面为准。

---

前置条件清单

开工前把这 6 项对齐,能省掉后面 80% 的排查时间:

1. 飞书侧权限:能创建"企业自建应用"的账号,或者能找到能帮你审批的管理员。机器人发版、加权限通常需要管理员过一遍。

2. 豆包工作侧:能创建智能体的账号,以及调用它所需的凭据(API Key / 应用 ID 之类,名称以官方页面为准)。

3. 一台能跑服务的地方:Node.js 18 以上的环境即可,本地电脑 + 内网穿透也能先跑通。

4. 一个公网可访问地址(走 webhook 模式时需要);飞书也有长连接模式,可以免公网 IP,推荐先用长连接把链路跑通。

5. 一张"能力清单":这个 Agent 服务的群里,谁是负责人、要有哪些技能、哪些知识库能读、哪些数据不能碰。

6. 一份输出规范:群聊消息和文档不一样,超过 200 字就没人看了。先把格式规则定下来。

---

第 0 步:先想清楚"群里的 Agent 到底干什么"

这一步不写代码,但决定后面好不好用。把 Agent 的职责收敛成三类,别贪多:

职责触发场景输出形态
应答有人问项目背景、规范、排期一句话结论 + 引用来源
分派有人问"谁来做"表格 + @ 具体人
汇总定时触发或有人说"总结一下"结论 / 待办 / 风险 三段

为什么必须收敛? 一个什么都干的 Agent 最后什么都干不好。群里最常见的失败不是模型不行,是它每次回 800 字,两轮之后没人再 @ 它了。

---

第 1 步:在豆包工作里创建并调试智能体

1.1 建智能体、写人设

在豆包工作的智能体创建入口新建一个,把人设和指令写清楚。下面这段可以直接改成你的版本:

```markdown

你是「项目小助」,服务对象是 XX 项目群的 8 位同事。

【职责】

1. 应答:回答项目背景、排期、规范类问题,优先引用知识库;知识库里没有的,明说"我查不到"。

2. 分派:当有人问"这个谁来做",输出表格:任务 | 负责人 | 建议时间 | 验收标准,并 @ 对应的人。

3. 汇总:收到"总结一下"时,输出三段:今天结论 / 待办 / 风险。

【硬性规则】

  • 结论先行:第一句话就是答案,理由放后面。
  • 群消息不超过 200 字,需要展开时输出"回复:详情"。
  • 不确定就说不确定。禁止编造人名、日期、数字、链接。
  • 只给建议时间,不承诺交付时间。
  • 与项目无关的闲聊,回一句"这块我不熟"就结束。

```

1.2 挂知识库

把项目文档、排期表、规范手册传进知识库。两个小技巧:

  • 给文档起人话名字。叫"XX项目-2024Q3排期"比叫"文档1"更容易被正确召回。
  • 删掉过期文档。知识库里躺着三份不同版本的排期,Agent 就会开始"编"。

1.3 在调试台自测四种场景

  • 问一个知识库里明确有的问题 → 看它引不引用来源。
  • 问一个完全不相关的问题 → 看它拒答还是硬编。
  • 说"这个谁来做" → 看它输出表格还是输出散文。
  • 故意问一个模糊问题 → 看它反问还是瞎猜。

1.4 拿到调用凭据

在平台的应用管理或 API 页面拿到 Key 和调用端点。字段名、鉴权方式、是否有会话(session)参数,一律以豆包工作官方文档为准。 拿到后先存进环境变量,别写在代码里。

---

第 2 步:在飞书开放平台创建机器人

2.1 创建企业自建应用

在飞书开放平台创建"企业自建应用",进去后开启机器人能力。开启后你会得到 App IDApp Secret,这两个是用来换 tenant_access_token 的。

2.2 配权限

需要几类权限,名称以官方文档为准,大致覆盖:

  • 接收群聊中 @ 机器人的消息
  • 以机器人身份发送消息
  • 读取群信息(知道群里有哪些人)

关键点:默认情况下机器人只能收到 @ 它的消息。想读全部群消息要单独申请,且通常需要审核。绝大多数团队协作场景,只收 @ 消息就够了,也更省心。

2.3 订事件

订阅消息接收事件(消息事件名大致是 im.message.receive_v1 这类,以官方文档为准)。接收方式选长连接或 webhook 均可。

2.4 发布版本,把机器人拉进群

改完权限一定要重新发布版本并等审核通过——权限变更不重新发版是不生效的,这是新手最常踩的坑。

发完版,在群里"设置 → 群机器人 → 添加机器人",把它拉进来。想让它认识群成员,可以提前把成员的 open_id 和姓名建一张映射表。

---

第 3 步:写一个最小可用的中转服务

先跑通"收到 @ → 回一句话"这条最短链路,别急着做卡片和定时任务。

```javascript

// server.js —— 最小可用的飞书中转服务

const express = require('express');

const app = express();

app.use(express.json());

// 已处理的事件 id,防止飞书重试导致重复回复

const handledEvents = new Set();

// 简易会话记忆:chatId -> [{ role, content }]

const sessions = new Map();

app.post('/feishu/events', (req, res) => {

const body = req.body || {};

// 1) 事件订阅地址校验:按官方文档要求把 challenge 原样返回

if (body.type === 'url_verification') {

return res.json({ challenge: body.challenge });

}

const eventId = body.header && body.header.event_id;

// 2) 幂等:同一个事件只处理一次

if (!eventId || handledEvents.has(eventId)) {

return res.json({ code: 0 });

}

handledEvents.add(eventId);

// 3) 先 ACK 再异步处理,避免回调超时被重试

res.json({ code: 0 });

handleMessage(body.event).catch((err) =>

console.error('handleMessage failed', err)

);

});

app.listen(process.env.PORT || 3000, () => {

console.log('listening');

});

```

```javascript

// agent.js —— 把群消息转给豆包工作智能体,再把回答发回群里

async function handleMessage(event) {

const msg = event && event.message;

if (!msg || msg.message_type !== 'text') return;

const chatId = msg.chat_id;

const openId = event.sender && event.sender.sender_id

? event.sender.sender_id.open_id

: '';

// 去掉 @机器人 的占位符,拿到真正的问题

const rawText = JSON.parse(msg.content || '{}').text || '';

const cleanText = rawText.replace(/@\S+/g, '').trim();

if (!cleanText) return;

// 把 open_id 换成人名,Agent 才知道"谁在说话"

const speaker = nameByOpenId[openId] || '某位同事';

const reply = await callDoubaoAgent({

sessionId: feishu:${chatId}, // 同群共用一段上下文

userText: 【${speaker}】${cleanText},

history: sessions.get(chatId) || [],

});

// 把本轮对话写回记忆,供下一轮使用

const history = sessions.get(chatId) || [];

history.push({ role: 'user', content: cleanText });

history.push({ role: 'assistant', content: reply });

sessions.set(chatId, history.slice(-20)); // 只保留最近 20 条

await sendToFeishu(chatId, reply);

}

```

```javascript

// doubao.js —— 调用豆包工作智能体

// 端点、字段名、鉴权头请以豆包工作官方文档为准

async function callDoubaoAgent({ sessionId, userText, history }) {

const resp = await fetch(${process.env.DOUBAO_BASE_URL}/your-agent-endpoint, {

method: 'POST',

headers: {

'Content-Type': 'application/json',

Authorization: Bearer ${process.env.DOUBAO_API_KEY},

},

body: JSON.stringify({

session_id: sessionId,

input: userText,

history: history, // 若平台自带会话记忆,这个字段可以去掉

}),

});

if (!resp.ok) {

console.error('agent error', resp.status, await resp.text());

return '我这边暂时连不上,稍后再试一次。';

}

const data = await resp.json();

return data.output_text || '我没拿到结果,换个说法再问我一次。';

}

```

```javascript

// feishu.js —— 拿 token、发消息

async function getTenantAI 词典:Token">Token() {

const resp = await fetch(

'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',

{

method: 'POST',

headers: { 'Content-Type': 'application/json' },

body: JSON.stringify({

app_id: process.env.FEISHU_APP_ID,

app_secret: process.env.FEISHU_APP_SECRET,

}),

}

);

return resp.json(); // { tenant_access_token, expire }

}

// 生产环境把 token 缓存起来,别每条消息都换一次

async function sendToFeishu(chatId, text) {

const { tenant_access_token } = await getTenantToken();

await fetch(

'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id',

{

method: 'POST',

headers: {

'Content-Type': 'application/json; charset=utf-8',

Authorization: Bearer ${tenant_access_token},

},

body: JSON.stringify({

receive_id: chatId,

msg_type: 'text',

content: JSON.stringify({ text }),

}),

}

);

}

```

跑起来,在群里 @ 一下,收到回复就算通了。

---

第 4 步:做出"分派任务"和"多人多轮"

4.1 分派任务:用卡片而不是纯文本

纯文本的 @ 很容易被刷过去。用交互卡片,把任务摊开,还带确认按钮:

```javascript

// 用卡片消息发任务,比纯文本更好确认

const card = {

config: { wide_screen_mode: true },

header: { title: { tag: 'plain_text', content: '任务分派' } },

elements: [

{

tag: 'div',

fields: [

{ is_short: true, text: { tag: 'lark_md', content: '任务\n接口联调' } },

{ is_short: true, text: { tag: 'lark_md', content: '负责人\n<at id=ou_xxx></at>' } },

{ is_short: true, text: { tag: 'lark_md', content: '建议时间\n本周五前' } },

{ is_short: true, text: { tag: 'lark_md', content: '验收标准\n联调环境跑通全流程' } },

],

},

{

tag: 'action',

actions: [

{

tag: 'button',

text: { tag: 'plain_text', content: '我来接' },

type: 'primary',

value: { action: 'accept', task_id: 't_001' },

},

],

},

],

};

// 卡片结构以飞书官方文档为准,字段大小写敏感

```

按钮点击会走卡片回调,你在回调里把 task_id 和点击人写进多维表格,任务闭环就成了。

4.2 多人多轮:三个必须做对的设计

会话键(session key)。用 chat_id 做键,群内共享上下文;如果希望每个人有独立记忆,用 chat_id + open_id。想清楚再选,中途换会丢历史。

上下文裁剪。别把 200 条消息全塞进去。只保留最近 20 条,同时把超过 3 天的历史丢弃。因为群聊里 90% 的消息对当前问题毫无价值。

并发隔离。同一个人连发三条消息时,加一个排队:

```javascript

// 同一个会话串行处理,避免"三连问"被并行回复乱序

const queues = new Map();

function enqueue(key, task) {

const prev = queues.get(key) || Promise.resolve();

const next = prev.then(task, task);

queues.set(key, next);

return next;

}

```

---

第 5 步:上线前的加固清单

  • 幂等:事件 id 去重(第 3 步已做),否则网络抖动会重复回复。
  • 超时:回调必须"秒回",重活异步干。具体超时阈值以官方文档为准。
  • 限流:Agent 调用加并发上限,超了排队而不是直连。
  • 密钥App SecretAPI Key 全部走环境变量,不进 Git。
  • 审计:每条请求记录 chat_id / open_id / 输入 / 输出 / 耗时,出问题时这是唯一的证据。
  • 兜底:Agent 调用失败时,回一句固定话术,而不是静默失败让人干等。

---

常见坑与排错

1. 群里 @ 了没反应。

九成是版本没发布,或者机器人没被拉进群。先去开放平台看"应用发布"状态,再看群成员列表里有没有它。

2. 不 @ 它就不理人。

这是正常行为。机器人默认只收 @ 消息,想收全部消息需要额外申请权限并走审核。

3. 同一条消息被回复了两次。

事件推送会重试。检查幂等逻辑是不是在 res.json() 之前就写好了。

4. 回调一直报超时。

你在回调里同步等 Agent 回答了。改成"先返回 200,再异步处理"。

5. 改了权限还是不生效。

权限变更必须重新发布版本,且通常要管理员审核通过。

6. Agent 把 A 的问题答到 B 头上。

会话键设计问题。先确认你要的是"群人共享记忆"还是"每人独立记忆",再定 key。

7. 长回答刷屏。

在指令里写死字数上限,超过就输出"回复:详情",用户主动要再看。这比事后调格式有效得多。

8. 回调验签失败。

加密 key、verification token 配置对不上。改完记得两边同步。

9. Agent 承诺了做不到的时间。

在指令里明确"只给建议时间,不承诺交付"。这类幻觉靠提示词能压掉大半。

10. 知识库里答案过期。

删掉旧文档,或者给文档加生效日期字段,让 Agent 优先引用最新的。

---

下一步建议

先扩场景,别急着扩人数。 跑通一个群之后,最容易想到的是"再拉 10 个群"。更好的做法是先在这个群里多跑两个场景:把日报汇总接进来、把任务卡片写进多维表格。场景密度比群数量更能体现价值。

把人的反馈变成数据。 在 Agent 的回复下面挂"有用 / 没用"两个按钮,攒够一两百条,你就有了自己的评测集。换模型、改指令之后跑一遍,才知道是真变好了还是碰巧。

开放"人纠正"的入口。 群里允许大家回一句"这条答错了,正确是 XXX",你定期把这些回灌进知识库或指令。这是让群聊 Agent 越用越准的唯一可靠办法。

最后再考虑多群多租户。 那时候要处理的是数据隔离、配额和权限模型,是另一篇教程的内容了。先让一个群真的离不开它。

AI 生成本文由 AI 基于公开信息自动生成,仅供参考。