搞QQ群聊机器人这事,我其实是被群友逼出来的。当时群里天天有人刷屏发垃圾链接,管理员封都封不过来,我就想干脆写个机器人自动踢人,后来发现官方把路子铺得很好了,根本不用自己去逆向协议。这篇文章就从零开始,把基于QQ开放平台用Python搭群聊机器人的完整流程梳理一遍,从账号申请、环境准备、SDK选型到核心代码、上线部署、常见坑位全部讲透,适合有一定Python基础、想自己动手写一个实用群管或者娱乐机器人的开发者参考。

1. 项目整体设计与方案选型

1.1 拆解需求:这个机器人到底要干什么

动手之前先别急着装环境,把需求想清楚能省掉后面一大半返工。群聊机器人看似简单,实际上按使用场景可以分成几个层次:最基础的层是"被动响应",机器人只在群里被@的时候回复一句,比如查个天气、翻译句话、生成个图片;进阶一点是"主动服务",机器人自己盯群里的消息流,发现关键词就自动处理,比如群内签到、关键词提醒、垃圾消息过滤;再往上就是"管理工具",涉及禁言、踢人、欢迎语、定时任务这些,这层需要调用平台的群管理能力,权限要求也更高。

我这次的目标很明确:做一个能处理指令的群聊工具,支持关键词触发回复、调用第三方API查天气/查新闻、以及一条管理类的"踢人"指令。选定这个范围是因为它刚好覆盖了机器人开发的核心链路——事件接收、消息解析、API调用、回复下发,又不会因为过度设计把自己卡死在前期准备上。建议第一次做的朋友也按这个思路来,哪怕你最终想要的是游戏机器人或者签到机器人,第一版都先跑通"收到消息-处理-回复"这个闭环,后面再往里面加业务逻辑。

需求拆解完了,下一步就是选技术路线。这一块的选择会直接决定你后面三个月维护的时候是轻松还是痛苦,得多花点心思。

1.2 实现方案对比:官方开放平台与SDK选型

QQ机器人现在有几条路可以走:一是官方开放平台提供的机器人接口,也就是q.qq.com这个后台能申请到的能力,基于WebSocket或Webhook接收事件,官方直接维护,稳定性有保障;二是第三方协议库,通过模拟客户端登录的方式去收发消息,这种方式能做更多"野"操作,但协议是逆向出来的,随时可能失效,账号也有风控风险,我不建议大家拿自己大号去试;三是走企业微信或者群机器人的Webhook,这个适合内部通知,但你没法接收群里的消息,只能单向推,不符合我们"对话式"的需求。

我最终选的是官方开放平台,因为从2023年开始QQ官方对机器人生态支持力度明显加大,Python SDK维护也跟得上,文档虽然还有糙的地方,但至少能跑通全流程。SDK方面,官方提供了 qq-botpy 这个Python包,在PyPI上可以直接装,它把鉴权、WebSocket长连接、事件分发这些都封装好了,我们只需要继承客户端类、重写事件回调方法,然后把自己的业务逻辑填进去就行。

这里我要特别强调一下WebSocket长连接和Webhook回调这两种模式的区别。长连接是机器人主动和服务器保持一个TCP连接,服务器有事件就通过这个连接推给你,优点是实时性好、不需要公网IP,本地开发就能直接跑;Webhook是你在后台配一个公网URL,服务器有事件就POST到这个地址上,优点是程序随便用什么语言写都行,但你必须有一台能被外网访问的服务器,并且要处理签名验证和重试逻辑。对于个人开发者和大多数中小企业来说,本地开发和初期测试阶段用WebSocket模式会舒服得多,这也是 qq-botpy 默认支持的模式。

SDK选型定下来之后,还有一个细节要提前想清楚:消息事件里区分"@机器人消息"和"群内全量消息"。前者是只有群成员在消息里@了你的机器人才会触发,权限门槛低,默认就能用;后者是机器人能监听到群里所有人的所有消息,需要额外申请权限。第一版建议先用@触发,既满足大部分场景,又不至于在权限审核上卡太久。

2. 动手前的准备工作:账号、权限与开发环境

2.1 QQ开放平台注册与开发者认证

