OpenClaw 接入 QQ 机器人渠道:从 AppSecret 配置到群聊激活与排查

2026-08-17

想把 OpenClaw 挂到 QQ 上,多数人卡住的地方不是”装不上”,而是装完之后一堆分不清的东西:私聊能发图群里为什么不行、AppSecret 到底放配置文件还是环境变量、群里要不要 @ 才回、/bot-logs 为什么提示没权限。这些在官方文档里都有明确写法,只是分散在好几节。

先说清一件事:QQ Bot 走的是官方 QQ Bot API 的 WebSocket 网关,不是那种扫码登录个人号的方案。它在 OpenClaw 里的状态是「官方可下载插件」,包名 @tencent-connect/openclaw-qqbot,也就是说渠道能力由这个外部包提供,和 OpenClaw 框架本体是两个版本线——后面会看到这个区分会实际咬人。

另一件要先定预期的事,是能力边界。C2C 私聊和群内 @ 提及是主要场景,富媒体(图片、语音、视频、文件)在这两类里可用;频道(Guild channel)消息只支持文本和远程 URL 图片,语音、视频、文件上传、本地文件和 Base64 图片在频道里都用不了。表情回应(reactions)和话题串(threads)则是所有场景都不支持。

三类会话的能力差别

场景目标格式富媒体说明
私聊 C2Cqqbot:c2c:OPENID图片/语音/视频/文件主要场景
群聊qqbot:group:GROUP_OPENID图片/语音/视频/文件@ 提及触发(可配置为不需要)
频道qqbot:channel:CHANNEL_ID仅文本 + 远程 URL 图片无语音/视频/文件上传,无本地或 Base64 图片

这里有个容易踩的坑:每个 bot 有自己一套用户 OpenID。Bot A 收到的 OpenID 不能拿去用 Bot B 发消息。跑多账号的时候如果把 openid 混着用,发送会失败,而不是”发给了别人”。

装插件、拿凭据、加渠道

三步,命令都是固定的。先装插件:

openclaw plugins install @tencent-connect/openclaw-qqbot

再去 QQ 开放平台(q.qq.com)用手机 QQ 扫码注册登录,点「创建机器人」,在机器人设置页拿到 AppID 和 AppSecret。文档专门提醒了一句:AppSecret 不是明文存着的,你如果没保存就离开页面,只能重新生成一个新的。所以拿到手第一时间存进密码管理器,别指望回头再翻。

然后加渠道、重启网关:

openclaw channels add --channel qqbot --token "AppID:AppSecret"

注意 --token 的值是 AppID:AppSecret 拼成的一串,中间冒号分隔,不是只填 secret。如果不想在命令行里敲明文,可以走交互式:

openclaw channels add

向导除了让你手输 AppID/AppSecret,还提供扫码绑定:用绑定了目标 QQ Bot 的手机端扫码完成绑定,OpenClaw 会把拿回来的凭据存到该账号的配置作用域下。

最小配置长这样:

{
  channels: {
    qqbot: {
      enabled: true,
      appId: "YOUR_APP_ID",
      clientSecret: "YOUR_APP_SECRET",
    },
  },
}

AppSecret 的三种存法,以及那个 SecretRef 限制

除了直接写 clientSecret 明文,还有两条路。一是环境变量,但只对顶层默认账号生效:QQBOT_APP_IDQQBOT_CLIENT_SECRET。二是文件挂载:

{
  channels: {
    qqbot: {
      enabled: true,
      appId: "YOUR_APP_ID",
      clientSecretFile: "/path/to/qqbot-secret.txt",
    },
  },
}

clientSecret 本身既接受明文字符串,也接受文件路径(对应 clientSecretFile)。命令行里的 --token-file 只设置 AppSecret,appId 还得靠配置或 QQBOT_APP_ID 提供——这是文档单独列出来的已知混淆点。

