Files
chatrebot_aireply_plug/README.md
root 0efe9970f5 docs: 补充脚本部署细节,明确clone路径和占位符验证
- Step 6 拆分为6.1-6.5子步骤
- 6.1 新增:在目标服务器上克隆仓库(git clone + 拷贝两种方式说明)
- 6.2 新增:完整脚本清单表(26个脚本分5组,含用途说明)
- 6.3 新增:Skills引用说明(YOUR_WORKSPACE_PATH/scripts/ 路径映射关系)
- 6.4 拆分脚本替换和Skills替换为两个独立代码块
- 6.5 新增:完整性验证命令(数量检查 + 占位符残留检查)
2026-05-04 19:09:18 +08:00

606 lines
18 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:6099)
│
│ HTTP POST(事件推送)
▼
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(:6099) → 回复发送到 QQ
```
**关键通信链路(全是 HTTP,无 WebSocket):**
| 链路 | 方向 | 协议 | 端口 |
|---|---|---|---|
| NapCat → qqrebot | 事件推送 | HTTP POST | `qqrebot:25580` |
| 插件 → OpenClaw | AI 请求 | HTTP POST | `127.0.0.1:18789` |
| 插件 → NapCat | 发送回复 | HTTP POST | `napcat:6099` |
| 脚本 → NapCat | 发消息/管理 | HTTP POST | `napcat:6099` |
## 前提条件
| 组件 | 状态 | 由本仓库部署 |
|---|---|---|
| OpenClaw Gateway | 假设已运行 | ❌(由用户自行部署) |
| NapCat(Docker) | 需部署 | ✅ |
| qqrebot(消息接收器)| 需部署 | ✅ |
| openclaw_bridge 插件 | 需部署 | ✅ |
| qq-agent(AI agent) | 需创建 | ✅ |
| QQ 技能/脚本 | 需部署 | ✅ |
## 部署步骤(阅读此文档的 AI agent 请按以下顺序执行)
---
### 第1步:询问用户信息
在执行任何操作前,请 **向用户询问以下信息**,不要使用仓库中的占位符:
| 信息 | 说明 | 示例 |
|---|---|---|
| `ADMIN_QQ` | 管理员的 QQ 号(白名单使用) | `123456789` |
| `GATEWAY_TOKEN` | OpenClaw Gateway 的认证 Token | 读取 `~/.openclaw/openclaw.json` 的 `gateway.auth.token` |
| `NAP CAT_HOST` | NapCat 服务器地址(可含端口) | `127.0.0.1`(同机)或 `192.168.1.100:6099` |
| `QQREBOT_HOST` | qqrebot 服务器地址(NapCat 侧看到的) | `127.0.0.1`(同机)或 `172.17.0.1:25580`(Docker 宿主机) |
| `NEW_AGENT_ID` | 新 agent 的唯一 ID | `qq-agent` |
| `SHARED_DIR` | NapCat 与宿主机共享目录路径 | `/opt/napcat_shared` |
> `NAP CAT_HOST` 和 `QQREBOT_HOST` 可能不同:当 NapCat 和 qqrebot 运行在同一台机器上时,NapCat 用 Docker 内部地址访问宿主机 qqrebot(如 `172.17.0.1:25580`),而脚本用外部地址访问 NapCat(如 `127.0.0.1:6099`)。
---
### 第2步:通过 Docker 部署 NapCat
NapCat 是 QQ 协议实现,接收 QQ 消息并通过 **HTTP POST** 推送到 qqrebot。
#### 2.1 创建目录结构
```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.2 启动 NapCat Docker 容器
```bash
docker run -d \
--name napcat \
--restart unless-stopped \
-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
```
端口说明:
| 端口 | 是否必开 | 用途 |
|---|---|---|
| `6099` | ✅ | OneBot HTTP API(脚本发消息/群管理/取数据都用这个端口) |
| `3001` | ❌ | WebSocket Server(本教程用 HTTP POST 推送,不需要) |
| `9000` | 按需 | WebUI 管理面板(首次扫码登录可临时用) |
如果机器防扫描严格,**只开 6099** 即可;WebUI 按需用完即关。
#### 2.3 首次登录配置
> NapCat 首次启动需要扫码登录 QQ 账号。登录数据持久化在 `/opt/napcat/qq_data`。
```bash
# 查看登录二维码(日志中会打印链接)
docker logs napcat 2>&1 | grep -o 'http[s]*://[^ ]*\.png'
# 或用浏览器打开 http://<服务器IP>:9000/webui 扫码登录
# 等待登录成功
docker logs napcat -f | grep "登录成功"
```
#### 2.4 配置事件推送(HTTP POST → qqrebot)
NapCat 需要将所有消息事件通过 HTTP POST 推送到 qqrebot(端口 `25580`)。
编辑 `/opt/napcat/config/onebot11.json`:
```json
{
"http": {
"enable": true,
"host": "0.0.0.0",
"port": 6099,
"enableHttpPost": false,
"enableHttpHeartbeat": false
},
"httpPost": [
{
"url": "http://${QQREBOT_HOST}/",
"secret": ""
}
],
"ws": {
"enable": false
},
"heartbeat": {
"enable": false
},
"enableLocalFile2Url": true
}
```
> **关键说明:**
> - `httpPost` 数组中的 URL 是 NapCat 向 qqrebot 推送消息事件的目标地址
> - 如果 NapCat 和 qqrebot 在**同一台宿主机上**,`url` 通常设置为 `http://172.17.0.1:25580/`(Docker 默认网关地址)
> - 如果**不同机器**,填 qqrebot 机器可达的真实 IP
> - `ws.enable = false` — 本教程不用 WebSocket
> - `http.enableHttpPost = false` — httpPost 由专门的 `httpPost` 数组控制
应用配置:
```bash
docker restart napcat
```
#### 2.5 验证 NapCat
```bash
# 验证 HTTP API 可访问
curl -s http://localhost:6099/get_version_info | python3 -m json.tool
# 预期输出:
# {"status": "ok", "data": {"app_name": "NapCat", ...}, ...}
```
---
### 第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 配置
编辑 `config/config.toml`:
```toml
[app]
list_port = 25580
send_url = "http://${NAP CAT_HOST}:6099" # → 插件回复时调 NapCat HTTP API 用
[rebot]
id = ""
[plugins]
dir = ["plugins"]
```
> **`send_url`**:qqrebot 框架用它作为 NapCat HTTP API 的基础地址。插件中的 `ctx.group.url` 来自此值,后续所有 `send_private_msg` / `send_group_msg` 调用都走这个地址。如果 NapCat 和 qqrebot 同机,填 `http://127.0.0.1:6099`。
#### 3.3 创建 systemd 服务
```ini
# /etc/systemd/system/qqrebot.service
[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
```
```bash
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 地址(端口 6099)
sed -i "s|YOUR_NAP CAT_HOST:25570|${NAP CAT_HOST}:6099|g" *.py
sed -i "s|YOUR_NAP CAT_HOST|${NAP CAT_HOST}:6099|g" *.py
sed -i "s|YOUR_NAPCAT_HOST:25570|${NAP CAT_HOST}:6099|g" *.py
sed -i "s|YOUR_NAPCAT_HOST|${NAP CAT_HOST}:6099|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"
done
```
> ⚠️ Skills 的替换很关键:如果漏掉,agent 调脚本时会指向不存在的旧路径。
#### 6.5 验证完整性
```bash
# 脚本数量
echo "scripts: $(ls "${AGENT_WORKSPACE}/scripts/" | wc -l) 个"
# 确认无残留占位符
if grep -r "YOUR_ADMIN_QQ\|YOUR_WORKSPACE_PATH" "${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. 在 QQ 上给机器人发消息
2. 检查 qqrebot 日志:`journalctl -u qqrebot -f | grep OpenClawBridge`
3. 检查 OpenClaw 日志:`journalctl -u openclaw -f`
4. 验证 agent 已回复
---
## 脚本适配说明
### 端口对照
| 组件 | go-cqhttp | NapCat(Docker) |
|---|---|---|
| HTTP API 端口 | `25570` | **6099** |
| WebSocket | `25570`(兼用) | 不启用(本教程) |
> 脚本中 `CQHTTP_URL = "http://YOUR_NAP CAT_HOST:25570"` 替换后变为 `http://<host>:6099`。
### 文件发送与共享目录
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_NAP CAT_HOST:25570` | `${NAP CAT_HOST}:6099` | 所有脚本 |
| `YOUR_NAP CAT_HOST` | `${NAP CAT_HOST}:6099` | 所有脚本 |
| `YOUR_NAPCAT_HOST` | `${NAP CAT_HOST}:6099` | 部分脚本 |
| `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` |
| `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 :6099)
│ ├── 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