简介这是一套基于服务器或虚拟主机运行的QQ云端免挂机器人发信API资源面向需要实现24小时自动发信、减少本地挂机依赖的服务器管理者和轻量自动化开发者。整套资源共11个文件压缩包仅42KB以6个PHP接口文件为主配合txt说明文档、菜单配置、CSS样式及指定回复规则基本覆盖API部署、参数配置与基础回复逻辑已有205人学习下载。资源包含可运行的PHP源码、必看说明与使用教程用户上传解压并按文档配置接入点、接收方、发送频率和身份验证信息后即可在云端持续监听并发送QQ消息适合自动回复、定时通知等长时在线场景。目前功能偏向单一发信但胜在轻量易部署可作为二次开发基础按需扩展图片/文件发送、关键词触发或与其他服务集成。下载包内目录简洁文件用途明确适合具备基础服务器管理经验的用户快速上手。1. 云端免挂的 QQ 智能机器人一条消息发出去背后到底有没有人很多团队和开发者第一次听说「QQ云端免挂智能机器人云端发信API」这个标题时会下意识把它拆成三件事免挂、智能机器人、API。真实场景里它们是一个整体——把个人 QQ 账号的收消息、回消息能力搬进云服务器让一个常驻进程以「机器人」身份在群里聊天对外暴露的则是一套 HTTP/WebSocket 接口任何业务系统都能调用它去发私聊、发群聊、发图片和回复消息。这套方案解决的核心问题只有一个让账号不依赖本地电脑不依赖手机常亮机器人长期在线。常见做法是用开源协议端模拟客户端登录把事件流通过 WebSocket 推给后端服务后端再拼装消息内容走 API 把结果发出去。适合手里没有官方机器人接口资质又需要在多个群、多个账号上做自动化回复的个人开发者和中小团队。我自己前前后后搭过三轮类似的系统从早期 Windows 机上挂一个壳、每天醒来发现掉线到后来整个链路放在 Linux 轻量服务器上连续运行两个月不用碰。这篇文章会把整个落地方案按顺序拆开架构怎么分、登录和发信怎么通、智能回复怎么接、以及最容易翻车的那几个点。2. 拆开「免挂 发信 API」协议端、事件流与云端发信怎么分工2.1 免挂到底免的是什么把本地挂机挪进云端服务「免挂」这个词源自早期聊天机器人必须有一台电脑或一部手机挂着 QQ一旦锁屏、断网、换机机器人就消失。云端免挂的本质是把客户端跑在数据中心的一台 Linux 机器上通过设备协议直接与服务端通信不依赖完整图形界面。这里面最关键的一个概念叫协议端。它做的工作是代替官方客户端完成登录、心跳、收发消息和维持长连接对外它把消息这种「事件」抽象成标准 JSON把「发消息」这种操作抽象成接口。你可以把它理解成一个无头版的 QQ 客户端没有聊天窗口只有 stdin/stdout 般的消息流。我习惯把系统拆成三个角色协议端维持账号在线收发消息暴露事件和操作接口智能服务订阅事件流把收到的消息清洗、拼 prompt、调大模型或自研策略决定回什么发信通道调用协议端暴露的发信 API把回复投递到群或好友。如果一个机器人只是做告警通知不需要智能那么协议端加发信 API 就够用如果要做智能问答、群管理、关键词回复就必须把「智能服务」放在协议端和发信 API 之间。注意别把智能逻辑直接堆在协议端里更不要在事件回调解里同步调用大模型接口否则一次慢请求会让整个发送队列堵死。2.2 事件与发信单向通知容易做回信要拿到会话令牌很多人第一次调通协议端后会卡在一个问题上我能收到群里有人发言但不知道怎么回过去。这里要分清两个方向入站是事件推送。协议端收到新消息后把消息体、发送者、群号、时间戳打包成一个 JSON 事件通过 WebSocket 或 HTTP 回调推给你的服务。它的方向是协议端到业务服务只读。出站是动作调用。你的服务要发消息必须向协议端发起一次 API 请求携带目标类型、目标 ID、消息内容甚至可以是图片、语音。它的方向是业务服务到协议端。这两个方向走的是不同端口、不同连接所以你会看到协议端同时开着 HTTP 端口和 WebSocket 端口。理解这一层后最常见的误解就消失了不是「我收到消息后直接在回调里 return 一句」而是你在回调里触发一次 HTTP 调用把要回复的话交给发信 API。消息 ID 在入站时已经生成出站时也可以拿到新消息的 ID这两套 ID 体系用于做去重和追踪。2.3 选型对比开源协议端与 API 服务的组合怎么选标题里的「云端发信 API」并不是一个现成的商业服务它是一层你自己封装的东西。最省事的做法是选一个开源协议端把它的 HTTP 接口直接当作发信 API 用再在外面套一层你自己的鉴权和限流。我对比过常见方案方案登录方式出站接口事件推送适合场景官方机器人平台平台审核HTTP 接口回调有资质的正式机器人禁个人号开源协议端 ALinux 容器化方案扫码/快速登录兼容 OneBot 11WebSocket/反向 WS个人号、多账号、云端部署开源协议端 B跨平台框架扫码自研 APIWebSocket单号轻量自用自研 Mini 客户端协议逆向无无不推荐维护成本极高我一般推荐第一款开源方案跑在 Docker 里因为它把 Linux 底层的登录、依赖和会话文件都打包好了你只需要管理配置。底层是 OneBot 11 协议这是目前大多数机器人框架通用的 JSON 协议资料多踩坑也能查到。还有两个容易被忽视的选型点一是协议端必须支持扫码登录后快速登录复用会话否则云端重启一次就要重新扫码二是它的 HTTP 接口必须支持自定义鉴权头否则发信接口裸奔在公网上等于把账号交出去。3. 在云服务器跑通最小发信链路安装、登录、投递第一条消息3.1 准备一台能长期连网的轻量机器规格与网络要求云端免挂有一个硬性前提服务器必须能访问腾讯服务的消息通道。这意味着你在本地搭建时一切正常换成某些网络隔离环境后可能无法登录。我建议用一台国内或中国港澳台的常规云主机带宽不需要高1M 都够因为聊天消息量远小于网页流量。硬件规格上一个账号占用的内存和 CPU 非常低。我自己的经验是单账号 1 核 1G 内存足够跑 3 到 5 个账号2 核 2G 也宽松。真正占用资源的是你后续接入的智能模型客户端因为大模型接口往往是外发的 HTTP 调用内存不大但网络延迟影响大。系统选 Debian 12 或 Ubuntu 22.04 都可以Docker 是必须装的因为协议端依赖特定运行环境。写代码和跑智能服务时再单独起一个容器或直接在宿主机装 Python 3.10。我有一个习惯协议端和业务服务永远分开目录和容器方便单独重启。3.2 拉起无头协议端一条命令启动扫码完成登录先给协议端建一个工作目录把配置和会话数据放在宿主机这样容器升级或重启后登录态还在。下面是我常用的启动命令mkdir -p ~/napcat/config cd ~/napcat docker run -d \ --name napcat \ --restartalways \ --network host \ -e NAPCAT_UID$(id -u) \ -e NAPCAT_GID$(id -g) \ -v ~/napcat/config:/app/config \ docker.napcat.dev/napcat/napcat:latest这段命令里几个参数值得单独说--network host让容器直接复用宿主机网络协议端的端口监听在宿主机上避免 Docker 端口映射的额外复杂度NAPCAT_UID和NAPCAT_GID用当前用户运行防止挂载目录下生成 root 归属的文件后面维护会方便很多。--restartalways是免挂的命脉服务器重启后容器自动拉起来不需要人干预。启动后从容器日志里找到管理面板的访问地址和端口。常见做法是打开http://服务器IP:6099/webui进入管理界面账号密码在首次启动日志中给出。进入后选择「扫码登录」用手机 QQ 扫二维码这一步会把登录态写入配置目录。3.3 打开云端发信 API配置 HTTP 端口与访问令牌登录成功后协议端管理面板里会有一项「网络配置」这里就是云端发信 API 的开关。你需要开启 HTTP 服务器设置端口和鉴权令牌。令牌是一串自定义字符所有外部调用都要带这个令牌相当于这个 API 的钥匙。有一处细节要提醒有些版本默认监听 127.0.0.1云端环境里如果你要从另一台机器访问需要把监听地址改成 0.0.0.0。改了之后防火墙和安全组把该端口放通。为了安全端口不要用默认的 3000改成高位随机端口比如 18080。配置完成后协议端会生成一段连接信息内容类似下面这样HTTP 服务器地址: http://0.0.0.0:18080 HTTP 访问令牌: your-secret-token WebSocket 服务器地址: ws://0.0.0.0:3001 WebSocket 访问令牌: your-secret-token现在这套运行环境已经具备两个基本能力WebSocket 用来向你的服务推送新消息事件HTTP 端口用来接收发信指令。两个端口共用一个令牌也可以分别设置。建议把它们保存在独立配置文件中不要写死在代码里。3.4 用 curl 验证 API 可用收到回执才算数配置完成后先用命令行确认发信链路通不通。找一个测试群执行下面的请求curl -X POST http://127.0.0.1:18080/Http_api \ -H Authorization: Bearer your-secret-token \ -H Content-Type: application/json \ -d { action: send_msg, params: { message_type: group, group_id: 6789012345, message: hello from cloud api } }正常情况下返回的 JSON 里会包含status: ok和消息的message_id这个 ID 就是这条消息在全链路中的凭证。如果返回retcode: 100这类错误通常是发送失败需要在第 5 章排查。拿到回执后我会再做一步把message_id存到本地然后去群里看一眼内容和发送者确认是账号自己发出的。这一步排除了「接口通了但实际没发出去」的假阳性。到这里云端发信 API 的最小闭环已经成立。4. 给机器人接上「智能」事件订阅、AI 回复与 API 封装4.1 订阅群消息与私聊事件WebSocket 事件包长什么样现在协议端已经能发消息但机器人还不能自己知道该什么时候发。这需要订阅事件流。协议端的 WebSocket 接口会持续推送消息事件事件包是一个标准 JSON。一条群消息通常长这样{ post_type: message, message_type: group, group_id: 6789012345, user_id: 1234567890, message_id: -123456789, message: [ { type: text, data: { text: 你好 } }, { type: at, data: { qq: 10001 } } ], raw_message: [CQ:at,qq10001]你好 }关键字段就四个post_type用来判断是消息还是通知message_type区分群和私聊message是消息段的数组里面的 text 段就是文本内容user_id是发言者。注意不要直接用raw_message里的 CQ 码去处理文本那种格式是给老的发送接口用的解析容易踩坑。写一个最简订阅程序验证事件能推到你的代码里import asyncio import json import websockets WS_URL ws://127.0.0.1:3001 TOKEN your-secret-token async def listen(): async with websockets.connect( WS_URL, additional_headers{Authorization: fBearer {TOKEN}} ) as ws: print(事件通道已连接) async for raw in ws: event json.loads(raw) if event.get(post_type) message: msg event.get(raw_message, ) print( f{event.get(message_type)} f{event.get(user_id)}: {msg} ) asyncio.run(listen())这段代码的逻辑说明async for raw in ws会持续收到协议端推送的每个事件不需要你主动轮询。post_type message过滤掉加群、退群、撤回等系统通知。如果连接被断开async for会抛异常退出实际生产代码里要套一个 while True 重连逻辑后面章节再展开。4.2 把消息交给智能模型再发出去一个最小可用的 Python 服务订阅通了之后把「收到消息」和「发送消息」串起来。最简洁的方式是收到消息后调一个大模型 API 生成回复再调用协议端 HTTP 接口发出去。以下是一个可直接跑的完整服务骨架import asyncio import json import re import httpx import websockets NAPCAT_API http://127.0.0.1:18080/Http_api NAPCAT_TOKEN your-secret-token LLM_API https://api.deepseek.com/chat/completions LLM_KEY sk-your-key def parse_text(message_segments): parts [] for seg in message_segments: if seg.get(type) text: parts.append(seg[data].get(text, )) elif seg.get(type) at: qq seg[data].get(qq) if qq: parts.append(f{qq}) return .join(parts) async def generate_reply(text: str) - str: prompt f你是一个群聊机器人请用简短的中文回答{text} async with httpx.AsyncClient(timeout30) as client: resp await client.post( LLM_API, headers{Authorization: fBearer {LLM_KEY}}, json{ model: deepseek-chat, messages: [{role: user, content: prompt}], temperature: 0.7, }, ) data resp.json() return data[choices][0][message][content] async def send_to_group(group_id: int, reply: str): payload { action: send_msg, params: { message_type: group, group_id: group_id, message: reply, }, } async with httpx.AsyncClient(timeout10) as client: r await client.post( NAPCAT_API, headers{Authorization: fBearer {NAPCAT_TOKEN}}, jsonpayload, ) return r.json() async def main(): while True: try: async with websockets.connect( ws://127.0.0.1:3001, additional_headers{Authorization: fBearer {NAPCAT_TOKEN}} ) as ws: async for raw in ws: event json.loads(raw) if event.get(post_type) ! message: continue segments event.get(message, []) text parse_text(segments) if not text: continue reply await generate_reply(text) if event.get(message_type) group: await send_to_group(event[group_id], reply) else: # 私聊用 send_private_msg pass except Exception as exc: print(连接断开重连中:, exc) await asyncio.sleep(3) asyncio.run(main())这个服务的参数说明parse_text把消息段拼成纯文本顺带保留 at 信息大模型不认识 CQ 码这一步必须做generate_reply调用大模型超时设为 30 秒群聊场景建议把超时降到 15 秒因为用户等太久就失去意义send_to_group复用协议端 HTTPtimeout10保证请求不会一直挂住外层while True是保命逻辑WebSocket 断开后自动重建。注意这版代码是「同步式智能回复」一条消息进来先等大模型再等发送期间后续事件会堆积。对于一个活跃群这是灾难后面第 6 章讲队列化解。4.3 发信 API 的参数细节at、图片、引用回复「发消息」这三个字背后有一堆参数细节。标题里的云端发信 API 如果只封装了文本发送那它是残废的。日常需求至少还包括 at 成员、发图片、引用回复。这三个动作在 OneBot 11 协议里都通过消息段实现也就是message字段不再是字符串而是一个数组。需求message 写法说明发纯文本直接传字符串兼容性最好at 某人[{type:at,data:{qq:12345}}]at 全体是all发本地图片[{type:image,data:{file:/data/pic.jpg}}]文件必须协议端能访问发网络图片[{type:image,data:{file:https://...}}]需要协议端能出网引用回复[{type:reply,data:{id:原消息ID}}]需把原消息 ID 传进去把这些段组合起来就能实现「引用那条消息 at 发送者 回复正文」这是一个群管理机器人最高频的三个动作。我的做法是封装一个build_reply_message函数接收text、reply_id、at_user三个参数返回消息段数组。这样业务层不用关心协议格式。另外要留意file字段是本地路径时路径要写成协议端容器能访问到的路径而不是你服务所在机器的路径。这是新手最常踩的坑服务在宿主机上跑图片放在/tmp/a.jpg协议端在容器里看不见就会发图失败。5. 云端免挂机器人避坑常见故障与排查顺序5.1 扫码过期或 token 失效登录态被挤不重登就静默断线现象机器人连续运行几天后突然不回消息检查协议端 WebSocket 显示已连接但推送事件停了。看日志发现登录态过期页面提示需要重新扫码。原因QQ 服务端会在长时间不发消息、IP 变化、设备信息变化时让登录态失效。这和你用手机挂 QQ 一个道理只是云端环境没有主动交互的界面失效后不容易察觉。解决不要重复扫码那个是最低效的。先在协议端管理页面找到「快速登录」入口它会读取之前保存的会话文件双击即可恢复。如果失效频繁检查服务器出口 IP 是否经常变化固定出口 IP 后登录态会持久很多。另外密码登录现在基本不可用扫码登录后立刻导出会话文件做备份是标准做法。5.2 消息已收到但发不出去能收不能发的 3 个原因现象事件订阅正常机器人在群里被 了也有日志但调用 HTTP 接口返回错误码群里没有任何动静。原因一账号本身被禁言。群里发消息返回错误码120或类似这种情况只能等禁言结束程序无需处理但要记录日志。原因二发送频率过高触发风控。连续多次调用发信 API协议端会拒绝部分请求。这个在代码里必须显式捕获并退避。原因三HTTP 路径不对。一开始我查了半天因为访问根路径返回 404正确路径是/Http_api大小写敏感。这属于协议端的特殊路由设计试一遍马上定位。解决给所有发信请求统一打印返回的status和retcode不要只打印 HTTP 状态码。HTTP 200 不代表发送成功真正的结果在响应体里。5.3 发信 API 偶发超时与重复投递做到幂等要加消息 ID 去重现象日志里看到某条回复发了两次群成员收到两条一模一样的内容有时请求超时报错但群里其实已经发出去。原因发信请求是网络操作响应可能在服务端成功处理、报文回传途中丢失。此时客户端不知道结果会重试一次于是产生重复消息。注意网络烧的是双向的。判断是否重复不能只看业务内容同一个 prompt 可能生成两次相同回复这种情况即便没有超时也会重。解决在业务层维护一个已发送消息的容器发送前生成一个唯一seq把收到的原始消息 ID、目标群、seq 绑定成功后再遇到相同 seq 直接丢弃。不需要额外引入 Redis一个字典配合过期清理在这个场景够用。我习惯把去重逻辑放在发送之前而不是发送之后因为发送后判重挡不住重试窗口。5.4 被风控判定异常频率、内容与设备指纹的三重限制现象账号正常代码正常但发送一段时间后所有接口都返回失败网页端登录也提示环境异常。原因免挂机器人本质上是非官方客户端频率突增和内容模式异常会触发服务端风控。常见触发点包括同一时间大量消息回复内容里频繁出现 URL多个账号在同一台服务器上共用相同 IP消息内容重复率过高。解决有几个实用技巧。每次发送之间加 1 到 3 秒随机延时不要用固定间隔。对所有外发内容做敏感词过滤。多账号运行时尽量给每个账号配置独立的网络入口避免同 IP 大量 QQ 同时在线。还要注意群内主动发言比回复发言更容易触发风控回复类机器人翻车率低于主动推送类。如果已经被临时限制最快恢复手段是停止发送保持在线状态等待数小时到一天。千万不要反复测试接口那会拉长限制时间。6. 让发信 API 更抗造队列削峰、发送前检查与详解可观测性前面第 4 章我特意留了一个尾巴——同步式智能回复会被慢请求卡死。这一个章节把这段补上。可靠做法的核心是引入一个独立的发送队列事件订阅进程只负责把「待回复的消息」放进队列发送 worker 从队列取任务调用大模型最终调用发信 API。这样大模型超时只影响当前任务不会阻塞新消息的事件接收。发送前做一次状态检查也很有必要。调用发信 API 前先问协议端一次get_login_info如果返回的账号 ID 为空说明登录态已丢这时直接跳过本轮回复等待重连完成。不然会出现「大模型已经生成了回复发送时才发现账号掉线」的浪费。可观测这块我会为每条消息打三个日志点收到事件时记录message_id发送请求前记录seq和内容长度发送成功后记录协议端返回的message_id。三组日志串起来结合时间戳能准确说出哪一跳延迟高。有了这套链路再配合 5 分钟内自动重连与 3 次发信重试云端免挂机器人才算真正能丢在服务器上不管。这个方向我前后踩了三次第一次栽在登录态丢失第二次摔在同步式回复把 WebSocket 事件拉垮第三次是因为重复发送被群主提醒才意识到健壮性不够。现在我的原则是「可以慢不要乱」宁可让一条回复晚几秒也绝不让同一条消息发两遍。希望这套思路帮你在做云端发信 API 时把最不该栽的坑避开剩下的迭代阻力就不大了。本文还有配套的精品资源点击获取