第 7 章 · 02 飞书卡片消息:交互式通知的构建 本节摘要:本节讲 Sequoia-X 触达层的「载体」——飞书交互卡片。飞书的「自定义机器人」支持发送两种消息:纯文本和交互卡片。纯文本消息单调(一坨字符串),交互卡片结构化(标题、日期、选股列表、链接、分割线、按颜色高亮)。本节会先讲飞书机器人的两种消息类型对比;再深入交互卡片的 JSON 结构—— / / 三大块的字段语义;然后讲 Sequoia-X 卡片设计——标题+日期+策略名+数量+选股列表的层次;最后用一段可运行的代码完整构造一张卡片 JSON,不发,只构造。学完本节,你就掌握了「把数据变成可视化消息」的工程能力——这套思路可迁移到企业微信、Slack、Discord。
本节摘要:本节讲 Sequoia-X 触达层的「载体」——飞书交互卡片。飞书的「自定义机器人」支持发送两种消息:纯文本和交互卡片。纯文本消息单调(一坨字符串),交互卡片结构化(标题、日期、选股列表、链接、分割线、按颜色高亮)。本节会先讲飞书机器人的两种消息类型对比;再深入交互卡片的 JSON 结构——
msg_type/card.header/card.elements三大块的字段语义;然后讲 Sequoia-X 卡片设计——标题+日期+策略名+数量+选股列表的层次;最后用一段可运行的代码完整构造一张卡片 JSON,不发,只构造。学完本节,你就掌握了「把数据变成可视化消息」的工程能力——这套思路可迁移到企业微信、Slack、Discord。
内容来源:飞书开放平台官方文档 + 原项目飞书通知模块精读。
阅读完本节,你应当能够:
| 维度 | 纯文本(text) | 交互卡片(interactive) |
|---|---|---|
| 内容形式 | 单字符串 | 结构化 JSON |
| 标题支持 | ❌ 无 | ✅ Header 块 |
| 多元素支持 | ❌ 一坨字符串 | ✅ Elements 数组(多块内容) |
| 链接支持 | 自动识别 URL | 可显式构造 |
| 富文本格式 | ❌ | ✅ 支持 lark_md |
| 视觉层次 | 平面 | 多层次(标题 / 内容 / 分割线) |
| 推荐场景 | 简单通知 | 结构化信息(如选股结果) |
Sequoia-X 选交互卡片——选股结果天然结构化(标题 + 日期 + 列表),用卡片信息密度更高。
飞书交互卡片是一个三层 JSON:
{ "msg_type": "interactive", "card": { "header": { /* 卡片标题 */ }, "elements": [ /* 内容块数组 */ ] } }
下面看 Sequoia-X 实际构造的卡片结构(简化版):
{ "msg_type": "interactive", "card": { "header": { "title": { "tag": "plain_text", "content": "📈 Sequoia-X 选股播报 | 海龟突破" }, "template": "blue" }, "elements": [ { "tag": "div", "text": { "tag": "lark_md", "content": "**日期:** 2024-06-15\n**策略:** 海龟突破\n**选股数量:** 2" } }, { "tag": "hr" }, { "tag": "div", "text": { "tag": "lark_md", "content": "**选股列表:**\n[贵州茅台](https://xueqiu.com/S/SH600519) [平安银行](https://xueqiu.com/S/SZ000001)" } } ] } }
逐层精读:
| 字段 | 含义 | 必需 |
|---|---|---|
msg_type |
固定 "interactive"(标识为交互卡片) |
✅ |
card |
卡片主体 | ✅ |
header(标题块)| 字段 | 含义 | Sequoia-X 的选择 |
|---|---|---|
title.tag |
标题类型 | plain_text(纯文本) |
title.content |
标题内容 | 📈 Sequoia-X 选股播报 | 策略名 |
template |
标题色板 | blue(蓝色,可选 red/green/orange 等) |
elements(内容块数组)elements 是一个数组,可以包含多种类型的「块」:
| 块类型 | tag |
作用 |
|---|---|---|
| 文本块 | div |
一段文字(支持 lark_md 富文本) |
| 分割线 | hr |
视觉分隔 |
| 按钮 | button |
可点击按钮 |
| 图片 | img |
显示图片 |
| 备注 | note |
折叠/补充信息 |
Sequoia-X 的卡片用了三种块:
div 块 × 2:日期/策略/数量 文字 + 选股列表 文字hr 块 × 1:分割线「块」的设计哲学——每个块独立渲染、互不干扰——比单字符串灵活得多。
div 块里的 text.tag 是 lark_md——飞书自定义的 markdown 方言:
| 语法 | 渲染效果 |
|---|---|
**加粗** |
加粗文字 |
*斜体* |
斜体文字 |
[链接文字](URL) |
可点击的链接 |
\n |
换行 |
Sequoia-X 用 **日期:** 2024-06-15 这种格式让「键」加粗、「值」不处理——视觉重点突出。
💡 核心心法:消息里谁加粗、谁不处理是「信息层次」的核心设计——加粗 = 视觉锚点——读者第一眼应该看到最重要的信息。
把 Sequoia-X 实际构造的卡片层次化展示:
📈 Sequoia-X 选股播报 | 海龟突破 ← 标题(蓝色) ───────────────────────────────────── **日期:** 2024-06-15 ← 元信息(加粗键) **策略:** 海龟突破 **选股数量:** 2 ───────────────────────────────────── ← 分割线 **选股列表:** ← 选股块(可点击链接) [贵州茅台](雪球链接) [平安银行](雪球链接)
信息层次:
三个层次从抽象到具体——眼睛的移动路径就是信息的展开路径。
下面这段代码完整演示「从选股结果到飞书卡片 JSON」的构造过程。它只构造、不发送——你能直接看到生成的 JSON 长什么样:
# feishu_card_demo.py # 可运行:构造一张飞书交互卡片(不发,只构造) import json from datetime import date def to_xueqiu_code(symbol: str) -> str: """6 开头 → SH;4/8 开头 → BJ;其余 → SZ。""" if symbol.startswith("6"): return f"SH{symbol}" elif symbol.startswith(("4", "8")): return f"BJ{symbol}" return f"SZ{symbol}" def to_link(symbol: str, name: str | None = None) -> str: """生成雪球链接 markdown。""" xq = to_xueqiu_code(symbol) label = name or xq return f"[{label}](https://xueqiu.com/S/{xq})" def build_card(symbols: list[str], strategy_name: str, names: dict[str, str] | None = None) -> dict: """ 构造一张飞书交互卡片。 symbols: 选股代码列表 strategy_name: 策略名(用于标题) names: 可选的代码→名称映射 """ today = date.today().strftime("%Y-%m-%d") # 选股列表 markdown(带可点击链接) if symbols: links = [to_link(s, (names or {}).get(s)) for s in symbols] symbol_text = " ".join(links) else: symbol_text = "(无选股结果)" return { "msg_type": "interactive", "card": { "header": { "title": { "tag": "plain_text", "content": f"📈 Sequoia-X 选股播报 | {strategy_name}", }, "template": "blue", }, "elements": [ { "tag": "div", "text": { "tag": "lark_md", "content": f"**日期:** {today}\n**策略:** {strategy_name}\n**选股数量:** {len(symbols)}", }, }, {"tag": "hr"}, { "tag": "div", "text": { "tag": "lark_md", "content": f"**选股列表:**\n{symbol_text}", }, }, ], }, } if __name__ == "__main__": symbols = ["600519", "000001", "300750"] names = {"600519": "贵州茅台", "000001": "平安银行"} card = build_card(symbols, "海龟突破", names) print(json.dumps(card, ensure_ascii=False, indent=2))
预期输出(格式化 JSON):
{ "msg_type": "interactive", "card": { "header": { "title": { "tag": "plain_text", "content": "📈 Sequoia-X 选股播报 | 海龟突破" }, "template": "blue" }, "elements": [ { "tag": "div", "text": { "tag": "lark_md", "content": "**日期:** 2026-08-06\n**策略:** 海龟突破\n**选股数量:** 3" } }, { "tag": "hr" }, { "tag": "div", "text": { "tag": "lark_md", "content": "**选股列表:**\n[贵州茅台](https://xueqiu.com/S/SH600519) [平安银行](https://xueqiu.com/S/SZ000001) [SH300750](https://xueqiu.com/S/SZ300750)" } } ] } }
把这段 JSON 贴到飞书卡片调试器(飞书开放平台 → 自定义机器人)里,就能直接看到渲染效果。
template 字段的可用色板header.template 控制标题色板:
| 模板 | 颜色 | 适用场景 |
|---|---|---|
blue |
蓝色 | 默认——中性 |
red |
红色 | 紧急 / 风险提示 |
orange |
橙色 | 警告 / 注意 |
green |
绿色 | 利好 / 成功 |
purple |
紫色 | 特殊场景 |
grey |
灰色 | 普通通知 |
Sequoia-X 默认用 blue——中性——不传递「利好」或「风险」的暗示(不构成投资建议)。
颜色是「情感信号」——蓝/灰更克制,红/绿更情绪化。Sequoia-X 选蓝色——与「只做信息触达」的克制立场一致。
飞书还有「Markdown 群机器人」(直接发 markdown)。为什么不选它?
| 维度 | 交互卡片 | Markdown 群机器人 |
|---|---|---|
| 视觉层次 | 强(标题 / 内容 / 分割) | 弱(靠标题符号) |
| 可点击链接 | ✅ 显式构造 | ✅ markdown 链接 |
| 支持块类型 | ✅ 多块(div / hr / button) | ❌ 单字符串 |
| API 兼容性 | 部分老群不支持 | 普遍支持 |
| 推荐场景 | 结构化信息(如选股结果) | 简单通知 |
Sequoia-X 选交互卡片——结构化信息需要结构化载体。
飞书卡片构建 ✅ ← 本节 │ ▼ 下一节(第 03 节)多机器人路由:按策略分发到不同群
msg_type → card.header → card.elements。div(文本)+ hr(分割线)+ button/img(可选)——比单字符串灵活。**加粗**、[链接](URL)、\n 换行——视觉层次靠富文本。template 色板:blue(中性)/red(风险)/green(利好)——Sequoia-X 用 blue(克制)。配套教学脚本:
images/feishu_card_demo.py——生成完整卡片 JSON。
下一节,把卡片分发到不同机器人——讲多机器人路由。