前五课都在写代码。这一课换个阵营:一行代码不写,用 n8n 拖拽搭出"定时 → AI 生成 → 推送到飞书群"的完整流水线。

适合三类人:不会 Python 的运营/产品、想快速做告警通知的运维、以及评估"这事到底要不要开发"的技术负责人。工具链两样:飞书自定义机器人(群里直接加,免审核)+ n8n 社区节点 n8n-nodes-lark-webhook(提示岛站内 id=12239 收录,GitHub ★19,MIT)。

〇、先看全景:两条路线怎么选

代码路线(L2-L5)零代码路线(本课)
机器人类型应用机器人(开发者后台建应用)自定义机器人(群设置直接加)
门槛要服务端部署 + 公网回调n8n 界面拖拽
能力读表格、收消息、卡片回调、跨群只能往本群发消息
鉴权tenant_access_token + scopewebhook URL + 关键词/IP/签名
限流同用户/群 5 QPS单租户单机器人 100 次/分钟、5 次/秒
适合对话机器人、业务数据管道告警、日报、通知类单向推送

官方原话划清边界:自定义机器人不具任何数据访问权限——要读表格(L5)、收消息(L4),仍得走应用机器人。本课覆盖的是"往外推"这一半。

一、添加自定义机器人:30 秒拿到 webhook