开发QQ机器人第一步不是写代码,而是去QQ开放平台(q.qq.com)注册一个开发者账号。这个流程比我预想的要繁琐一点,需要走实名认证环节。QQ开放平台是并入腾讯整体开发者体系的,注册的时候会让你选择用QQ登录还是微信登录,然后补全身份信息。个人开发者和企业开发者的权限是不一样的,个人能创建的机器人和能申请的能力范围都有限,但做群聊机器人绰绰有余。

注册完之后,在控制台里找到"机器人"或者"应用"一栏,创建一个新应用。这里有个很容易搞混的点:应用和机器人是两个概念。应用是你的开发者账号下的一个容器,里面可以配置各种能力;机器人才是实际在群里说话的那个"人"。创建应用的时候要填应用名称、简介、Logo这些信息,审核不算严,但名称不能带夸张的营销词汇,我见过有人起名叫"全网最强机器人"被驳回的,改成中性一点的"小助手"就过了。

应用创建成功后,进到应用详情页,找到"添加能力"或者"添加机器人"按钮,把机器人能力加进去。这一步之后你会拿到两个关键凭证:AppID和AppSecret。AppID是公开的,相当于机器人的身份证号;AppSecret是密钥,相当于密码,绝对不能泄露到GitHub或者任何公开渠道,否则别人可以拿着你的密钥冒充你的机器人发消息。拿到凭证之后,建议立刻把它写进本地环境变量或者配置环境文件里,别硬编码在代码中,这个习惯越早养成越好。

2.2 机器人配置:开启群聊能力和沙箱环境

拿到AppID和AppSecret之后,还不能马上开发,你需要到机器人的配置页面里把"群聊"这个能力打开。我一开始没注意这个开关,代码写完了发现怎么都收不到群消息,排查了半天才发现是能力没开通。在机器人的功能配置页面里,一般会有"消息接收方式"、"事件订阅"几块,你需要把"群@机器人消息"和"群消息"这两个事件订阅勾上,如果后面积分、签到功能需要监听成员变动,再把对应的成员事件也订阅了。

这里必须聊一下沙箱环境。QQ开放平台的机器人在正式发布之前有一个沙箱机制,也就是说机器人不会对全网用户可见,只有你在后台配置的"测试群"里的成员才能跟它互动。沙箱配置页面会让你添加测试群,操作上通常是把机器人的一个二维码或者链接发给你要测试的群,群主或者管理员确认后,机器人就被拉进群里了。这里有个经验:测试群一定不要用自己的大号工作群,因为沙箱阶段机器人行为不可控,代码里如果有bug可能会刷屏,找个拉几个小号建的临时群最稳妥。

配置完成之后,后台会显示沙箱环境和正式环境两个入口。沙箱环境的AppID和AppSecret跟正式环境是同一套,但会额外给一个Token,用于回调模式验证。我们走WebSocket长连接,Token暂时用不上,但建议也存好,万一以后切换模式或者调试的时候能用到。这块配置完,开发环境就具备了一半条件,剩下的是把Python环境搭起来。

2.3 Python虚拟环境与SDK安装

Python版本方面,建议使用3.9或者3.10。 qq-botpy 依赖了新版pydantic和一些异步库,Python 3.8以下可能会出现兼容性问题。我用的是3.10,跑得很稳。如果你机器上有多个Python版本,强烈建议用虚拟环境隔离,别把全局环境搞乱了。

创建虚拟环境的命令很简单:

python3 -m venv qqbot_env
source qqbot_env/bin/activate  # Windows下用 qqbot_env\Scripts\activate
pip install --upgrade pip

然后安装官方SDK:

pip install qq-botpy

装完之后可以验证一下版本:

pip show qq-botpy
python -c "import botpy; print(botpy.__version__)"

如果导入没有报错,依赖就算装好了。这里我想多说一句:SDK的包名是 qq-botpy ,但导入名是 botpy ,按 botpy 导入,别搞混了。我第一次写的时候对着文档看到 import botpy 还以为是装错了包,后来查了一下才发现就是这样的设计。

开发工具方面,VSCode加上Python插件就够了。调试的时候要注意,因为 qq-botpy 是异步框架,断点打在一个异步回调函数里是没问题的,但如果打在初始化代码里,要小心事件循环已经跑起来了,不要用阻塞式的 input() 之类的操作,否则会卡住整个进程。

3. 核心代码实现:从鉴权到消息回复

