✅ 本文方案已于 2026-06-28 实际验证通过 — 两个 WorkBuddy 定时自动化任务(凌晨 2:00 工作纪要、3:00 早间新闻)均已成功通过 QQ 群推送。
背景:自动化任务需要"最后一公里"#前面几篇文章分别解决了 Gitea 代码仓库、禅道项目管理、微信/企微数据读取 的 AI 接入问题。但这些解决的都是数据输入——让 AI 能读数据、查信息。
一个真正有用自动化助手还需要输出通道。具体需求:
「悟空的早间新闻推送」:每天凌晨 3:00 自动采集 AI 动态、天气、财经行情、ETF 监控,推送到手机「温陵布衣昨日工作纪要」:每天凌晨 2:00 整理前一天的企微消息、邮件、项目日志,推送摘要两个任务都跑得挺好,但消息一直只能写本地文件——你需要主动打开电脑去看,手机端完全收不到。这和"主动通知"的目标背道而驰。
路线一:企业微信(失败)#最自然的思路是企业微信——公司全员在用,WorkBuddy 也有企微连接器(wecom connector)。
尝试过程#企微连接器发消息:WorkBuddy 企微连接器已绑定成功,但发消息时报错 当前企业暂不支持授权机器人「消息」使用权限管理员确认:咨询企业微信管理员,回复只有「文档」授权,没有「消息」授权wecom-cli skill:这个 skill 本质是解密本地 SQLite 数据库,只读不写,无法发送消息结论#企微消息推送的前提是企业管理员在企微后台开通「消息」权限。如果你的企业没有开通(多数企业内部出于安全管控不开放),企微推送这条路就彻底堵死了。无绕路方案。
📎 如果你所在企业的企微已开通消息权限,WorkBuddy 企微连接器可以直接发消息,本文后续的 QQ Bot 方案不必看。
路线二:QQ 机器人(成功)#受 OpenClaw 接入 QQ 机器人 的思路启发——OpenClaw 可以通过 QQ Bot 定时推送消息,WorkBuddy 的自动化任务同样可以。
核心技术栈:
WorkBuddy 自动化任务(凌晨执行)
→ 采集数据、生成消息文本
→ 调用 Python 脚本
→ botpy SDK 连接 QQ WebSocket 认证
→ 发送群消息
→ 手机 QQ 收到推送
完整实施步骤#第一步:在 QQ 开放平台注册机器人#打开 QQ 开放平台,用手机 QQ 扫码登录点击「创建机器人」,填写名称(如 YourBot-WorkBuddy)进入机器人详情 → 开发设置 → 获取以下两个凭据:凭据说明AppID纯数字,如 YOUR_APPIDAppSecret点击「生成」获取,只显示一次,立即保存在「开发设置 → 权限配置」中开启 「群聊消息」 权限确认机器人状态为 「已上线」(开发中的机器人无法调用 API)⚠️ AppSecret 只显示一次。错过了只能「重置」,旧密钥立即失效。
第二步:创建专用 QQ 群#在手机 QQ 创建一个新群(只有你一人即可),命名如 YourGroup-WorkBuddy把刚注册的机器人拉进群关键配置:群设置 → 机器人 → 打开 「机器人主动在群聊内发言」为什么是群聊而不是私聊?QQ 官方 Bot API 对私聊有严格限制——每月只能主动发 4 条消息。群聊则无此限制(2026 年 6 月全量开放),每分钟可发 20 条。
第三步:安装 botpy SDK#1
pip install qq-botpy
botpy 是腾讯官方维护的 QQ Bot Python SDK,封装了 WebSocket 连接和 REST API。
第四步:获取群标识(group_openid)#QQ Bot API 发送群消息需要 group_openid,这不是群号,需要通过 WebSocket 事件获取。
创建 qq_get_group_openid.py(下载):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env python3
"""
获取 QQ 群的 group_openid
运行方式:把机器人加到群后,运行本脚本,然后在群里 @机器人 发一条消息
脚本会打印 group_openid 并保存到文件,然后自动退出
"""
import os
import sys
APPID = "YOUR_APPID" # 替换为你的 AppID
SECRET = "YOUR_APPSECRET" # 替换为你的 AppSecret
OUTPUT_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "qq_group_openid.txt")
import botpy
from botpy.message import GroupMessage
class GetGroupOpenidClient(botpy.Client):
async def on_group_at_message_create(self, message: GroupMessage):
"""收到群 @消息时触发"""
group_openid = message.group_openid
print(f"GROUP_OPENID={group_openid}", flush=True)
# 退出脚本
import os as _os
_os._exit(0)
if __name__ == "__main__":
print("=" * 50)
print("QQ Group openid Capture Script")
print("=" * 50)
print(f"AppID: {APPID}")
print("In the QQ group, send an @message to the bot")
print("=" * 50)
intents = botpy.Intents.all()
client = GetGroupOpenidClient(intents=intents, bot_log=False)
client.run(appid=APPID, secret=SECRET)
运行方式:
1
python qq_get_group_openid.py
脚本启动后,去手机 QQ 群 @机器人 发一条消息。脚本会打印 GROUP_OPENID=XXXXXXXX,同时保存到 qq_group_openid.txt。
第五步:编写推送脚本#创建 qq_send_group_msg.py(下载):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env python3
"""
QQ 群消息发送脚本 - 通过 botpy WebSocket 连接发送群消息
用法:
python qq_send_group_msg.py "消息内容"
python qq_send_group_msg.py --file <文件路径>
"""
import sys
import os
APPID = "YOUR_APPID" # 替换
SECRET = "YOUR_APPSECRET" # 替换
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
GROUP_OPENID_FILE = os.path.join(SCRIPT_DIR, "qq_group_openid.txt")
import botpy
from botpy.message import GroupMessage
class SendGroupMsgClient(botpy.Client):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._msg_to_send = None
self._group_openid = None
async def on_ready(self):
"""WebSocket connected, send message then exit"""
if self._msg_to_send and self._group_openid:
try:
result = await self.api.post_group_message(
group_openid=self._group_openid,
msg_type=0,
content=self._msg_to_send
)
msg_id = result.get('id') if isinstance(result, dict) else result.id
print(f"SEND_OK: id={msg_id}", flush=True)
except Exception as e:
print(f"SEND_FAIL: {e}", flush=True)
else:
print("READY_OK: no message to send", flush=True)
os._exit(0)
async def on_group_at_message_create(self, message: GroupMessage):
print(f"GROUP_OPENID={message.group_openid}", flush=True)
def main():
if len(sys.argv) < 2:
print("Usage: python qq_send_group_msg.py
print(" python qq_send_group_msg.py --file
sys.exit(1)
msg = sys.argv[1]
if msg == "--file" and len(sys.argv) >= 3:
filepath = sys.argv[2]
if os.path.exists(filepath):
with open(filepath, "r", encoding="utf-8") as f:
msg = f.read().strip()
else:
print(f"ERROR: File not found: {filepath}")
sys.exit(1)
if not os.path.exists(GROUP_OPENID_FILE):
print("ERROR: qq_group_openid.txt not found")
print("Run qq_get_group_openid.py first to capture group_openid.")
sys.exit(1)
with open(GROUP_OPENID_FILE, "r", encoding="utf-8") as f:
group_openid = f.read().strip()
print(f"Target: {group_openid} | Size: {len(msg)} chars", flush=True)
intents = botpy.Intents.all()
client = SendGroupMsgClient(intents=intents, bot_log=False)
client._msg_to_send = msg
client._group_openid = group_openid
try:
client.run(appid=APPID, secret=SECRET)
except Exception as e:
print(f"ERROR: {e}", flush=True)
sys.exit(1)
if __name__ == "__main__":
main()
测试发送:
1
python qq_send_group_msg.py "[测试] WorkBuddy QQ推送通道测试"
如果手机 QQ 群收到消息,通道即打通。
第六步:接入 WorkBuddy 自动化任务#在 WorkBuddy 自动化任务的 prompt 中,将「推送」步骤改为调用上述脚本:
## 任务六:通过QQ机器人推送
调用 Python 脚本发送消息:
python /path/to/qq_send_group_msg.py “<消息内容>”
如果推送失败,将内容写入备用文件:
/path/to/fallback_news.txt
注意事项:
消息内容中不要使用 emoji(Windows GBK 控制台编码兼容问题)消息内容中的双引号需要转义建议在自动化 prompt 中指定 cwds 为脚本所在目录五个踩坑实录#以下是实际过程中遇到的五个坑,排序按耗时从多到少。
坑一:AppSecret 复制错误#现象:botpy 连接报错 100016 invalid appid or secret
排查过程:
检查 AppID 格式(字符串/数字都试过)检查 AppSecret 是否有隐藏字符(空格、换行)直接 curl API 测试根因:QQ 开放平台的 AppSecret 生成和展示不在同一个页面。第一次从错误位置复制的旧密钥已失效。
教训:获取 AppSecret 后立刻用 curl 验证:
1
2
3
curl -s -X POST https://bots.qq.com/app/getAppAccessToken \
-H "Content-Type: application/json" \
-d '{"appId":"YOUR_APPID","clientSecret":"YOUR_APPSECRET"}'
返回 access_token 即为有效。
坑二:botpy SDK API 变化#现象:ImportError: cannot import name 'GroupMessage' from 'botpy.types.message'
根因:botpy SDK 大版本更新后,类的位置变了:
❌ 旧版:from botpy.types.message import GroupMessage✅ 新版:from botpy.message import GroupMessage同样,Intents 的构造方式也变了:
❌ 旧版:botpy.Intents(botpy.Intents.DEFAULT_VALUE)✅ 新版:botpy.Intents.all()教训:遇到 SDK 文档不匹配时,直接读安装的包源码:
1
2
pip show qq-botpy | grep Location # 找到安装路径
grep -r "class GroupMessage" <安装路径>/botpy/ # 找到类的真实位置
坑三:Windows 沙箱拦截文件写入#现象:脚本内部写文件时报 PermissionError
根因:WorkBuddy 沙箱模式下,某些路径的写操作被拦截。
解决方案:改为先打印到 stdout,再手动创建文件写入:
1
print(f"GROUP_OPENID={group_openid}", flush=True) # stdout 总能捕获
坑四:GBK 控制台编码导致 emoji 崩溃#现象:脚本打印 emoji 时崩溃 UnicodeEncodeError
根因:WorkBuddy 自动化任务运行环境使用 GBK 编码控制台,emoji 字符无法 encode。
解决方案:
脚本中全部使用纯英文/ASCII 字符输出消息内容中去掉 emoji,用纯文本符号代替设置 PYTHONIOENCODING=utf-8 环境变量(如环境支持)坑五:消息发送后脚本没有退出#现象:自动化任务执行后一直挂起不结束
根因:botpy Client 的 on_ready 回调发送消息后没有主动退出进程,WebSocket 连接保持导致脚本不退出。
解决方案:发送完成后调用 os._exit(0) 强制退出:
1
2
3
4
async def on_ready(self):
result = await self.api.post_group_message(...)
print(f"SEND_OK: id={result.id}", flush=True)
os._exit(0) # 必须强制退出
方案对比#维度企微推送QQ Bot 群推送前提条件企业管理员开通「消息」权限注册 QQ 开放平台机器人开通难度高(多数企业不开放)低(个人即可操作)发送限制无20 条/分钟私聊推送支持每月仅 4 条技术栈WorkBuddy 内置连接器botpy + 自定义脚本手机端企微 AppQQ App附录:企微推送失败全记录#企业微信推送尝试了以下三条路径,全部失败:
尝试一:WorkBuddy 企微连接器#WorkBuddy 内置的企微连接器(wecom connector)在绑定企业微信后,文档读写正常,但发送消息时报错:
当前企业暂不支持授权机器人「消息」使用权限
尝试二:企业微信管理后台#咨询企业微信管理员后确认:该企业的企微授权范围仅为「文档」,不包含「消息」。这是企业层面(而非用户层面)的权限管控,管理员本人也无法单独开通。
尝试三:wecom-cli skill#wecom-cli 的工作原理是解密本地企微客户端的 SQLite 数据库文件来读取聊天记录和联系人。它不具备发送消息的能力(没有调用企微消息 API)。
结论#企微消息推送的三要素:企业授权 + 管理员配置 + 消息 API 权限。缺一不可。如果你的企业没有开通「消息」权限,不要在这条路上浪费时间,直接走 QQ Bot 方案。
是否值得封装为 Skill?#可以,而且建议。 将 QQ Bot 推送流程封装为 WorkBuddy Skill 有以下好处:
一键安装:其他人只需安装 skill,无需手动下载脚本统一配置:凭据和路径集中管理在 SKILL.md 中自动化任务引用更简洁:只需 @skill:qq-bot-push --msg "内容"Skill 结构建议:
qq-bot-push/
SKILL.md # 技能定义 + 配置说明
scripts/
qq_send_group_msg.py # 发送脚本(已脱敏占位)
qq_get_group_openid.py # 获取 group_openid 脚本
后续我会把这一整套流程封装为一个 Skill,届时单独发布。
需要替换的脱敏数据#⚠️ 占位符替换说明 — 以下占位符需替换为你的真实值,真实值请自行妥善保存(建议存本地加密备忘录或密码管理器)。
占位符说明获取方式YOUR_APPIDQQ 开放平台 AppID(纯数字)QQ 开放平台 → 机器人详情 → 开发设置YOUR_APPSECRETQQ 开放平台 AppSecretQQ 开放平台 → 开发设置 → 点击「生成」获取(只显示一次)YOUR_GROUP_OPENID目标 QQ 群的 openid运行 qq_get_group_openid.py 后从 stdout 获取YourBot-WorkBuddy你在 QQ 开放平台注册的机器人名称自定义YourGroup-WorkBuddy你自建的 QQ 群名称自定义附件下载#以下脚本文件可直接下载使用(已脱敏,替换占位符即可):
文件下载说明qq_get_group_openid.py下载获取 QQ 群 group_openid(WebSocket 事件监听)qq_send_group_msg.py下载发送 QQ 群消息(WebSocket 连接+发送+退出)附件中所有 YOUR_APPID、YOUR_APPSECRET 均为占位符,使用前需替换为真实值。完整 Skill 封装见后续文章 WorkBuddy Skill 封装实战。
总结#打通 WorkBuddy 自动化任务的消息推送,核心结论:
企微用不了就别纠结——没有消息权限就是没有,绕不过QQ Bot 群推送是目前最可行的替代方案——个人即可注册,零成本botpy 的 WebSocket 模式比纯 REST API 更可靠——QQ 平台要求先建 WebSocket 连接再发消息踩过的坑都是好的——SDK API 变化、沙箱限制、编码问题,各花 5-10 分钟排查