真正需要留意的是一条已知限制:外部的 @tencent-connect/openclaw-qqbot不支持结构化的 SecretRef 对象作为 clientSecret。如果你现有配置用的是 SecretRef 那套写法,升级之前得先把密钥挪到 QQBOT_CLIENT_SECRET 环境变量或 clientSecretFile,否则升完就起不来。凭据在 OpenClaw 里的通用存放方式可以参考 密钥与凭据怎么存,QQ Bot 这条是那套通用做法之外的例外。

顺带一提热升级的兜底:如果热升级中断了网关、openclaw.json 还没写完,插件会在下次启动时从内部快照恢复该账号最后已知的 appId / clientSecret(且不会覆盖你有意做的配置修改),所以不用重新扫一遍码。

群聊:谁触发、能用哪些命令、带多少上下文

群支持用的是 QQ 群 OpenID,不是群名称。把 bot 拉进群之后,要么 @ 它,要么把这个群配置成不需要提及。配置结构是 groups 下的通配符默认值加具体群覆盖:

{
  channels: {
    qqbot: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["member_openid"],
      groups: {
        "*": {
          requireMention: true,
          commandLevel: "all",
          historyLimit: 50,
          tools: { deny: ["exec", "read", "write"] },
        },
        GROUP_OPENID: {
          name: "Release room",
          requireMention: false,
          ignoreOtherMentions: true,
          commandLevel: "safety",
          historyLimit: 20,
          prompt: "Keep replies short and operational.",
        },
      },
    },
  },
}

groups["*"] 是所有群的默认值,具体的 groups.GROUP_OPENID 覆盖单个群。各字段和默认值:

字段默认作用
requireMentiontrue回话前是否要求先 @ 机器人
commandLevelall群内可运行哪些内置斜杠命令
ignoreOtherMentionsfalse丢弃只 @ 了别人、没 @ 机器人的消息
historyLimit50保留多少条最近的非提及消息,作为下一次被提及时的上下文;0 关闭历史
tools对整个群做工具的允许/拒绝
toolsBySender按发送者做工具覆盖
nameopenid 前缀日志和群上下文里用的友好标签
prompt内置默认追加到 agent 上下文的本群行为提示

commandLevel 三档的差别值得单独看,这是把”群里能干什么”和”私聊能干什么”切开的主要手段:

级别行为
all现有内置命令保持可用;部分命令在菜单里隐藏,但有权限的人仍能在群里执行
safety群里保留 /help/btw/stop;敏感命令(/config/tools/bash 等)必须去私聊执行
strict只允许严格运行所需的群会话控制;/stop 仍可用,授权发送者可以打断正在跑的任务

激活模式只有 mentionalways 两种,requireMention: true 映射到 mentionfalse 映射到 always。如果存在会话级的激活覆盖,会话级的赢过配置文件。另外,旧的 QQBot toolPolicy 配置项已经废弃,用 openclaw doctor --fix 迁移到 tools

入站队列是按 peer 分的:群 peer 的队列上限比私聊大(50 对 20),队列满时优先淘汰机器人自己发的消息而不是人发的,并且会把一串普通群消息合并成一个带归属的回合。斜杠命令不参与合并,逐条执行。群里多个机器人互相刷屏的一般性防护,见 机器人互相刷屏:bot loop 保护与群消息策略

allowFrom 和斜杠命令的授权是两件事

访问控制这块最容易理解错。allowFrom / groupAllowFrom 决定谁能和 bot 说话,dmPolicy / groupPolicy 决定用哪种执行模式(open / allowlist / disabled)。默认值是动态的:一旦 allowFrom 里出现具体的(非通配符)条目,dmPolicy 默认变成 allowlist,否则是 opengroupPolicy 则在 groupAllowFromallowFrom 任一有具体条目时默认变 allowlist