3.1 初始化客户端:理解鉴权与事件循环

官方SDK的设计思路很简洁:你创建一个继承 botpy.Client 的子类,在子类里重写事件处理方法,然后调用 run 方法启动。启动之后SDK会自动完成AppID和AppSecret的鉴权,走WebSocket连上QQ开放平台的消息服务器,然后一直监听事件。

最基础的代码长这样:

import botpy
from botpy.message import GroupMessage

class MyBot(botpy.Client):
    async def on_group_at_message_create(self, message: GroupMessage):
        # 在这里处理群聊@消息
        await message.reply(content="你好,我是机器人,收到指令了。")

if __name__ == "__main__":
    intents = botpy.Intents(group_messages=True)
    client = MyBot(intents=intents)
    client.run(appid="你的AppID", secret="你的AppSecret")

intents 这个参数容易被人忽略,但它很关键。它决定了你的机器人要订阅哪些类型的事件,把 group_messages=True 打开,才能收到群聊消息事件。如果你后面要处理C2C单聊消息,还需要把 c2c_messages=True 加上。SDK会根据你传入的intents去跟服务器协商订阅关系,少传了某个事件,后台对应的事件就推不过来。

鉴权这块SDK内部已经处理得很完善了,它会自动从开放平台获取access_token,并在过期前自动刷新。我们基本不需要自己动手维护Token。不过有一个细节值得知道:如果你的配置里开启了沙箱环境,SDK在连接的时候可能需要额外传一个token参数。我在实际项目中遇到过一次"鉴权失败"的报错,排查到最后发现是后台沙箱Token被重置了,更新一下配置就好。

3.2 消息事件处理:解析内容与权限校验

on_group_at_message_create 这个回调函数里, message 参数就是一个 GroupMessage 对象,它封装了这条消息的全部信息。常用的属性包括:

  • message.id :消息ID,回复的时候要用到
  • message.content :消息的文本内容,注意这里会包含@机器人的部分
  • message.group_openid :群的OpenID,是机器人视角下这个群的唯一标识
  • message.author :发送者的信息,里面有 member_openid

关于 content 有个很坑的点:当群成员@机器人时, content 字段里会包含一个类似 <@!机器人openid> 的XML标签或者字符串形式。如果拿这个字符串直接去做关键词匹配,经常匹配不上。我自己的处理习惯是先把content里所有 <...> 标签去掉,再做指令解析,这样兼容性最好是:

import re

def clean_content(content: str) -> str:
    # 去掉 @ 机器人的部分
    content = re.sub(r'<@!?\w+>', '', content).strip()
    return content

指令解析我推荐用最朴素的 startswith 前缀匹配。比如机器人支持"天气"和"新闻"两个指令,就判断处理后的content是不是以"天气"开头,如果是,把后面的城市名取出来。不要第一版就上什么插件框架、模糊匹配,先把主流程跑通,后面再迭代。

权限校验这一块很容易被忽视。群聊机器人在沙箱环境里只有测试群的成员能用,但一旦上线,整个QQ里的群都有可能把你拉进去,这时候如果机器人没有权限管控,任何群成员都能触发"踢人"这类高危指令,后果不堪设想。我自己的做法是维护一个管理员白名单,在消息处理开头先判断 message.author.member_openid 是否在名单里,不在就直接忽略高危指令。

3.3 回复消息与调用外部API

回复消息的方式有两种。一种最简单,直接用 message.reply(content="xxx") ,SDK会自动帮你回传到对应群和对应消息上下文。另一种是主动调用 post_group_message 接口,需要自己传 group_openid 和 msg_id ,灵活性更强,适合在你已经缓存了群信息、想主动推消息(比如定时任务)的时候用。

# 方式一:直接回复(推荐)
await message.reply(content="查询结果:今天晴,26到32摄氏度。")

# 方式二:主动推送
await self.api.post_group_message(
    group_openid=group_openid,
    msg_type=0,
    content="这是主动推送的消息",
    msg_id=message.id
)

对于 post_group_message ,要特别留意 msg_type 参数。0表示文本,2表示图片,后面如果要发卡片或者富文本,对应的类型值不一样。第一版建议先用文本消息跑通,后续扩展图片、Markdown卡片的时候再查阅文档。

调用外部API是群聊机器人最常见的增强功能。比如对接一个天气接口:

import aiohttp

async def fetch_weather(city: str) -> str:
    url = f"https://api.example.com/weather?city={city}"
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            data = await resp.json()
            temp = data["current"]["temp"]
            desc = data["current"]["text"]
            return f"{city}当前{temp}度,{desc}"

然后在消息处理函数里调用它:

async def on_group_at_message_create(self, message: GroupMessage):
    content = clean_content(message.content)
    if content.startswith("天气"):
        city = content[2:].strip() or "北京"
        result = await fetch_weather(city)
        await message.reply(content=result)

注意 fetch_weather 必须写成异步函数,因为整个 qq-botpy 框架是跑在事件循环里的,如果你在回调里用了阻塞式的 requests.get ,整个事件循环会被卡住,机器人在那几秒内对任何群消息都没有反应。我见过有人部署后反应"机器人老是延迟回复",看一下日志发现是同步HTTP请求阻塞了事件循环,换成 aiohttp 之后问题立刻消失。

3.4 组装一个可运行的完整示例

把上面的思路拼起来,一个能跑的机器人骨架大概长这样:

import re
import botpy
import aiohttp
from botpy.message import GroupMessage

ADMIN_OPENIDS = {"这里填你的管理员openid"}

class GroupBot(botpy.Client):
    async def on_group_at_message_create(self, message: GroupMessage):
        try:
            content = re.sub(r"<@!?\w+>", "", message.content).strip()
            if not content:
                return

            if content.startswith("你好"):
                await message.reply(content="你好呀,我是群助手,有事请叫我。")
                return

            if content.startswith("天气"):
                city = content[2:].strip() or "北京"
                await message.reply(content=f"正在查询{city}的天气...")
                weather = await self._fetch_weather(city)
                await message.reply(content=weather)
                return

            # 管理员指令示例:踢人
            if content.startswith("踢人") and message.author.member_openid in ADMIN_OPENIDS:
                # 调用平台禁言/移除接口
                await message.reply(content="收到管理员指令,正在处理。")
                return

            await message.reply(content="未识别的指令,试试:你好 / 天气+城市")
        except Exception as e:
            print(f"处理消息异常: {e}")
            try:
                await message.reply(content="服务开小差了,过会儿再试试。")
            except Exception:
                pass

    async def _fetch_weather(self, city: str) -> str:
        url = f"https://api.example.com/weather?city={city}"
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as resp:
                data = await resp.json()
                return f"{city}当前{data['current']['temp']}度,{data['current']['text']}"

if __name__ == "__main__":
    intents = botpy.Intents(group_messages=True)
    client = GroupBot(intents=intents)
    client.run(appid="你的AppID", secret="你的AppSecret")

这个版本已经能处理基本的"你好"问候和天气查询了,消息异常都有兜底,不会因为一条消息报错导致整个进程崩溃。实际做的时候我会建议再加一个日志模块,把收到的每条消息和回复都记录下来,后面调bug会轻松很多。

4. 本地调试、上线部署与常见问题速查

4.1 本地调试技巧:日志是关键

本地开发最大的优势是能看到实时日志。 qq-botpy 底层用的是Python标准库logging,默认日志级别是INFO,会输出连接状态、事件接收情况等信息。开发的时候建议把日志级别调到DEBUG,能看到更详细的协议交互:

import logging
logging.basicConfig(level=logging.DEBUG)

这个改动在排错的时候价值巨大。比如你发现机器人收不到群消息,打开DEBUG日志后能看到WebSocket连接是否建立、有没有心跳包、事件推送到哪一步被过滤掉了。我遇到过一次消息推过来了但代码里没反应,看日志发现事件是收到了,但intents配置里没打开群消息类型,SDK在分发的时候就给拦掉了,这个用肉眼根本看不出来,必须靠日志。

另外一个调试技巧是用Python自带的 asyncio 调试模式。如果怀疑代码里有协程没被正确await,可以在启动时加 asyncio.run(main(), debug=True) ,事件循环会打印出未等待的协程警告。很多时候"机器人静默无响应"就是因为在回调里调了异步函数但忘了加await,函数返回一个协程对象之后就被丢弃了,既没执行也没报错。