群设置 → 群机器人 → 添加机器人 → 自定义机器人 → 设头像名称 → 复制 webhook 地址(格式 https://open.feishu.cn/open-apis/bot/v2/hook/xxxx)。

官方红字提醒:请妥善保存此地址,不要公布在 GitLab、博客等公开网站——泄露即被人恶意刷消息。这条对做教程的你同样成立:下文所有示例都用 **** 打码。

二、webhook 消息格式:和 L2 接口有四个关键差异

调用方式:向 webhook POST 一段 JSON。以文本为例:

{
    "msg_type": "text",
    "content": { "text": "新更新提醒" }
}

与 L2 的 im/v1/messages 对比,四点必须记住:

差异点L2 应用接口本课 webhook
content 类型JSON 字符串(要双重序列化)直接对象({"text": "..."},不用 dumps 两次!)
体积上限文本 150KB整个请求体 ≤20KB
消息位置任意用户/群(receive_id)固定本群(webhook 即身份)
返回成功code=0 + message{"code":0,"msg":"success"}

第二点最容易把 L2 的老习惯带进来——webhook 的 content 是对象,照 L2 再 json.dumps 一次必报 9499 Bad Request。

支持的消息类型速查:

msg_type说明content 关键结构
text文本{"text": "..."};@人用 <at user_id="ou_xxx">Tom</at>
post富文本{"post": {"zh_cn": {"title": "...", "content": [[{"tag":"text","text":"..."},{"tag":"a","text":"链接","href":"https://..."},{"tag":"at","user_id":"ou_xxx"}]]}}}
image图片{"image_key": "img_xxx"}(仍需先上传换 key)
share_chat群名片{"share_chat_id": "oc_xxx"}
interactive卡片顶层用 card 字段(不是 content):{"msg_type":"interactive","card":{...}}。官方 webhook 卡片示例用的是 schema 2.0 结构;如果你复用 L3 的 1.0 卡片 JSON,同样放进 card 字段(两套协议差异见 L3)

三、三种安全设置:错误码对照 + 签名算法

webhook 裸奔 = 谁拿到地址谁就能发。官方提供三种防护(可叠加):

方式规则失败错误码
自定义关键词最多 10 个,消息须含其一。只过滤 text/title 这类文本参数值,不过滤 href19024 Key Words Not Found
IP 白名单最多 10 个,支持 123.12.1.*、123.1.1.1/24 段19022 Ip Not Allowed
签名校验请求体带 timestamp + sign19021 sign match fail...

签名算法(官方 Python 示例,注意它比常见的 HMAC 用法特殊:签名字符串当 key、对空字符串做 HmacSHA256):

import base64
import hashlib
import hmac


def gen_sign(timestamp: int, secret: str) -> str:
    # 官方算法:string_to_sign = timestamp + "\n" + 密钥;对空串做 HmacSHA256 再 Base64
    string_to_sign = "{}\n{}".format(timestamp, secret)
    hmac_code = hmac.new(string_to_sign.encode("utf-8"), digestmod=hashlib.sha256).digest()
    return base64.b64encode(hmac_code).decode("utf-8")

发送时把两个字段并进请求体:

import json
import time
import urllib.error
import urllib.request

WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/****"   # 你的真实地址别外泄
SECRET = "****"          # 开启签名校验后后台给的秘钥

CODE_HINTS = {
    9499: "请求体格式错误:对照第二节检查 content 结构、确认 ≤20KB",
    19021: "签名校验失败:检查 secret、timestamp(秒级、距当前≤1小时)、服务器时钟",
    19022: "来源 IP 不在白名单",
    19024: "消息未包含自定义关键词:标题或正文里带上关键词",
    11232: "触发限流(100次/分、5次/秒):排队重试;避开整点/半点高峰",
}


def send_webhook(msg_type: str, content=None, card=None) -> dict:
    body = {"msg_type": msg_type}
    if card is not None:
        body["card"] = card                    # interactive:card 直接放对象
    else:
        body["content"] = content              # 其余:content 也是对象,无需二次序列化
    if SECRET:
        ts = int(time.time())                  # 秒级时间戳
        body["timestamp"] = str(ts)
        body["sign"] = gen_sign(ts, SECRET)

    req = urllib.request.Request(
        WEBHOOK_URL,
        data=json.dumps(body, ensure_ascii=False).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=10) as resp:
            payload = json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        payload = json.loads(e.read().decode("utf-8"))
    if payload.get("code") != 0:
        hint = CODE_HINTS.get(payload.get("code"), "查官方自定义机器人指南错误码")
        raise RuntimeError(f"[{payload.get('code')}] {payload.get('msg')} | 排查:{hint}")
    return payload


if __name__ == "__main__":
    send_webhook("text", content={"text": "每日巡检:全部服务正常 ✅"})

四、n8n 路线:装社区节点,10 分钟拖出流水线

节点信息来自提示岛站内条目 id=12239「n8n 飞书自定义机器人节点」(GitHub ★19、MIT、TypeScript,作者 bestony):

  • 支持操作:Send Text Message / Send Markdown Message (via card) / Send Post / Send Card——正好覆盖第二节四种主力格式
  • 凭证配置:官方 README 两步——①群里创建自定义机器人 ②复制 Webhook URL 粘进 n8n credential 页面

安装与搭建 7 步:

步骤操作成功标志
1n8n 里 Settings → Community Nodes → Install搜到 n8n-nodes-lark-webhook 确认安装(需 n8n 允许社区节点)
2目标群添加自定义机器人,复制 webhook 地址拿到 .../bot/v2/hook/xxxx
3n8n 新建 Credentials,粘贴 webhook凭证保存成功
4工作流起点加 Schedule 节点(如每天 9:00)节点启用
5加 OpenAI/LLM 节点,Prompt 填第七节模板测试运行输出报告文本
6加 Lark Webhook 节点,Operation 选 Send Text,内容引用上一节点输出 {{ $json.output }}节点亮绿
7Execute Workflow 手动跑一次群里收到 AI 生成的日报

不想装社区节点?等价方案:n8n 原生 HTTP Request 节点直接 POST 第二节的 JSON 到 webhook——效果相同,只是要手填 body。社区节点省掉拼 JSON 这步。

五、四个必踩的坑

坑 1:把 L2 的双重序列化习惯带进来(9499)

webhook 的 content 是对象不是字符串。从 L2 迁移代码的人最常在这翻车——json.dumps(content) 删掉,直接传 dict。

坑 2:限流节奏和应用机器人完全不同(11232)

自定义机器人是单租户单机器人 100 次/分钟、5 次/秒,且官方明确提醒:尽量避开 10:00、17:30 等整点半点——平台压力集中时更容易限流失败,失败会导致消息丢失。定时日报把触发时间设成 9:02、17:33 这种"错峰分钟",比踩着整点发稳妥得多。

坑 3:关键词只过滤文本参数值(19024)

设了关键词"报警",但富文本消息只在 href 里带"报警"——照样被拦。官方规则:只检查 text、title 这类参数值。把关键词放进标题是最稳的做法。

坑 4:签名对不上(19021)

三个高频原因:timestamp 用了毫秒(要秒级)、超过 1 小时(每次发送现算,别缓存 sign)、服务器时钟漂移(校准 NTP)。另注意本课签名是"string_to_sign 当 key、对空串求 HmacSHA256"这个特殊形态,别按通用 HMAC 习惯把 body 当消息签。

结论:webhook 四查——content 别序列化、错峰防 11232、关键词放标题、签名秒级现算。

六、两段可以直接复制的报告类提示词

流水线的 AI 节点里填什么?这两段来自提示岛站内条目,变量槽和 n8n 上游节点输出天然对应。

① 每日/活动报告——id=12018「营销活动报告生成」(4 个变量槽,全文照抄):

You are an AI marketing report writer. Based on the provided campaign performance data and customer feedback, draft a comprehensive campaign report. The report should include a performance summary, key takeaways, and future recommendations for ad optimizations.

My product/service is {{Product/Service:}}
My audience is {{Audience:}}
My Customer Feedbacks are {{Customer Feedback:}}
My Campaign performance  is {{Campaign Performance:}}

变量槽 ← n8n 数据源映射:{{Campaign Performance:}} ← 上游 HTTP 节点拉回的后台数据/Google Sheets 节点输出;{{Customer Feedback:}} ← 第五课那种表格读出的行数据;{{Product/Service:}}/{{Audience:}} ← Set 节点常量的固定值。四个槽三个能自动化喂数,两个一次配置固定——这就是报告机器人"全自动"的真相:提示词只是模板,变量来自工作流。

② 监控巡检报告——id=11395「广告投放频次监控」:

Function as a {{Ad Frequency:}} ad campaign manager. Devise a comprehensive process for routinely observing the effectiveness of my ad campaigns for the product/service. My product/service is {{Product/Service:}}, and my audience is {{Audience:}}

The strategy should be capable of meticulously analyzing key performance indicators and should include a plan for improving the campaign based on these observations.

用法差异:①产出"这一期的报告"(配 Schedule 定期推),②产出"持续监控的机制建议"(一次性生成 SOP,结果可存进多维表格再让①每期引用)。

结论:报告机器人的提示词要"留满变量槽"——每个槽接一个自动化数据源,机器人才能真正无人值守。

这一课做完,你手上有什么

  • 自定义机器人 webhook 的正确用法(content 对象、20KB、错峰限流)
  • 签名校验完整实现(官方算法 + 5 个错误码中文映射)
  • n8n 社区节点 7 步搭建流程(零代码版"AI 日报机器人")
  • 两段变量槽对齐 n8n 数据流的报告提示词

下一课(L7,收官):完整项目复盘——把 L1-L6 拧成一个"多机器人协作"的实战架构,并盘点提示岛站内那 147 条飞书插件里还有哪些可直接拿来用的轮子。


附:提示岛是什么

本文节点与提示词来自提示岛(prompts.ssjintaitong.com),AI 提示词与 Skill 库,实测收录 10909 条,其中文字提示词 3484 条(完整全文、一键复制),Skill/插件 5298 条,23 个分类。免登录、免注册。

飞书相关入口:

  • 飞书 AI 自动化专题(147 条):prompts.ssjintaitong.com/topic/feishu
  • 本文节点原文:prompts.ssjintaitong.com/prompts/12239(附 GitHub 源码链接)
  • 本文两段提示词:prompts.ssjintaitong.com/prompts/12018、/prompts/11395
  • 本系列 L1-L5 教程条目:同专题内搜「飞书对接 AI」

站内两个实用功能:Skill 质量评分(5298 个插件条目按四维度打 A-D 档,报告在 /quality-report);每条附原始出处(GitHub 链接 + 许可证)。搜索技巧:用场景词搜,搜「飞书」有 133 条,站内搜「n8n 飞书」直接命中本课节点。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