mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-16 13:31:35 +00:00
363 lines
14 KiB
Markdown
363 lines
14 KiB
Markdown
---
|
|
summary: "QQ Bot setup, config, and usage"
|
|
read_when:
|
|
- You want to connect OpenClaw to QQ
|
|
- You need QQ Bot credential setup
|
|
- You want QQ Bot group or private chat support
|
|
title: QQ bot
|
|
---
|
|
|
|
QQ Bot connects to OpenClaw via the official QQ Bot API (WebSocket gateway).
|
|
C2C private chat and group `@`-mentions are the primary chat types, with rich
|
|
media (images, voice, video, files). Guild channel messages are supported for
|
|
text and remote-URL images only; voice, video, file uploads, and local/Base64
|
|
images are not available in guild channels. Reactions and threads are not
|
|
supported anywhere.
|
|
|
|
Status: official downloadable plugin.
|
|
|
|
## Install
|
|
|
|
```bash
|
|
openclaw plugins install @openclaw/qqbot
|
|
```
|
|
|
|
## Setup
|
|
|
|
1. Go to the [QQ Open Platform](https://q.qq.com/) and scan the QR code with your
|
|
phone QQ to register / log in.
|
|
2. Click **Create Bot** to create a new QQ bot.
|
|
3. Find **AppID** and **AppSecret** on the bot's settings page and copy them.
|
|
|
|
<Note>
|
|
AppSecret is not stored in plaintext. If you leave the page without saving it, you'll have to regenerate a new one.
|
|
</Note>
|
|
|
|
4. Add the channel:
|
|
|
|
```bash
|
|
openclaw channels add --channel qqbot --token "AppID:AppSecret"
|
|
```
|
|
|
|
5. Restart the Gateway.
|
|
|
|
Interactive setup:
|
|
|
|
```bash
|
|
openclaw channels add
|
|
```
|
|
|
|
The wizard also offers QR-code binding as an alternative to typing AppID/AppSecret
|
|
manually: scan the code with the phone app tied to the target QQ Bot to complete
|
|
binding. OpenClaw persists the returned credentials under the account's config
|
|
scope.
|
|
|
|
## Configure
|
|
|
|
Minimal config:
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
qqbot: {
|
|
enabled: true,
|
|
appId: "YOUR_APP_ID",
|
|
clientSecret: "YOUR_APP_SECRET",
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Default-account env vars (top-level account only):
|
|
|
|
- `QQBOT_APP_ID`
|
|
- `QQBOT_CLIENT_SECRET`
|
|
|
|
File-backed AppSecret:
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
qqbot: {
|
|
enabled: true,
|
|
appId: "YOUR_APP_ID",
|
|
clientSecretFile: "/path/to/qqbot-secret.txt",
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Env SecretRef AppSecret:
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
qqbot: {
|
|
enabled: true,
|
|
appId: "YOUR_APP_ID",
|
|
clientSecret: { source: "env", provider: "default", id: "QQBOT_CLIENT_SECRET" },
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
|
|
- `openclaw channels add --channel qqbot --token-file ...` sets the AppSecret
|
|
only; `appId` must already be set in config or `QQBOT_APP_ID`.
|
|
- `clientSecret` accepts a plaintext string, a file path (`clientSecretFile`),
|
|
or a structured SecretRef object.
|
|
- Legacy `secretref:...` / `secretref-env:...` marker strings are rejected for
|
|
`clientSecret`; use a structured SecretRef object instead.
|
|
|
|
### Access policy
|
|
|
|
- `allowFrom` / `groupAllowFrom` gate who can chat with the bot in C2C /
|
|
group contexts. `dmPolicy` / `groupPolicy` (`open` | `allowlist` | `disabled`)
|
|
control the enforcement mode. `dmPolicy` defaults to `allowlist` once
|
|
`allowFrom` has a concrete (non-wildcard) entry, otherwise `open`.
|
|
`groupPolicy` defaults to `allowlist` once either `groupAllowFrom` or
|
|
`allowFrom` has a concrete entry, otherwise `open`.
|
|
- "Auth: allowlist" slash commands require an explicit non-wildcard entry in
|
|
`allowFrom` (or `groupAllowFrom` for group invocations) regardless of
|
|
`dmPolicy` / `groupPolicy` — see [Slash commands](#slash-commands).
|
|
|
|
### Multi-account setup
|
|
|
|
Run multiple QQ bots under a single OpenClaw instance:
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
qqbot: {
|
|
enabled: true,
|
|
appId: "111111111",
|
|
clientSecret: "secret-of-bot-1",
|
|
accounts: {
|
|
bot2: {
|
|
enabled: true,
|
|
appId: "222222222",
|
|
clientSecret: "secret-of-bot-2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Each account owns an isolated WebSocket connection, API client, and token
|
|
cache, keyed by `appId`. Log lines are tagged with the owning account id so
|
|
diagnostics stay separable when you run several bots under one Gateway.
|
|
|
|
Add a second bot via CLI:
|
|
|
|
```bash
|
|
openclaw channels add --channel qqbot --account bot2 --token "222222222:secret-of-bot-2"
|
|
```
|
|
|
|
### Group chats
|
|
|
|
Group support uses QQ group OpenIDs, not display names. Add the bot to a
|
|
group, then mention it or configure the group to run without a mention.
|
|
|
|
```json5
|
|
{
|
|
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["*"]` sets defaults for every group; a concrete `groups.GROUP_OPENID`
|
|
entry overrides those defaults for one group. Group settings:
|
|
|
|
| Field | Default | Description |
|
|
| --------------------- | ---------------- | -------------------------------------------------------------------------------------------------- |
|
|
| `requireMention` | `true` | Require an `@`-mention before the bot replies. |
|
|
| `commandLevel` | `all` | Which built-in slash commands can run in the group (see below). |
|
|
| `ignoreOtherMentions` | `false` | Drop messages that mention someone else but not the bot. |
|
|
| `historyLimit` | `50` | Recent non-mention messages kept as context for the next mentioned turn. `0` disables history. |
|
|
| `tools` | — | Allow/deny tools for the whole group. |
|
|
| `toolsBySender` | — | Per-sender tool overrides; see [Groups](/channels/groups#groupchannel-tool-restrictions-optional). |
|
|
| `name` | openid prefix | Friendly label used in logs and group context. |
|
|
| `prompt` | built-in default | Per-group behavior prompt appended to the agent context. |
|
|
|
|
`commandLevel` accepts:
|
|
|
|
| Level | Behavior |
|
|
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `all` | Existing built-in commands stay available. Some stay hidden from menus but authorized users can still run them in the group. |
|
|
| `safety` | `/help`, `/btw`, `/stop` stay visible in the group; sensitive commands (`/config`, `/tools`, `/bash`, etc.) must be run in private chat. |
|
|
| `strict` | Only group-session controls needed for strict operation are allowed. `/stop` still works so an authorized sender can interrupt an active run. |
|
|
|
|
Old QQBot `toolPolicy` entries are retired. Run `openclaw doctor --fix` to migrate them to `tools`.
|
|
|
|
Activation modes are `mention` and `always`. `requireMention: true` maps to
|
|
`mention`; `requireMention: false` maps to `always`. A session-level activation
|
|
override, when present, wins over config.
|
|
|
|
The inbound queue is per peer. Group peers get a larger queue cap (50 vs. 20
|
|
for direct peers), evict bot-authored messages before human ones when full,
|
|
and merge bursts of normal group messages into one attributed turn. Slash
|
|
commands run one by one, independent of any merge batch.
|
|
|
|
### Voice (STT / TTS)
|
|
|
|
STT and TTS support two-level configuration with priority fallback:
|
|
|
|
| Setting | Plugin-specific | Framework fallback |
|
|
| ------- | -------------------------------------------------------- | ----------------------------- |
|
|
| STT | `channels.qqbot.stt` | `tools.media.audio.models[0]` |
|
|
| TTS | `channels.qqbot.tts`, `channels.qqbot.accounts.<id>.tts` | `messages.tts` |
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
qqbot: {
|
|
stt: {
|
|
provider: "your-provider",
|
|
model: "your-stt-model",
|
|
},
|
|
tts: {
|
|
provider: "your-provider",
|
|
model: "your-tts-model",
|
|
voice: "your-voice",
|
|
},
|
|
accounts: {
|
|
"qq-main": {
|
|
tts: {
|
|
providers: {
|
|
openai: { voice: "shimmer" },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Set `enabled: false` on either to disable. Account-level TTS overrides use the
|
|
same shape as `messages.tts` and deep-merge over channel/global TTS config.
|
|
|
|
STT requests time out after 60 seconds by default. Plugin-specific STT uses the
|
|
selected `models.providers.<id>.timeoutSeconds` override. Framework audio STT
|
|
uses `tools.media.audio.models[0].timeoutSeconds`, then
|
|
`tools.media.audio.timeoutSeconds`, then the selected provider override.
|
|
|
|
Inbound QQ voice attachments are exposed to agents as audio media metadata
|
|
while keeping raw voice files out of generic `MediaPaths`. `[[audio_as_voice]]`
|
|
in a plain-text reply synthesizes TTS and sends a native QQ voice message when
|
|
TTS is configured.
|
|
|
|
Outbound audio upload/transcode behavior can also be tuned with
|
|
`channels.qqbot.audioFormatPolicy`:
|
|
|
|
- `sttDirectFormats`
|
|
- `uploadDirectFormats`
|
|
- `transcodeEnabled`
|
|
|
|
## Target formats
|
|
|
|
| Format | Description |
|
|
| -------------------------- | ------------------ |
|
|
| `qqbot:c2c:OPENID` | Private chat (C2C) |
|
|
| `qqbot:group:GROUP_OPENID` | Group chat |
|
|
| `qqbot:channel:CHANNEL_ID` | Guild channel |
|
|
|
|
<Note>
|
|
Each bot has its own set of user OpenIDs. An OpenID received by Bot A **cannot** be used to send messages via Bot B.
|
|
</Note>
|
|
|
|
## Slash commands
|
|
|
|
Built-in commands intercepted before the AI queue:
|
|
|
|
| Command | Auth | Scope | Description |
|
|
| -------------------- | --------- | ------------ | ------------------------------------------------------------------------------ |
|
|
| `/bot-ping` | — | any | Latency test |
|
|
| `/bot-help` | — | any | List all commands |
|
|
| `/bot-me` | — | private only | Show the sender's QQ user ID (openid) for `allowFrom` / `groupAllowFrom` setup |
|
|
| `/bot-version` | — | private only | Show the OpenClaw framework version and plugin version |
|
|
| `/bot-upgrade` | — | private only | Show the QQBot upgrade guide link |
|
|
| `/bot-approve` | allowlist | private only | Manage command-execution approval config (on / off / always / reset / status) |
|
|
| `/bot-logs` | allowlist | private only | Export recent gateway logs as a file |
|
|
| `/bot-clear-storage` | allowlist | private only | Delete cached downloads under the QQBot media directory |
|
|
| `/bot-streaming` | allowlist | private only | Toggle C2C streaming replies |
|
|
| `/bot-group-allways` | allowlist | private only | Toggle the default group activation mode (mention-required vs. always-on) |
|
|
|
|
Append `?` to any command for usage help (for example `/bot-upgrade ?`).
|
|
|
|
"Auth: allowlist" commands additionally require the sender's openid in an
|
|
explicit non-wildcard `allowFrom` list (`groupAllowFrom` takes precedence for
|
|
group-issued commands, falling back to `allowFrom`). A wildcard
|
|
`allowFrom: ["*"]` permits chat but not these commands. Running one of them
|
|
outside private chat, or without authorization, returns a hint rather than
|
|
silently dropping the message.
|
|
|
|
`/bot-me`, `/bot-version`, and `/bot-upgrade` are private-chat-only but do not
|
|
require the allowlist — any C2C sender can run them.
|
|
|
|
When QQ Bot exec approvals use the default same-chat fallback, native approval
|
|
button clicks follow the same explicit non-wildcard command allowlist. To
|
|
grant approval-only access without broader command access, configure
|
|
`channels.qqbot.execApprovals.approvers`. Native exec approvals are enabled by
|
|
default.
|
|
|
|
## Media and storage
|
|
|
|
- Inbound, outbound, and gateway-bridge media share one payload root under
|
|
`~/.openclaw/media/qqbot` (honoring `OPENCLAW_HOME` when set), so uploads,
|
|
downloads, and transcode caches stay under one guarded directory.
|
|
- Rich media delivery for C2C and group targets goes through one `sendMedia`
|
|
path. Local files and in-memory buffers of 5 MiB or more use QQ's
|
|
chunked upload endpoints; smaller payloads and remote-URL/Base64 sources use
|
|
the one-shot upload API.
|
|
- If a hot upgrade interrupts the Gateway before it finishes writing
|
|
`openclaw.json`, the plugin restores the last-known `appId` / `clientSecret`
|
|
for that account from an internal snapshot on the next start (never
|
|
overwriting an intentional config change), so re-scanning the QR code is not
|
|
required.
|
|
|
|
## Troubleshooting
|
|
|
|
- **Gateway does not start / no inbound messages:** verify `appId` and
|
|
`clientSecret` are correct and the bot is enabled on the QQ Open Platform.
|
|
A missing credential surfaces as "QQBot not configured (missing appId or
|
|
clientSecret)".
|
|
- **Setup with `--token-file` still shows unconfigured:** `--token-file` only
|
|
sets the AppSecret. `appId` must still be set in config or `QQBOT_APP_ID`.
|
|
- **Bursty group replies collide:** the inbound queue evicts bot-authored
|
|
messages ahead of human ones when a peer's queue fills up, and merges
|
|
bursts of normal (non-command) group messages into one attributed turn, so
|
|
a flood of bot chatter should not starve human messages.
|
|
- **Proactive messages not arriving:** QQ may block bot-initiated messages if
|
|
the user has not interacted recently.
|
|
- **Voice not transcribed:** ensure STT is configured and the provider is
|
|
reachable.
|
|
|
|
## Related
|
|
|
|
- [Pairing](/channels/pairing)
|
|
- [Groups](/channels/groups)
|
|
- [Channel troubleshooting](/channels/troubleshooting)
|