关键在于:标着「Auth: allowlist」的斜杠命令,要求发送者的 openid 明确出现在非通配符的 allowFrom(群内发起的命令优先看 groupAllowFrom,没有则回落到 allowFrom)里,这跟 dmPolicy / groupPolicy 设成什么无关。写成 allowFrom: ["*"] 只放开了聊天,不放开这些命令。在私聊之外运行、或者没授权,会返回一条提示,而不是静默丢弃。

内置命令表(拦截在进 AI 队列之前):

命令授权范围说明
/bot-ping任意延迟测试
/bot-help任意列出所有命令
/bot-me仅私聊显示发送者的 QQ openid,用来填 allowFrom / groupAllowFrom
/bot-version仅私聊显示框架版本和插件版本
/bot-upgrade仅私聊显示 QQBot 升级指南链接
/bot-approveallowlist仅私聊管理命令执行审批配置
/bot-logsallowlist仅私聊把最近的网关日志导出成文件
/bot-clear-storageallowlist仅私聊删除 QQBot 媒体目录下的缓存下载
/bot-streamingallowlist仅私聊切换 C2C 流式回复
/bot-group-allwaysallowlist仅私聊切换默认群激活模式

任何命令后面加 ? 可以看用法,比如 /bot-upgrade ?/bot-me/bot-version/bot-upgrade 虽然限私聊,但不要求白名单,任何 C2C 发送者都能跑——第一次配置时先让对方在私聊发 /bot-me 拿 openid,是最省事的取值方式。

exec 审批走默认的同聊天回落时,原生审批按钮的点击也遵守同一套非通配符命令白名单。如果只想给某人审批权、不给更大的命令权限,配 channels.qqbot.execApprovals.approvers。原生 exec 审批默认是开启的。

引用消息也算上下文:contextVisibility 控制 QQ 附带过来的引用消息文本,默认 "all" 原样保留;设 "allowlist" 则只有引用消息的发送者通过发送者策略时才带上;"allowlist_quote" 保留显式引用、过滤其他补充上下文。

流式回复与语音

流式相关的两个开关:

{
  channels: {
    qqbot: {
      streaming: {
        mode: "partial", // "partial"(默认)或 "off"
        nativeTransport: true,
      },
    },
  },
}

nativeTransport: true 会让私聊回复走 QQ 官方的 stream_messages 接口,群和频道目标不受影响。老写法 streaming: true|false 标量和 streaming.c2cStreamApi 键可以用 openclaw doctor --fix 迁移到这个新结构。私聊里发 /bot-streaming on|off 改的是同一份配置。

语音走两级配置加优先级回落:STT 先看 channels.qqbot.stt,没有则回落到 tools.media.models[] 里第一个支持音频的条目;TTS 先看 channels.qqbot.ttschannels.qqbot.accounts.<id>.tts,没有则回落到全局 tts。账号级 TTS 用和 tts 相同的结构,深合并到渠道级和全局配置之上;任一层设 enabled: false 可以关掉。STT 请求默认 60 秒超时。

入站的 QQ 语音附件会以音频媒体元数据的形式暴露给 agent,原始语音文件不进通用的 MediaPaths。想让 bot 用语音回话,在纯文本回复里放 [[audio_as_voice]],配置了 TTS 时会合成并发原生 QQ 语音消息。出站音频的上传和转码行为可以用 channels.qqbot.audioFormatPolicy 下的 sttDirectFormatsuploadDirectFormatstranscodeEnabled 调。

媒体存储上,入站、出站、网关桥接三类共用 ~/.openclaw/media/qqbot 这一个负载根目录(设了 OPENCLAW_HOME 时按它走)。私聊和群的富媒体发送走同一条 sendMedia 路径,本地文件和内存缓冲达到 5 MiB 及以上用 QQ 的分片上传接口,更小的以及远程 URL / Base64 来源走一次性上传接口。

网关重启,没处理完的消息会不会丢

这一节文档写得比较硬核,但对生产部署很关键。对 QQ 网关的 turn 事件,OpenClaw 会先把原始事件持久化,再推进已保存的网关 resume 序列号。因此待处理或可重试的 turn 能挺过网关重启,按会话保持串行,并用 provider 的事件 ID 在活跃或保留的完成记录还在时抑制重复入队。

