通过 OneBot v11 协议(NapCat)将 QQ 接入 OpenClaw AI 框架。
┌─────────────────────────────────────────────────────────────────┐
│ OpenClaw 容器/进程 │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ @openclaw/qq 插件 │ │
│ │ │ │
│ │ gateway/ outbound/ admin-commands │ │
│ │ ┌────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ connection │ │ send-text │ │ /ping /logs │ │ │
│ │ │ inbound │ │ send-media │ │ /groups ... │ │ │
│ │ │ lifecycle │ └─────────────┘ └─────────────┘ │ │
│ │ └────────────┘ │ │
│ │ ↑ 消息事件 ↓ 发送指令 │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ OneBotClient (client.ts) │ │ │
│ │ │ 正向WS ←→ 反向WS Server ←→ HTTP API (带重试) │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ↕ │
└──────────────────────────┼──────────────────────────────────────┘
│ OneBot v11 协议
┌──────────────────────────┼──────────────────────────────────────┐
│ NapCat 容器/进程 │ │
│ HTTP :3000 ←───────────┘ (发送消息) │
│ WS Client ────────────→ :3002 (反向WS,接收事件) │
└─────────────────────────────────────────────────────────────────┘
消息处理流水线:
入站消息 → 去重 → 黑白名单 → 静默关键词 → 频控
→ 管理命令拦截 → 触发检测(@/关键词/旁观) → AI 派发
→ 回复防抖合并 → 分片/TTS/Markdown → 发送
- 多通道连接:正向 WebSocket / 反向 WebSocket / HTTP API 三通道互备
- 灵活触发:@机器人、关键词、戳一戳、旁观模式(AI 自主决定是否发言)
- 消息防抖:AI 连续输出自动合并为一条消息,避免轰炸
- 跨会话投递:
[TO:group:群号]前缀或/sendto命令发送到任意目标 - 配置热重载:
/reload即时生效,无需重启 - 群路由按需刷新:
/groups命令手动注册群路由,解决 cron 投递问题 - HTTP 重试:指数退避自动重试,5xx/网络错误不丢消息
- 智能表情:15 种关键词场景自动贴表情
- 管理命令:
/ping/status/version/logs/reload/groups/sendto/mute/kick/temperature - 安全管控:Token 鉴权、群组白名单、用户黑名单、入站频控、静默关键词
- Docker 部署:
curl | bash一键安装,跨服务器远程一键升级
机器人加入了新群但 cron 投递报错"找不到会话"?发 /groups 即可:
/groups
→ ✅ 已刷新 5 个群路由,cron 投递现在可用
原理:调用 getGroupList() 拉取所有已加入群,为每个群注册 session 路由。无需重启容器。
多个 bot 在同一群会产生循环对话?开启 ignoreSenderBot(默认 true),bot 消息会被自动过滤:
四层检测机制:
- 手动白名单(
knownBotIds):最高优先级,适用于不支持签名的 bot - sender.bot 字段:OneBot v11 标准字段,部分 bot 框架会设置
- 自维护缓存:通过签名自动发现并缓存(持久化到
~/.openclaw/napcat-qq/data/known-bots-<accountId>.json),后续无需任何标记也能识别 - 签名检测(in-band,仅 visible / zero-width 模式启用):见下表
- (v1.9.2 移除) 协议层握手:因 OneBot
json段在 QQ 客户端渲染为可见卡片消息,会启动广播 spam。接收侧仍保留作防御性兜底。
冷启动历史回填:bot 启动时拉取每个群最近 30 条历史,扫描文本签名,自动回填 known-bots-store。解决"对方 bot 之前发过签名,本 bot 启动后才入群"的不对称时序问题。
友军抑制:检测到其他 bot 活跃后,本 bot 会静默 botSuppressionMs 毫秒(默认 120 秒)
{
"ignoreSenderBot": true,
"botSuppressionMs": 120000,
"knownBotIds": [123456789, 987654321],
"botSignatureStyle": "visible"
}# Docker 环境变量
QQ_IGNORE_SENDER_BOT: "true"
QQ_BOT_SUPPRESSION_MS: "120000"
QQ_KNOWN_BOT_IDS: "123456789,987654321" # 手动 bot 白名单
QQ_BOT_SIGNATURE_STYLE: visible # 默认:[BOT:xxx] 文本签名签名样式对比(v1.9.2+):
| 样式 | 格式 | 用户文本 | 启动 spam | 适用场景 |
|---|---|---|---|---|
visible(默认) |
[BOT:12345678] 拼到消息末尾 |
❌ 可见 | ✅ 无 | 跨框架 bot 兼容,可靠 |
zero-width |
零宽字符 U+200B/U+200C | ✅ 不可见 | ✅ 无 | 美观优先,99% 场景有效 |
none |
无任何文本标记 | ✅ 干净 | ✅ 无 | 仅靠 sender.bot / knownBotIds / cache |
v1.9.0/1.9.1 删除说明:早先的
metadata模式(用 OneBotjson段握手)被完全移除——json 段在 QQ 客户端会渲染为可见卡片消息,导致启动时向所有群广播 spam 卡片。
私聊不追加签名。账号断开重连时持久化 cache 跨重启保留,新加入的群通过冷启动回填自动发现历史中的 bot。
防止 reasoning 类模型(Claude with extended thinking / o1 / o3 等)把 CoT 混到回复里。
# Docker 环境变量
QQ_RESPONSE_GUIDELINES: "" # 不设置 = 使用默认硬约束;设 "" = 关闭约束;设自定义文本 = 替换默认默认约束摘要:
- 不输出内部推理 / 用户行为分析 / 英文 meta 注释
- 群聊 50 字以内,信息密度优先
- 不"八股"结构(不用首先/其次/最后)
- 语言跟用户
- 多 bot 共存不复读其他 bot
- 旁听没想法的回复 [SILENT]
完整内容见 src/constants.ts 的 DEFAULT_RESPONSE_GUIDELINES。
AI 监听群聊所有消息,自主判断是否参与对话,无需 @:
推荐:使用 temperature 快速调节
{
"passiveMode": {
"enabled": true,
"temperature": 50
}
}temperature 是 0–100 的整数,控制主动程度:0=几乎不插话,50=均衡(默认),100=很活跃。等价于手动设置 cooldownMs / minIntervalMs / botSuppressionMs 三个毫秒参数。
也可继续使用细粒度参数:
{
"passiveMode": {
"enabled": true,
"cooldownMs": 10000,
"minIntervalMs": 30000,
"botSuppressionMs": 120000,
"systemPrompt": "你是一个观察者,仅在值得发言时回复,否则输出 [SILENT]"
}
}cooldownMs:实质回复后的冷却时间(默认 10 秒)minIntervalMs:最小触发间隔,含 [SILENT] 响应(默认 30 秒),防止 AI 被频繁调用botSuppressionMs:友军识别抑制时长(默认 120 秒),检测到其他 bot 回复后静默temperature:主动回复温度(0–100),设置后覆盖上述三个毫秒参数
Bot 只在指定群聊中响应,其他群自动忽略:
QQ_ALLOWED_GROUPS: "123456789,987654321" # 逗号分隔的群号,留空=所有群{ "allowedGroups": [123456789, 987654321] }群里有其他 bot 指令(如 ww签到)会误触发?配置 silentKeywords 直接屏蔽:
QQ_SILENT_KEYWORDS: "ww,签到,打卡" # 包含任一关键词的消息直接丢弃AI 连续输出多条碎片消息时,自动等待并合并为一条发送:
{ "deliverDebounce": { "enabled": true, "windowMs": 1500, "maxWaitMs": 8000 } }夜间不想被 bot 打扰?配置 sleepMode 让 bot 在指定时段自动休眠,仅响应 @ 和关键词触发:
{ "sleepMode": { "enabled": true, "startHour": 23, "endHour": 7 } }# Docker 环境变量
QQ_SLEEP_MODE_ENABLED: "true"
QQ_SLEEP_MODE_START_HOUR: "23"
QQ_SLEEP_MODE_END_HOUR: "7"startHour/endHour:使用服务器本地时间,支持跨午夜(如 23→7 表示晚上 11 点到早上 7 点)- 休眠期间:@机器人 + 关键词触发 → 正常响应;被动模式/旁观模式/名字触发 → 全部静默
- 私聊不受影响
AI 回复中使用 [TO:group:群号]内容 可发送到任意群/用户,绕过 session 限制。管理员也可用 /sendto group:群号 内容 手动发送。
环境要求:openclaw >= 2026.7.1;Node.js >=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0。
排障提示:openclaw 2026.7.1 起引入 crash-loop breaker——gateway 多次不干净启动后,频道不会自动启动(日志出现
channel autostart suppressed by crash-loop breaker),需手动执行channels.start恢复。
docker-compose.yml 完整示例(点击展开)
services:
# ── NapCat:QQ 协议端 ──────────────────────────────────────
napcat:
image: mlikiowa/napcat-docker:latest
container_name: napcat
volumes:
- ./napcat-data:/app/napcat/config
ports:
- "6099:6099" # WebUI(首次扫码登录)
- "3000:3000" # HTTP API
restart: unless-stopped
# ── OpenClaw + QQ 插件 ─────────────────────────────────────
openclaw:
image: ghcr.io/openclaw/openclaw:latest
container_name: openclaw
user: "0:0"
depends_on:
- napcat
ports:
- "18789:18789" # OpenClaw WebUI
- "3002:3002" # 反向 WS(NapCat 连入)
volumes:
- ./openclaw-data:/home/node/.openclaw
environment:
HOME: /home/node
TZ: Asia/Shanghai
OPENCLAW_GATEWAY_BIND: lan
OPENCLAW_GATEWAY_TOKEN: <你的gateway-token>
OPENCLAW_EXTRA_EXTENSIONS_DIR: /home/node/.openclaw/extensions
# ── NapCat 连接 ─────────────────────────────────────
QQ_HTTP_URL: http://napcat:3000
QQ_REVERSE_WS_PORT: "3002"
QQ_ACCESS_TOKEN: <你的napcat-token>
# ── 权限 ────────────────────────────────────────────
QQ_ADMINS: "123456789" # 管理员 QQ 号,多个用逗号分隔
QQ_REQUIRE_MENTION: "true" # 群聊是否需要 @ 触发
QQ_ALLOWED_GROUPS: "" # 群组白名单,逗号分隔,留空=所有群
QQ_BLOCKED_USERS: "" # 用户黑名单,逗号分隔
# ── 友军识别 ─────────────────────────────────────────
QQ_IGNORE_SENDER_BOT: "true" # 过滤 sender.bot=true 的消息
QQ_BOT_SUPPRESSION_MS: "120000" # 友军抑制时长(ms),0=禁用
QQ_KNOWN_BOT_IDS: "" # 手动 bot 白名单,逗号分隔的 QQ 号
QQ_BOT_SIGNATURE_STYLE: visible # 签名样式:visible | zero-width
# ── 行为 ────────────────────────────────────────────
QQ_SYSTEM_PROMPT: "" # 自定义系统提示词
QQ_HISTORY_LIMIT: "5" # 携带历史消息条数
QQ_MARKDOWN_MODE: passthrough # Markdown 处理:passthrough | strip | native
QQ_RATE_LIMIT_MS: "1000" # 发送限速(ms)
QQ_INBOUND_RATE_LIMIT_MS: "0" # 入站频控(ms),0=禁用
QQ_KEYWORD_TRIGGERS: "" # 无需 @ 的触发关键词,逗号分隔
QQ_SILENT_KEYWORDS: "" # 静默关键词,命中即丢弃
QQ_SLEEP_MODE_ENABLED: "false" # 休眠模式,默认关闭
QQ_SLEEP_MODE_START_HOUR: "23" # 休眠开始小时(0-23)
QQ_SLEEP_MODE_END_HOUR: "7" # 休眠结束小时(0-23)
# ── 旁观模式 ─────────────────────────────────────────
QQ_PASSIVE_MODE_ENABLED: "false" # 是否启用旁观模式
QQ_PASSIVE_MODE_COOLDOWN_MS: "10000" # 实质回复冷却(ms)
QQ_PASSIVE_MODE_MIN_INTERVAL_MS: "30000" # 最小触发间隔(ms)
QQ_PASSIVE_MODE_TEMPERATURE: "50" # 主动回复温度(0-100),覆盖三个毫秒参数
restart: unless-stopped配置说明:
| 环境变量 | 必填 | 说明 |
|---|---|---|
OPENCLAW_GATEWAY_TOKEN |
✅ | OpenClaw 网关 Token,用于 WebUI 鉴权 |
QQ_HTTP_URL |
✅ | NapCat HTTP API 地址 |
QQ_REVERSE_WS_PORT |
✅ | 反向 WS 监听端口 |
QQ_ACCESS_TOKEN |
✅ | NapCat 鉴权 Token(需与 NapCat 侧一致) |
QQ_ADMINS |
✅ | 管理员 QQ 号 |
QQ_ALLOWED_GROUPS |
❌ | 群组白名单,留空=所有群 |
QQ_IGNORE_SENDER_BOT |
❌ | 过滤其他 bot 消息,默认 true |
QQ_KNOWN_BOT_IDS |
❌ | 手动 bot 白名单(QQ 号),适用于不支持签名的 bot |
QQ_BOT_SIGNATURE_STYLE |
❌ | 签名样式:visible(默认)或 zero-width |
QQ_PASSIVE_MODE_ENABLED |
❌ | 旁观模式,默认 false |
QQ_PASSIVE_MODE_TEMPERATURE |
❌ | 主动回复温度(0–100),覆盖三个毫秒参数 |
NapCat 侧配置(onebot11_<QQ号>.json):
{
"network": {
"httpServers": [{
"enable": true, "port": 3000, "host": "0.0.0.0",
"messagePostFormat": "array", "token": "<同 QQ_ACCESS_TOKEN>"
}],
"websocketClients": [{
"enable": true, "url": "ws://openclaw:3002",
"messagePostFormat": "array", "token": "<同 QQ_ACCESS_TOKEN>",
"reconnectInterval": 5000
}]
}
}首次部署:
docker compose up -d
docker exec -it openclaw sh -c \
"curl -fsSL https://raw.githubusercontent.com/Daiyimo/openclaw-napcat/main/scripts/docker-install.sh | bash"
docker compose restart openclaw
docker exec -it openclaw openclaw onboard # 配置 AI 模型
docker compose restart openclaw已有实例的升级,在宿主机上执行一行命令即可:
curl -fsSL https://raw.githubusercontent.com/Daiyimo/openclaw-napcat/main/scripts/remote-upgrade.sh | bash国内加速(raw.githubusercontent.com 被墙时):
curl -fsSL https://ghfast.top/https://raw.githubusercontent.com/Daiyimo/openclaw-napcat/main/scripts/remote-upgrade.sh | bash自定义容器名或数据目录:
CONTAINER_NAME=my-bot DATA_DIR=/my/data curl -fsSL ... | bash升级流程:下载源码 → 备份 → 容器内编译 → 部署 → 重启。失败自动回滚。
详细部署指南见 docs/DOCKER.md。
~/.openclaw/openclaw.json 中添加:
{
"channels": {
"napcat": {
"reverseWsPort": 3002,
"httpUrl": "http://<NapCat地址>:3000",
"accessToken": "你的Token",
"admins": [你的QQ号]
}
}
}OpenClaw 的 cron 系统支持定时执行任务并投递结果到 QQ 群。NapCat 插件提供两种投递模式:
| 模式 | 说明 | 适用场景 |
|---|---|---|
default |
OpenClaw announce 投递(走 message tool → napcat 插件) | 简单文本消息 |
napcat |
直接调用 NapCat HTTP API 发送(delivery=none,cron 内部 curl) | 需要可靠群发、避免 message tool 路由问题 |
在 OpenClaw 容器内执行:
node scripts/new-cron.cjs按提示输入任务名、cron 表达式,选择投递模式。
如果已有 cron 任务出现投递失败(Channel napcat is unavailable for message actions),执行:
node scripts/fix-cron.cjs该脚本会自动将所有 NapCat 相关 cron 任务修复为 delivery=none + curl 直发模式,并注入完整的 HA Token。
openclaw cron edit <job-id> \
--no-deliver \
--command-argv '["sh","-lc","curl -s -X POST http://napcat:3000/send_group_msg ..."]' \
--command-env HA_TOKEN=<你的完整token>openclaw cron list
# 或 JSON 格式
openclaw cron list --json| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
reverseWsPort |
number | - | 反向 WS 监听端口 |
httpUrl |
string | - | NapCat HTTP API 地址 |
accessToken |
string | - | 鉴权 Token |
admins |
number[] | [] |
管理员 QQ 号 |
requireMention |
boolean | true |
群聊是否需要 @ 触发 |
allowedGroups |
number[] | [] |
群组白名单(空=全部) |
blockedUsers |
number[] | [] |
用户黑名单 |
ignoreSenderBot |
boolean | true |
过滤其他 bot 消息,防止循环对话 |
knownBotIds |
number[] | [] |
手动 bot 白名单,适用于不支持签名的 bot |
botSignatureStyle |
string | "visible" |
签名样式:visible(默认,[BOT:xxx] 文本签名)/ zero-width / none |
debug |
boolean | false |
开启消息处理流水线的详细诊断日志(@mention / bot 过滤 / 表情),排查问题时临时开启 |
botSuppressionMs |
number | 120000 |
友军抑制时长(ms),0=禁用 |
keywordTriggers |
string[] | [] |
无需 @ 的触发关键词 |
silentKeywords |
string[] | [] |
静默关键词(命中即丢弃) |
historyLimit |
number | 5 |
携带历史消息条数 |
rateLimitMs |
number | 1000 |
发送限速(ms) |
passiveMode |
object | - | 旁观模式配置,支持 temperature(0–100)快速调节 |
deliverDebounce |
object | - | 消息防抖配置 |
sleepMode |
object | - | 休眠模式:夜间静默,仅 @和关键词触发 |
完整配置见 docs/CONFIG.md。
- BUILD.md — 本地构建与开发指南
- CONFIG.md — 完整配置项
- COMMANDS.md — 管理员指令
- DOCKER.md — Docker 部署指南
- UPGRADE.md — 远程一键升级指南
- MODULES.md — 模块职责
- CHANGELOG.md — 更新日志