5.6 KiB
5.6 KiB
飞书群发消息 + @人(已验证配方 2026-06-16)
目标:把消息发到正确的飞书群并 @ 正确的人,一次做对。依赖 lark-cli(lark-im 技能)。
步骤
1. 找出 bot 实际所在的群(不要猜 chat_id)
cd ~ && lark-cli im +chat-list --as bot
返回每个群的 chat_id、name、description、owner_id。挑出你和目标人共处的那个群。
- 本环境已知群:"Doro, Maggie, 魏玮"(描述"小Maggie工作群")=
oc_a927f86118216c36cb9394b0e95f2a11。 - 若有多个候选群,按成员和描述确认,仍不确定就问用户,别赌。
2. @人的格式(两种已验证写法,均触发真实可点击 @ + 通知)
- text 模式:
--msg-type text,content 形如{"text":"<at>…</at> 正文"},@ 标签<at user_id="ou_xxx">显示名</at>(用 open_id;嵌进 JSON 字符串时内层引号按 JSON 规则转义)。@所有人<at user_id="all"></at>。 - post 模式(多行/结构化汇报推荐,2026-06-16 已验证):post JSON 里 @ 用 at 元素
{"tag":"at","user_id":"ou_xxx"},与文本元素{"tag":"text","text":"…"}同行拼接,配--msg-type post。结构:{"zh_cn":{"content":[[{"tag":"at","user_id":"ou_757f053c9d7aff6c73b18aa60c337756"},{"tag":"text","text":" 进展汇报…"}],[{"tag":"text","text":"第二行"}]]}} - 不要用
--markdown发 @:会强制转 post 且 @ 处理不可靠,用显式 post JSON 自己控制。
3. 先 dry-run 验证 payload
lark-cli im +messages-send --chat-id oc_xxx --as bot \
--content '{"text":"<at user_id=\"ou_757f053c9d7aff6c73b18aa60c337756\">Doro</at> 正文…"}' \
--msg-type text --dry-run
检查 body 里 chat_id、msg_type、@标签是否正确。
4. 去掉 --dry-run 正式发送
成功返回 message_id + create_time。把 message_id 和北京时间报给用户便于核对。
发送前如何核实「这个 open_id 确实是目标本人」
@错人是红线。理想是查通讯录,但本 bot 常缺 contact / chat 读权限,按可靠性从高到低:
- gateway.log 取地面真值(最可靠,无需任何 scope)——平台事件原始数据,比 API、比记忆都硬:
再看「当前这条消息」的入站行确认发送者:
grep "oc_<群id>" ~/.hermes/logs/gateway.log | grep -oE "ou_[a-z0-9]{20,}" | sort | uniq -c | sort -rn把刚收到那句话的grep "inbound message: platform=feishu" ~/.hermes/logs/gateway.log | tail # → user=ou_xxx chat=oc_xxx msg='…' 即是谁在这个群说了这句话user=ou_xxx与已知映射比对,一致才发。 - 已知 open_id 映射(下方表 + memory),ID 没映射到人 → 先问不猜。
- 通讯录 API(常被 scope 挡):
lark-cli contact +get-user --user-id ou_xxx --user-id-type open_id --as user。本环境 2026-06-16 报缺contact:user.basic_profile:readonly;im chat.members get也缺im:chat.members:read等。缺权限是正常状态,别卡在这里——退回方法 1。
已知 open_id(核对身份用,新增/纠正后同步到 memory)
- Doro =
ou_757f053c9d7aff6c73b18aa60c337756(与 bot 私聊 chat=oc_9292e11bd98ddb5a69ea2c2da10d4f12) - Scott(魏玮) =
ou_04fade9a9335c09ad09846da2051b3c0
注意
--as bot:消息以应用 bot 名义发出,bot 必须已在目标群里。- lark-cli 是 API 工具,不是消息网关;bot 身份不代理用户(Scott 已纠正)。
- 终端里 lark-cli 输出常带 HTTPS_PROXY 的 WARN 和版本更新 notice,是噪音,不影响结果;可
grep -v "WARN\|proxy"过滤。
发文件附件到群里(md/pdf/docx 报告,已验证)
要把一份文件(错误分析 md、合同 docx、报告 pdf)发到群里,用 --file。常见组合:先发文件附件,再发一条 @某人 的 post 说明(文件本身不能 @ 人,说明消息负责 @)。
# 先发文件(--file 接 cwd 相对路径),成功返回 message_id 并打印 "uploading file: xxx"
cd ~/lark_send_tmp && lark-cli im +messages-send \
--chat-id oc_a927f86118216c36cb9394b0e95f2a11 \
--as bot --file "./报告.md" \
--dry-run 2>&1 | grep -v "WARN\|proxy" # 先 dry-run,确认后去掉 --dry-run
# 再发 @某人 的 post 说明(见上「@人的格式」post 模式),把文件背景+要点写清楚
⚠️ 关键坑:--file 只接 cwd 相对路径,绝对路径被拒
lark-cli 安全限制:--file(及 --image/--video/--audio)拒绝绝对路径(如 /tmp/x.md),路径解析 ../symlink 后必须仍在 cwd 内。
解法:把文件复制到干净工作目录,cd 进去用 ./文件名 发:
mkdir -p ~/lark_send_tmp && cp "/tmp/报告.md" ~/lark_send_tmp/
cd ~/lark_send_tmp && lark-cli im +messages-send --chat-id oc_xxx --as bot --file "./报告.md"
rm -rf ~/lark_send_tmp # 发完清理
- 本地文件 lark-cli 会先自动上传再发 file 消息,无需手动
images.create/拿 file_key。 - dry-run 时 file_key 显示占位符
file_dryrun_upload是正常的,正式发送才真上传。 - 同理发图片用
--image ./x.png,视频--video ./x.mp4 --video-cover ./cover.png。
已知群与人 ID(核对身份用)
| 对象 | ID |
|---|---|
| 飞书工作群"Doro, Maggie, 魏玮"(小Maggie工作群) | oc_a927f86118216c36cb9394b0e95f2a11 |
| Doro | ou_757f053c9d7aff6c73b18aa60c337756(私聊 chat oc_9292e11bd98ddb5a69ea2c2da10d4f12,别和群混) |
| Scott / 魏玮 | ou_04fade9a9335c09ad09846da2051b3c0 |
| @所有人 | all |