本地调试时推荐用 --reload 思路的自动重启脚本,或者简单粗暴用 watchdog 监控代码目录,文件一变就自动重启进程。这不是必须的,但能省掉很多手动重启的时间。等你把代码逻辑测稳了,再考虑部署到服务器上常驻运行。

4.2 部署方案:从nohup到systemd的完整选择

本地开发没问题之后,就要把机器人放到服务器上跑了。选服务器没什么特别的,国内主流云厂商的轻量应用服务器即可,1核2G就足够跑一个机器人进程了,系统选Ubuntu 22.04或者Debian 12都行,CentOS也可用但生态不如Ubuntu方便。

部署方式按复杂度排序有三种:最快的是 nohup 直接挂着跑,适合临时测试;靠谱一点的是用 screen 或者 tmux 会话跑,断开了也能重新连回去看日志;最正规的是写一个systemd服务,让机器人开机自启、崩溃自动重启、日志统一收集。我自己的生产环境用的是systemd方案,写一个服务文件:

[Unit]
Description=QQ Group Bot
After=network-online.target

[Service]
User=www-data
WorkingDirectory=/opt/qqbot
ExecStart=/opt/qqbot/qqbot_env/bin/python main.py
Restart=always
RestartSec=3
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target

将文件放到 /etc/systemd/system/qqbot.service ,然后:

sudo systemctl daemon-reload
sudo systemctl enable qqbot
sudo systemctl start qqbot

用systemd的好处是机器人进程万一因为网络波动崩溃了,最多3秒就能自动拉起来,不需要你半夜爬起来手动重启。日志用 journalctl -u qqbot -f 随时看,排错体验比nohup输出到文件再tail好得多。

不管用哪种方式部署,都要注意服务器上的Python环境和本地保持一致,最好也用虚拟环境隔离。代码同步我建议直接用git,服务器上git pull就行,别用ftp一个一个文件传,传漏了很难排查。

4.3 高频踩坑:事件收不到、消息发不出、进程被暗杀

开发过程中踩过的坑大概是所有新手都会遇到的,我整理了一个速查表,按出现频率从高到低排:

现象 可能原因 解决办法
机器人收不到任何群消息 未勾选事件订阅或intents未开启 检查后台"事件订阅"里的群消息开关,检查intents传参
消息收到了但代码没反应 忘了await异步函数 检查是不是返回了协程对象,加上await
回复报"开放平台错误" AppSecret错误或沙箱Token失效 核对AppID/AppSecret,在后台重置沙箱Token
机器人时灵时不灵 事件循环被阻塞 检查是否有同步HTTP调用,全部换成aiohttp
刚启动能跑,一会就断线 服务器没有外网网络或者遭遇长连接保护 检查WebSocket心跳日志,确认SDK版本是否为最新
上线后普通群用不了 还在沙箱环境,审批未通过 后台提交审核,等待正式发布

这里面我想重点展开"事件订阅"这个坑。后台的配置页面里,事件订阅和数据权限是分开两个页面,很容易只看到"数据权限"里的群聊勾选,但没注意到"事件订阅"里的群消息开关是关着的。SDK的intents只是客户端声明"我想收什么",但服务端那边的开关没打开,消息根本推不过来,这俩是"与"的关系,缺一个都收不到。

还有一个容易被忽视的问题是SDK版本旧了之后,服务端可能逐渐不兼容旧协议。坚持用官方最新版本,升级前看下release note,防止某次升级把接口名改了。我升级过一个大版本, on_group_at_message_create 这种签名没变,但内部 api.post_group_message 的参数名变了,升级后有一段代码直接报TypeError,这种问题不看文档根本想不到。

5. 进阶功能设计与后期维护经验

5.1 从玩具到工具:功能模块化与状态管理

消息回复跑通之后,下一个自然的问题是怎么把机器人从"玩具"升级成"工具"。我的建议是尽早做模块化:把指令处理和具体业务解耦。一种简单的做法是建一个指令路由表,把"指令前缀"映射到"处理函数":

COMMAND_HANDLERS = {
    "天气": handle_weather,
    "新闻": handle_news,
    "签到": handle_signin,
    "帮助": handle_help,
}

每个 handle_xxx 都是一个接收 message 参数的异步函数,返回要发送的文本。这样新增一个功能只需要写一个函数、加一行路由注册,改旧功能也不会牵连到别的指令。我做机器人第二周就把这个路由机制上了,后续加功能舒服得多。

