Files
chatrebot_aireply_plug/README.md
root 9dff73e7bc fix: 通过本地完整测试发现的 11 个 bug
🔴 致命(5个):
- Bug1: onebot11.json 格式错误(旧 {http:{},ws:{}} → network.httpServers/httppClients)
- Bug2: 端口映射错位(WebUI 6099, OneBot API 6097 独立端口)
- Bug3: 变量名含空格 NAP CAT_HOST → NAPCAT_HOST(14脚本+2SKILL+README)
- Bug4: heredoc 单引号阻止变量展开
- Bug5: process.py 缺失 _get_high_risk_words() 方法

🟡 重要(3个):
- Bug6: onebot11.json 默认不存在(cat > 而非 edit)
- Bug7: API 须登录后才响应(新增扫码引导步骤)
- Bug8: qqrebot systemd 依赖 napcat 服务

🟢 中等(3个):
- Bug9: Skills 占位符缺 YOUR_NAPCAT_HOST sed 覆盖
- Bug10: venv 不可用需降级方案
- Bug11: 端口 25580 冲突处理
已验证全链路:NapCat + qqrebot + 插件 + OpenClaw Gateway + AI 回复
2026-05-04 19:47:26 +08:00

714 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OpenClaw Bridge — QQ AI Reply Plugin
> 将 QQ 消息转发到 OpenClaw Gateway,由 AI agent 自动处理并回复。
> 本 README 面向 AI agent(OpenClaw 基础智能体),引导其完成全流程部署(NapCat → qqrebot → 插件 → agent)。
## 架构
```
QQ 用户 →→→ NapCat(Docker)
│
│ HTTP POST(事件推送:6097→qqrebot:25580)
▼
qqrebot(HTTP Server :25580) ← 消息接收
│
├── 执行 openclaw_bridge 插件
│ │
│ │ HTTP POST /v1/chat/completions
│ ▼
│ OpenClaw Gateway(:18789)
│ │
│ ▼
│ qq-agent(AI 模型)
│ │
◄── 返回回复文本 ──┘
│
│ HTTP POST(send_private_msg / send_group_msg)
▼
NapCat(Docker:6097)→ 回复发送到 QQ
```
**关键通信链路(全是 HTTP,无 WebSocket):**
| 链路 | 方向 | 协议 | 地址 |
|---|---|---|---|
| NapCat → qqrebot | 事件推送 | HTTP POST | `http://172.17.0.1:25580/` |
| 插件 → OpenClaw | AI 请求 | HTTP POST | `127.0.0.1:18789` |
| 插件 → NapCat | 发送回复 | HTTP POST | `127.0.0.1:6097` |
| 脚本 → NapCat | 发消息/管理 | HTTP POST | `127.0.0.1:6097` |
## 前提条件
| 组件 | 状态 | 由本仓库部署 |
|---|---|---|
| OpenClaw Gateway | 假设已运行 | ❌(由用户自行部署) |
| NapCat(Docker) | 需部署 | ✅ |
| qqrebot(消息接收器)| 需部署 | ✅ |
| openclaw_bridge 插件 | 需部署 | ✅ |
| qq-agent(AI agent) | 需创建 | ✅ |
| QQ 技能/脚本 | 需部署 | ✅ |
## 部署步骤(阅读此文档的 AI agent 请按以下顺序执行)
---
### 第1步:环境自动检测 + 询问关键信息
本步骤将自动推导绝大多数配置,**只需向用户确认两个不可推导的值**。
#### 1.1 设置默认值(agent 自动执行)
```bash
# ─── 可自动推导的变量,全部使用默认值 ───
# Agent 唯一标识(默认 qq-agent,用户可改但通常不需要)
NEW_AGENT_ID="${NEW_AGENT_ID:-qq-agent}"
AGENT_WORKSPACE="/home/program/${NEW_AGENT_ID}-workspace"
# 共享目录路径
SHARED_DIR="${SHARED_DIR:-/opt/napcat_shared}"
# NapCat HTTP API 地址(同机部署走 127.0.0.1)
NAPCAT_HOST="127.0.0.1"
# OneBot HTTP API 端口(与 WebUI 端口 6099 不同)
NAPCAT_API_PORT="${NAPCAT_API_PORT:-6097}"
# 从 NapCat Docker 容器角度看到的 qqrebot 地址
# 同机部署时 NapCat 通过 Docker 网关访问宿主机
QQREBOT_HOST="172.17.0.1:25580"
# Gateway Token:自动从本机 OpenClaw 配置文件读取
GATEWAY_TOKEN=$(python3 -c "
import json
with open('$HOME/.openclaw/openclaw.json') as f:
cfg = json.load(f)
print(cfg.get('gateway', {}).get('auth', {}).get('token', ''))
" 2>/dev/null)
```
> 变量命名规则:脚本中的占位符为 `YOUR_NAPCAT_HOST:25570`(带端口),由 sed 替换为 `${NAPCAT_HOST}:${NAPCAT_API_PORT}`。请勿在 bash 变量名中使用空格。
> `QQREBOT_HOST` 带端口 `:25580`,用于 onebot11.json 的 `httpClients` URL。
#### 1.2 向用户确认
只有以下两项无法自动推导,agent 需向用户询问:
| 变量 | 必须 | 说明 |
|---|---|---|
| `ADMIN_QQ` | ✅ | 管理员 QQ 号,用于白名单和安全告警上报 |
| `GATEWAY_TOKEN` | 看情况 | 自动读取失败时(空值)才需要用户提供 |
> 其余变量(`NEW_AGENT_ID`、`SHARED_DIR`、`NAPCAT_HOST`、`NAPCAT_API_PORT`、`QQREBOT_HOST`)全部使用默认值即可。仅在跨机部署时需要用户调整 `NAPCAT_HOST` 或 `NAPCAT_API_PORT`。
#### 1.3 应用变量
```bash
# 确认必填项
if [ -z "$ADMIN_QQ" ]; then
echo "请提供 ADMIN_QQ"
exit 1
fi
if [ -z "$GATEWAY_TOKEN" ]; then
echo "自动读取 GATEWAY_TOKEN 失败,请提供"
exit 1
fi
export ADMIN_QQ NEW_AGENT_ID AGENT_WORKSPACE SHARED_DIR NAPCAT_HOST NAPCAT_API_PORT QQREBOT_HOST GATEWAY_TOKEN
echo "变量已就绪:ADMIN_QQ=$ADMIN_QQ, AGENT=$NEW_AGENT_ID, NAPCAT=$NAPCAT_HOST:$NAPCAT_API_PORT"
```
---
### 第2步:通过 Docker 部署 NapCat
NapCat 是 QQ 协议实现,接收 QQ 消息并通过 **HTTP POST** 推送到 qqrebot。
#### 2.1 端口说明
| 端口 | 是否必开 | 用途 |
|---|---|---|
| `6097` | ✅ | OneBot HTTP API(脚本发消息/群管理/取数据都用此端口) |
| `6099` | ✅ | WebUI 管理面板(NapCat 默认占用,不能与 API 共用) |
| `3001` | ❌ | WebSocket Server(本教程用 HTTP POST,不启用) |
> NapCat v4 的 WebUI 默认绑定端口 6099。OneBot HTTP API 需要独立端口(本教程使用 6097)。
> WebUI 用于扫码登录和管理界面,首次部署时需保持开启;生产环境可关闭或将 WebUI 绑定到 `127.0.0.1`。
#### 2.2 创建目录结构
```bash
# 共享文件目录(NapCat Docker 内发文件时读取)
SHARED_DIR="${SHARED_DIR:-/opt/napcat_shared}"
mkdir -p "${SHARED_DIR}"
# NapCat 配置目录 + QQ 登录数据持久化
mkdir -p /opt/napcat/config
mkdir -p /opt/napcat/qq_data
```
#### 2.3 创建 onebot11.json 配置
> ⚠️ onebot11.json 默认不存在,需手动创建。NapCat v4 使用 `network` 配置格式(非旧版 `http{} ws{}` 格式)。
```bash
cat > /opt/napcat/config/onebot11.json << 'ONEBOTEOF'
{
"network": {
"httpServers": [
{
"name": "http-server",
"enable": true,
"host": "0.0.0.0",
"port": 6097,
"token": "",
"enableCors": true,
"debug": false
}
],
"httpClients": [
{
"name": "http-post",
"enable": true,
"url": "http://${QQREBOT_HOST}/",
"messagePostFormat": "array",
"reportSelfMessage": false,
"token": "",
"debug": false
}
],
"websocketServers": [],
"websocketClients": []
},
"musicSignUrl": "",
"enableLocalFile2Url": true,
"parseMultMsg": false
}
ONEBOTEOF
```
> `httpServers`:OneBot HTTP API,脚本通过此端口发送消息/管理群组。
> `httpClients`:NapCat 将消息事件通过 HTTP POST 推送到 qqrebot。
> `httpClients[0].url` 中 `${QQREBOT_HOST}` 需替换为实际地址(同机部署时为 `172.17.0.1:25580`)。Docker 的默认 bridge 网关是 `172.17.0.1`,可通过 `docker network inspect bridge` 确认。
#### 2.4 启动 NapCat Docker 容器
```bash
docker run -d \
--name napcat \
--restart unless-stopped \
-p 6097:6097 \
-p 6099:6099 \
-v /opt/napcat/config:/app/napcat/config \
-v /opt/napcat/qq_data:/app/.config/QQ \
-v "${SHARED_DIR}:/app/napcat/share" \
--dns=114.114.114.114 \
mlikiowa/napcat-docker:latest
```
> 必须同时暴露 `6097`(OneBot API)和 `6099`(WebUI),缺一不可。
#### 2.5 QQ 登录(扫码)
> ⚠️ OneBot HTTP API 在 QQ 登录成功之前不会启动!
> `curl /get_version_info` 类 API 调用必须在登录后才能成功。
```bash
# 查看登录二维码(日志中会打印链接)
docker logs napcat 2>&1 | grep -o 'http[s]*://[^ ]*\.png'
# 或用浏览器打开 http://<服务器IP>:6099/webui 扫码登录
# 等待登录成功
docker logs napcat -f | grep "登录成功"
# 登录成功后 OneBot 配置会自动加载,可以看到类似日志:
# [Notice] [OneBot11] HTTP服务: 0.0.0.0:6097, : 已启动
# [Notice] [OneBot11] HTTP上报服务: http://172.17.0.1:25580/, : 已启动
```
#### 2.6 验证 NapCat
```bash
# 验证 HTTP API 可访问(仅在登录成功后可调用)
curl -s http://localhost:6097/get_version_info | python3 -m json.tool
# 预期输出:
# {"status": "ok", "data": {"app_name": "NapCat", ...}, ...}
# 验证 WebUI 可访问
curl -s -o /dev/null -w "%{http_code}" http://localhost:6099/webui
# 预期返回 200
```
---
### 第3步:部署 qqrebot(消息接收器)
qqrebot 是 HTTP 服务器,NapCat 将 QQ 消息 POST 到 qqrebot,qqrebot 加载插件处理。
#### 3.1 安装 qqrebot
从 [chatrebot1.0 release](https://jianfgit.xyz/jianf/chat_rebot-connect-with-onebot-standard-/src/tag/chatrebot1.0/) 下载:
```bash
wget https://jianfgit.xyz/jianf/chat_rebot-connect-with-onebot-standard-/archive/chatrebot1.0.tar.gz
tar xzf chatrebot1.0.tar.gz
mv chat_rebot-connect-with-onebot-standard- /opt/qqrebot
cd /opt/qqrebot
```
#### 3.2 检查端口冲突
```bash
# 检查 25580 是否已被占用
if ss -tlnp | grep -q :25580; then
echo "⚠️ 端口 25580 已被占用,请修改为 25581 或其他空闲端口"
echo " 修改 qqrebot config.toml 中的 list_port"
exit 1
fi
```
#### 3.3 配置
编辑 `config/config.toml`:
```toml
[app]
list_port = 25580
send_url = "http://${NAPCAT_HOST}:${NAPCAT_API_PORT}" # 指向 NapCat OneBot API
[rebot]
id = ""
[plugins]
dir = ["plugins"]
```
> `send_url` 是 qqrebot 框架发给插件的 NapCat API 基础地址(即 `ctx.group.url`)。所有 `send_private_msg` / `send_group_msg` 调用都走此地址。
> 如果 NapCat 和 qqrebot 同机,`send_url = "http://127.0.0.1:6097"`。
#### 3.4 创建 systemd 服务
```bash
# 注意:如果 qqrebot 已有其他实例在运行,请修改端口和服务名
# 此处假设使用端口 25580,服务名 qqrebot
cat > /etc/systemd/system/qqrebot.service << 'SERVICEEOF'
[Unit]
Description=QQ Robot
After=network.target docker.service
Requires=docker.service
[Service]
Type=simple
WorkingDirectory=/opt/qqrebot
ExecStart=/opt/qqrebot/run.sh
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
SERVICEEOF
systemctl daemon-reload
systemctl enable --now qqrebot
```
---
### 第4步:安装 openclaw_bridge 插件
本仓库即 openclaw_bridge 插件的源码,需打包后部署到 qqrebot。
**打包(必须在目标主机上执行,因含 C 扩展):**
```bash
cd /path/to/chatrebot_aireply_plug
pip install -r requirements.txt
python3 package.py
```
**部署:**
```bash
cp dist/openclaw_bridge.zip /opt/qqrebot/plugins/
```
**创建插件配置 `/opt/qqrebot/config/openclawbridge/config.toml`:**
```toml
[openclaw]
gateway_url = "http://127.0.0.1:18789"
gateway_token = "${GATEWAY_TOKEN}"
allowed_sender = "${ADMIN_QQ}"
model = "openclaw/${NEW_AGENT_ID}"
agent_id = "${NEW_AGENT_ID}"
```
**重启 qqrebot 加载插件:**
```bash
systemctl restart qqrebot
```
**验证插件加载:**
```bash
journalctl -u qqrebot -f | grep OpenClawBridge
```
预期输出:
```
Config loaded: url=http://127.0.0.1:18789, allowed=123456789
```
---
### 第5步:创建新的 OpenClaw agent
在 `~/.openclaw/openclaw.json` 的 `agents.list` 中添加新 agent:
```bash
AGENT_ID="${NEW_AGENT_ID}"
AGENT_WORKSPACE="/home/program/${AGENT_ID}-workspace"
mkdir -p "${AGENT_WORKSPACE}/scripts"
mkdir -p "${AGENT_WORKSPACE}/skills"
mkdir -p "${AGENT_WORKSPACE}/self-workplace"
mkdir -p "${AGENT_WORKSPACE}/memory"
mkdir -p "${AGENT_WORKSPACE}/files"
```
添加 agent 配置项到 `agents.list`:
```json
{
"id": "${NEW_AGENT_ID}",
"name": "${NEW_AGENT_ID}",
"model": "kimi/kimi-for-coding",
"workspace": "/home/program/${NEW_AGENT_ID}-workspace"
}
```
> 通过 `GET /api/config/all` 获取当前配置,找到 `agents.list` 数组执行 push,然后 `POST /api/config/set`。或直接编辑 `~/.openclaw/openclaw.json` 后重启 Gateway。
---
### 第6步:获取源码并部署到 agent 的 workspace
> agent 需要在目标服务器上获得 chatrebot_aireply_plug 的 `scripts/`(26 个脚本)和 `skills/`(8 个 skill)目录。
#### 6.1 在目标服务器上克隆仓库
```bash
# 方案 A:git clone
git clone https://jianfgit.xyz/jianf/chatrebot_aireply_plug.git /opt/chatrebot_aireply_plug
# 方案 B:本机已有 repo,直接复制
# cp -r /home/program/pm-workspace /opt/chatrebot_aireply_plug
```
后续步骤假设源码解压到 `/opt/chatrebot_aireply_plug`。
#### 6.2 复制脚本
```bash
cp -r /opt/chatrebot_aireply_plug/scripts/* "${AGENT_WORKSPACE}/scripts/"
```
脚本清单(26 个),按功能分组:
| 分组 | 脚本 | 用途 |
|---|---|---|
| **QQ 消息** | `qq_send_msg.py` | 发送文本消息 |
| | `qq_send_file.py` | 发送文件/图片 |
| | `qq_upload_group_file.py` | base64 直接上传群文件 |
| | `qq_send_like.py` | 点赞 |
| | `qq_ocr_image.py` | 图片 OCR 识别 |
| **QQ 查询** | `qq_get_groups.py` | 获取群列表 |
| | `qq_get_friends.py` | 获取好友列表 |
| | `qq_get_group_files.py` | 获取群文件列表 |
| | `qq_get_file.py` | 下载文件 |
| | `qq_get_history.py` | 拉取历史消息 |
| | `qq_resolve_name.py` | QQ号/群号 ↔ 可读名称 |
| **QQ 管理** | `qq_group_action.py` | 退群、接受/拒绝群邀请 |
| | `qq_group_manage.py` | 群成员管理(踢/禁言等) |
| | `qq_friend_action.py` | 删好友、同意/拒绝好友请求 |
| **MC 服务器** | `mc_query.py` | 服务器状态查询 |
| | `mc_status.py` | 状态(简化版) |
| | `mc_players.py` | 玩家信息 |
| | `mc_world.py` | 世界详情 |
| | `mc_rcon.py` | 远程执行 RCON 命令 |
| | `mc_clear_items.py` | 清理掉落物 |
| | `mc_config.py` | 服务器配置管理 |
| **工具** | `browse.py` | 网页浏览/截图 |
| | `file_store_api.py` | 文件存储 API |
| | `ask_nix.py` | 向 ops-manager 求助 |
| | `qq_video_download.py` | 视频下载 |
| | `__init__.py` | 包初始化 |
#### 6.3 复制 Skills
Skills 是 agent 的能力描述文件(`SKILL.md`),每个 skill 一个子目录,agent 启动时会加载:
```bash
for SKILL in qq-messenger qq-management qq-resolver qq-napcat-extras mc-query nix-helper browser file-process; do
cp -r "/opt/chatrebot_aireply_plug/skills/${SKILL}" "${AGENT_WORKSPACE}/skills/"
done
```
> Skills 中的 SKILL.md 通过 `YOUR_WORKSPACE_PATH/scripts/xxx.py` 引用脚本路径。
> agent 执行 `subprocess.run` 时,实际调用的是 `${AGENT_WORKSPACE}/scripts/` 下的脚本。
#### 6.4 替换占位符(关键!必须执行)
**替换脚本占位符:**
```bash
cd "${AGENT_WORKSPACE}/scripts"
# NapCat HTTP API 地址(端口 ${NAPCAT_API_PORT},非旧版 25570)
sed -i "s|YOUR_NAPCAT_HOST:25570|${NAPCAT_HOST}:${NAPCAT_API_PORT}|g" *.py
sed -i "s|YOUR_NAPCAT_HOST|${NAPCAT_HOST}:${NAPCAT_API_PORT}|g" *.py
# 管理员 QQ
sed -i "s|YOUR_ADMIN_QQ|${ADMIN_QQ}|g" *.py
# Gateway Token
sed -i "s|YOUR_GATEWAY_TOKEN|${GATEWAY_TOKEN}|g" *.py
# 工作区路径
sed -i "s|YOUR_WORKSPACE_PATH|${AGENT_WORKSPACE}|g" *.py
# 共享目录
sed -i "s|YOUR_SHARED_DIR|${SHARED_DIR}|g" *.py
```
**替换 Skills 占位符:**
```bash
cd "${AGENT_WORKSPACE}/skills"
for f in */SKILL.md; do
sed -i "s|YOUR_WORKSPACE_PATH|${AGENT_WORKSPACE}|g" "$f"
sed -i "s|YOUR_ADMIN_QQ|${ADMIN_QQ}|g" "$f"
sed -i "s|YOUR_SHARED_DIR|${SHARED_DIR}|g" "$f"
done
```
> ⚠️ Skills 的替换很关键:
> - `YOUR_WORKSPACE_PATH` → agent 的 subprocess.run 能找到脚本
> - `YOUR_SHARED_DIR` → 涉及文件发送的 Skill(qq-messenger、qq-napcat-extras)理解的宿主机共享路径
> - 两个 Skill(qq-messenger、qq-napcat-extras)还记录了容器路径 `/app/napcat/share/`,这是一个固定常量,对应 Docker volume `-v SHARED_DIR:/app/napcat/share`。如果修改了 volume 挂载点,需同步修改这些 SKILL.md 和 `qq_send_file.py`、`qq_ocr_image.py` 中的容器路径。
**文件发送全链路路径转换示意:**
```
agent 工作区 宿主机共享目录 NapCat 容器内
/script/file.txt →cp→ /opt/napcat_shared/ ←volume→ /app/napcat/share/
↓
qq_send_file.py 构造
file:///app/napcat/share/file.txt
↓
NapCat HTTP API → QQ 用户
```
> 代理的思维模型:"我要发文件 → 把文件放到共享目录 → 脚本从共享目录发"。Skill 中提到的"发送文件/图片"都隐含了这一步文件复制。
**验证文件路径转换:**
```bash
# 确认共享目录存在
ls -la "${SHARED_DIR}/"
# 手动测试:复制一个文件过去,走 qq_send_file.py
echo hello > /tmp/test.txt
python3 "${AGENT_WORKSPACE}/scripts/qq_send_file.py" "/tmp/test.txt" --target "${ADMIN_QQ}" --private
```
#### 6.5 验证完整性
```bash
# 脚本数量
echo "scripts: $(ls "${AGENT_WORKSPACE}/scripts/" | wc -l) 个"
# 确认无残留占位符
if grep -r "YOUR_ADMIN_QQ\|YOUR_WORKSPACE_PATH\|YOUR_NAPCAT_HOST\|YOUR_SHARED_DIR" "${AGENT_WORKSPACE}/"; then
echo "⚠️ 还有未替换的占位符!"
else
echo "✅ 占位符全部替换完毕"
fi
```
---
### 第7步:重启 OpenClaw Gateway
```bash
openclaw gateway restart
```
确认新 agent 已加载:
```bash
openclaw config get agents.list
# 或 journalctl -u openclaw -f | grep "agent.${NEW_AGENT_ID}"
```
---
### 第8步:端到端验证
1. 确认 NapCat QQ 已登录(`docker logs napcat 2>&1 | grep "登录成功"`)
2. 确认 OneBot API 可访问(`curl localhost:6097/get_version_info`)
3. 确认 qqrebot 正在运行(`systemctl status qqrebot`)
4. 在 QQ 上给机器人发消息
5. 检查 qqrebot 日志:`journalctl -u qqrebot -f | grep OpenClawBridge`
6. 检查 OpenClaw 日志:`journalctl -u openclaw -f`
7. 验证 agent 已回复
---
## 脚本适配说明
### 端口对照
| 组件 | 旧版 go-cqhttp | NapCat(本教程) |
|---|---|---|
| HTTP API 端口 | `25570` | **6097** |
| WebUI | N/A | **6099**(扫码登录用) |
| WebSocket | `25570`(兼用) | 不启用 |
> 脚本中 `CQHTTP_URL = "http://YOUR_NAPCAT_HOST:25570"` 替换后变为 `http://127.0.0.1:6097`。
### 文件发送与共享目录
NapCat 运行在 Docker 内部,宿主机文件路径不能直接访问。解决方式:
```
宿主机 ${SHARED_DIR}/ ⇔ Docker volume → 容器内 /app/napcat/share/
```
| 脚本 | 关联 | 说明 |
|---|---|---|
| `qq_send_file.py` | 使用 `TARGET_DIR` | 发文件前复制到共享目录,NapCat 从 `/app/napcat/share/` 读取 |
| `qq_ocr_image.py` | 提到 NapCat 回退 | 只在本地 Tesseract 不可用时走 NapCat,此时需文件在共享目录 |
| `qq_get_file.py` | 无依赖 | NapCat 返回 base64 或 URL,自动下载,不依赖共享目录 |
| `qq_upload_group_file.py` | 无依赖 | 使用 base64:// 编码直接上传,不依赖共享目录 |
### 变量速查
| 占位符 | 替换值 | 出现位置 |
|---|---|---|
| `YOUR_NAPCAT_HOST:25570` | `${NAPCAT_HOST}:${NAPCAT_API_PORT}` | 所有脚本 |
| `YOUR_NAPCAT_HOST` | `${NAPCAT_HOST}:${NAPCAT_API_PORT}` | 部分脚本 |
| `YOUR_ADMIN_QQ` | `${ADMIN_QQ}` | 脚本 + SKILL.md |
| `YOUR_GATEWAY_TOKEN` | `${GATEWAY_TOKEN}` | 脚本 |
| `YOUR_SHARED_DIR` | `${SHARED_DIR}` | `qq_send_file.py`、`qq_ocr_image.py`、`qq-messenger/SKILL.md`、`qq-napcat-extras/SKILL.md` |
| `YOUR_WORKSPACE_PATH` | `${AGENT_WORKSPACE}` | SKILL.md + 脚本 |
---
## 安全模块说明
部署完成后,新 agent 将具备以下安全能力(全部在 `src/process.py` 中实现):
### 高危词检测
内置 `HIGH_RISK_WORDS` 词库,覆盖以下类别:
| 类别 | 示例关键词 |
|---|---|
| 越狱/提示词攻击 | `ignore all instructions`、`forget previous` |
| 记忆操控 | `delete memory`、`forget everything` |
| 敏感信息泄漏 | `sudo password`、`api key` |
| 系统命令 | `cat /etc/passwd`、`rm -rf` |
**触发时行为:**
- 非管理员 → 自动拦截 + 上报管理员 + 该用户加入黑名单
- 管理员 → 记录日志 + 发送告警到 admin 私聊
### 管理员白名单
| 配置项 | 说明 |
|---|---|
| `allowed_sender` | 唯一的管理员 QQ 号 |
| 非管理员操作 | MC 指令过滤(`/` 开头消息跳过 AI 处理) |
### 消息过滤
- 纯媒体消息(无文字:纯图片/文件/视频)自动跳过
- 系统通知(`[系统通知]`、`[文件回执]`)自动跳过
- 非管理员发送的操作指令(`/` 开头)跳过 AI 处理
### 安全上报
当非管理员触发高危词时,插件自动通过 NapCat HTTP API 给 `allowed_sender` 发送告警(调用 `send_private_msg`)。
### 错误脱敏
所有 HTTP 响应体、异常详情不暴露给 QQ 用户,仅记录日志。
## 配置文件参考
| 配置项 | 必填 | 说明 |
|---|---|---|
| `gateway_url` | ✅ | OpenClaw Gateway 地址 |
| `gateway_token` | ✅ | Gateway 认证 Token |
| `allowed_sender` | ✅ | 管理员 QQ 号 |
| `model` | ✅ | Agent 模型 ID(格式:`openclaw/${AGENT_ID}`) |
| `agent_id` | ✅ | Agent ID(与 `agents.list` 一致) |
## 目录结构
```
chatrebot_aireply_plug/
├── config/
│ └── openclawbridge/
│ └── config.toml # 插件配置模板
├── src/
│ ├── process.py # 插件核心逻辑(含全部安全模块)
│ ├── config.toml # 本地测试配置
│ └── modules/
│ ├── plugin_modules.py # BasePlugin + MessageContext
│ └── user_module.py # User/Group 封装
├── scripts/ # ✅ 部署时复制到 agent workspace
│ ├── qq_send_msg.py # 发送消息(调 NapCat :6097)
│ ├── qq_send_file.py # 发送文件/图片
│ ├── qq_get_groups.py # 获取群列表
│ ├── qq_get_friends.py # 获取好友列表
│ ├── qq_group_manage.py # 群管理(踢/禁言/设管理)
│ └── ...
├── skills/ # ✅ 部署时复制到 agent skills/
│ ├── qq-messenger/SKILL.md
│ ├── qq-management/SKILL.md
│ ├── qq-resolver/SKILL.md
│ ├── qq-napcat-extras/SKILL.md
│ ├── mc-query/SKILL.md
│ └── ...
├── dependence.py
├── package.py
├── packup.sh / packup.bat
├── test.py
├── requirements.txt
└── README.md
```
## 自定义安全词库
编辑 `src/process.py` 中的 `HIGH_RISK_WORDS` 列表后重新打包部署重启:
```python
HIGH_RISK_WORDS = {
"prompt_injection": ["ignore all instructions", ...],
"memory_manipulation": ["delete memory", ...],
"info_leak": ["sudo password", ...],
"system_commands": ["cat /etc/passwd", ...],
}
```
## 许可证
MIT