如果持久化写入失败,OpenClaw 会直接掐掉当前网关 socket 且不推进序列号,重连/恢复路径就能把这条未提交的事件再要一次。但要注意:从队列到 agent 这一段的投递语义仍然是至少一次,交接过程中崩溃可能导致一个回合被重放。也就是说,别把”发一条消息就扣一次款”这类不幂等的动作直接挂在 QQ 消息触发上。

多账号

一个 OpenClaw 实例可以跑多个 QQ bot:

{
  channels: {
    qqbot: {
      enabled: true,
      appId: "111111111",
      clientSecret: "secret-of-bot-1",
      accounts: {
        bot2: {
          enabled: true,
          appId: "222222222",
          clientSecret: "secret-of-bot-2",
        },
      },
    },
  },
}

每个账号有独立的 WebSocket 连接、API 客户端和 token 缓存,按 appId 作键;日志行会带上所属账号 id,所以一个网关下跑好几个 bot 时诊断信息还是分得开。用 CLI 加第二个 bot:

openclaw channels add --channel qqbot --account bot2 --token "222222222:secret-of-bot-2"

官方给出的排查项

症状官方说法
网关起不来 / 收不到消息核对 appIdclientSecret,确认 bot 在 QQ 开放平台是启用状态;缺凭据会报「QQBot not configured (missing appId or clientSecret)」
用了 --token-file 还显示未配置--token-file 只设 AppSecret,appId 仍须在配置或 QQBOT_APP_ID
群里回复相撞队列满时优先淘汰机器人自己的消息,普通群消息成批合并为一个回合,人发的消息不至于被机器人刷掉
主动消息发不出去用户近期没有互动时,QQ 可能拦截机器人主动发起的消息
语音没转写确认 STT 已配置且 provider 可达

渠道通用的连不上排查(配对状态、网关侧问题)另见 渠道连不上的官方排查表,接入流程的通用部分见 渠道接入的通用流程与配对机制

什么时候不适合用它,以及文档没覆盖的部分

如果你的场景重度依赖频道(Guild)里的文件分发或语音互动,这条渠道现在做不到——文档明确列了频道只支持文本和远程 URL 图片。依赖表情回应做轻量确认(比如让 bot 用一个表情回应表示已收到)的交互设计也不用考虑,reactions 和 threads 在所有场景都不支持。

需要 bot 主动推送的场景要打个问号:文档只说”用户近期没有互动时 QQ 可能拦截主动消息”,具体的时间窗口和判定规则没有写,也不是 OpenClaw 这边能控制的。把定时播报做在 QQ 上之前,最好先按自己的实际用量验证一遍。

还有几个点文档没给数值,别自己脑补:分片上传的 5 MiB 只是走哪条上传接口的分界,单文件大小上限文档没写;群队列 50 / 私聊 20 是队列条目数而不是速率限制;historyLimit 默认 50 指的是保留的消息条数,不涉及 token 预算。真要压测这些边界,得自己跑。

最后一条运维提醒:这个渠道由外部插件提供,插件版本和框架版本是分开的。升级前先在私聊跑 /bot-version 记下两个版本号,出问题时至少知道动的是哪一边;配置里如果还留着 toolPolicy 或老的 streaming 标量写法,先用 openclaw doctor --fix 迁移完再升。

延伸阅读


本文依据 OpenClaw 官方仓库(github.com/openclaw/openclawdocs/ 下的官方文档整理,核对日 2026-08-17。 我们没有安装或运行过 OpenClaw,因此不涉及界面外观、操作手感与实测耗时的任何描述; 文中的默认值、命令与配置项均为文档口径,不构成对实际运行结果的保证。 该项目迭代很快,请以仓库最新内容为准。接入即时通讯平台前,请自行确认所在平台的规则与合规要求。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。