另外要尽早考虑状态管理。签到、积分、抽奖这类功能需要持久化数据,不能存内存里,进程一重启就全没了。轻量场景用SQLite就够,加一个 sqlite3 的封装,往命令处理器里注入一个db对象。重量级场景再考虑MySQL或者Redis。我自己的机器人用SQLite存了群配置和用户积分,跑了几个月没出过问题。

定时任务这块也是群聊机器人的高频需求。比如每天早上8点往固定群推送"今日新闻"。 qq-botpy 本身不提供cron能力,需要你自己在进程里跑一个异步定时器。我用的方案是 asyncio 自带的 loop.create_task 配合while循环加 asyncio.sleep ,每天算好距离目标时间点还有多少秒然后sleep。注意如果机器人进程重启了,定时任务要从头开始算时间,最好把上一次执行日期存一下,防止重复推送。

5.2 维护期避坑与合规提醒

机器人上线后,维护期有一些很容易踩的坑,我按重要性排一下:

第一,注意平台的风控和频率限制。群聊接口对单条消息长度、每分钟消息条数都有隐式限制。你写了个循环给群成员逐个发消息,发到一半触发了限制,接口直接拒绝,后续一段时间可能都被禁。我建议所有主动推送都加一个简单的令牌桶限流,每秒钟最多发一条,宁慢勿快。

第二,敏感内容的过滤一定要做好。群里用户发什么你管不着,但机器人如果回复了违规内容,责任落在开发者头上。接入一个简单的违禁词表,命中就回一句"我不能聊这个"或直接忽略。如果机器人接了大模型API,用户可能用提示词注入试图让机器人说出违规内容,这种情况也要在回复层再做一次过滤。

第三,账号安全是底线。AppSecret泄露是最危险的,一旦泄露,立即去后台重置。我还习惯把开发和生产的Secret分开,开发环境用一个测试应用,上线用一个正式应用,各用各的密钥,互不影响。Git提交前检查一下有没有把配置文件和历史记录里的密钥漏出去,这个真出过事的。

第四,微信群聊机器人不是本文讨论的QQ平台内容,网上有些用企业微信接口私搭群机器人的方案,接口形态、鉴权方式完全不同,不要拿QQ的思路直接套到微信生态上,会撞一脸灰。要做微信方向的,去研究微信官方提供的群机器人或企业微信机器人文档,别走野路子。

5.3 后续可以怎么扩展

一个稳定的QQ群聊机器人框架跑起来之后,想扩展的玩法非常多。我列几个我做过或者看到别人做过的方向:

  • 接入大模型的对话能力,让机器人在群里变成一个闲聊AI,这个是目前最热的方向,也是用户感知最强的功能。注意做好上下文长度控制和敏感内容过滤。
  • 做群内小游戏,比如猜数字、接龙、成语填空,基于状态管理做一个简单的房间机制就能撑起来。
  • 订阅类提醒,把微博、B站、公众号的动态更新轮询一下,有更新就推到群里,相当于给群做一个消息聚合器。
  • 群数据统计,记录群成员的发言频次、活跃时段,每天生成一个简单的日报,这个对头部用户运营很有价值。
  • 接语音识别和图片识别,利用QQ平台的多模态消息接口,做签到拍照、图片审核之类的功能。

但不管往哪个方向扩,有一条主线不能丢:先保证核心收发稳定,再谈加功能。很多人的机器人一开始加了一堆花哨功能,结果基础消息处理没做好,群友用起来体验很差,最后项目就黄了。我自己的原则是每加一个功能前先问一句:如果这个功能挂了,会不会影响已有功能?会,那就先做隔离设计再接进去。

我个人这几个月跑下来的体会是,做群聊机器人最值钱的不是那点代码,而是你真正理解了异步编程和事件驱动是怎么在真实场景里工作的。一开始觉得 async/await 理论学了不少,但实际写一个长连接机器人,把事件循环卡死的问题修了一遍之后,再去写别的网络服务,思路完全不一样了。最后分享一个实用小技巧:在线上的机器人代码里,每一个消息处理函数的入口和出口都打一条带耗时统计的日志,时间久了你会突然发现,原来有那么多群的调用时间分布规律可以用来看群活跃度,这个数据比任何功能都好玩。

更多推荐