pi-qq-integration
v0.5.3
Published
QQ integration for pi — control pi from QQ | pi QQ 集成 — 在 QQ 中操控 pi
Maintainers
Readme
pi-qq-integration — 中文版
在 QQ 中操控 pi。安装此扩展后,pi 启动时会自动加载扩展并默认自动连接 QQ Bot(可在配置中关闭)。连接后即可通过 QQ 向 pi 发消息、查看 session 列表、浏览历史对话;也可随时用 /qq-connect、/qq-disconnect 手动控制连接。
安装
pi install npm:pi-qq-integration快速开始
1. 注册 QQ Bot
在 QQ 开放平台 创建一个机器人应用,获取 AppID 和 AppSecret。
2. 创建配置文件
创建 ~/.pi/agent/qq-integration-config.json:
{
"appId": "你的 AppID",
"appSecret": "你的 AppSecret"
}3. 启动 pi
pi扩展加载后,pi 会话启动时会自动连接 QQ Bot(默认行为)。如需关闭自动连接,在配置文件加 "autoConnect": false 后重启 pi,再用 /qq-connect 手动连接;断开用 /qq-disconnect。
现在在 QQ 中给机器人发消息,就能和 pi 对话了。
配置项(qq-integration-config.json)
配置文件路径:~/.pi/agent/qq-integration-config.json(位于 pi 的 agent 数据目录,与扩展代码目录无关)。
顶层字段
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| appId | string | ✅ | — | QQ 开放平台机器人应用的 AppID |
| appSecret | string | ✅ | — | QQ 开放平台机器人应用的 AppSecret(敏感,勿提交 git) |
| instanceId | string | ❌ | PID | 多实例下本实例的唯一 ID(默认取进程 PID,用于 #to <PID> 切换与消息署名) |
| role | "auto" \| "leader" \| "follower" | ❌ | "auto" | 多实例角色:auto 由文件锁自动选举;leader 强制持有 QQ 连接;follower 强制经 IPC 接入 leader |
| autoConnect | boolean | ❌ | true | pi 启动时是否自动连接 QQ Bot;设为 false 则需手动 /qq-connect |
| allowedUsers | string[] | ❌ | — | 允许向 pi 发 prompt 的 c2c 用户 openid 白名单。未配置则放行所有私聊消息(会输出安全告警)。强烈建议配置,以防远程提示词注入 |
| allowedGroups | string[] | ❌ | — | 允许向 pi 发 prompt 的群 openid 白名单。未配置则放行所有 @机器人消息 |
settings 字段(转发设置)
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| forwardDesktopMessages | boolean | false | 桌面端(pi 终端)输入的消息是否转发到 QQ |
| forwardToolCalls | boolean | false | 工具调用及其结果是否转发到 QQ(与 lastMessageOnly 互斥;开启一个会自动关闭另一个,配置文件与 #settings 均强制) |
| lastMessageOnly | boolean | false | 只转发整次 agent 运行的最后一条 assistant 回复(与 forwardToolCalls 互斥;开启一个会自动关闭另一个) |
| defaultSession | object | undefined | undefined | 默认 QQ 转发目标。收到 QQ 消息时会自动更新为该消息来源会话;也可由 /qq-target 或 QQ #target 设置 |
settings内的字段既可在配置文件里静态写死,也可在 QQ 内用#settings命令动态调整并持久化。#settings命令对前两个开关使用了简写别名:forwardMessages对应forwardDesktopMessages,forwardTools对应forwardToolCalls。
完整示例
{
"appId": "你的 AppID",
"appSecret": "你的 AppSecret",
"autoConnect": true,
"role": "auto",
"settings": {
"forwardDesktopMessages": false,
"forwardToolCalls": false,
"lastMessageOnly": false
}
}环境变量
| 变量 | 说明 |
|------|------|
| QQ_INTEGRATION_DATA_DIR | 覆盖数据目录(默认 ~/.pi/agent) |
| QQ_API_BASE | 覆盖 QQ API 域名(默认 https://api.sgroup.qq.com) |
| QQ_TOKEN_API | 覆盖 Token API 地址(默认 https://bots.qq.com/app/getAppAccessToken) |
多实例
同时运行多个 pi 实例时,用文件锁选举唯一的 leader 持有 QQ 连接;其余实例作为 follower 经本地 IPC 把 QQ 收发委托给 leader(macOS/Linux 用 Unix socket,Windows 用命名管道)。
role: "auto"(默认):谁先抢到锁谁是 leader,其余自动成为 follower。role: "leader"/"follower":强制角色。follower即使 leader 宕机也不会尝试接管成为 leader。instanceId:默认即进程 PID,同时作为实例署名与#to <PID>定向路由的标识;仅在需要固定 ID 时手动设置。
消息署名 — 所有发往 QQ 的消息都会带一段引用块署名,标明消息来自哪个实例:
> 【session名-3863】
<消息内容>(session 名为当前 pi session 名;未命名时署名为 > 【PID】。)该署名同时是引用消息路由的兜底依据(见下)。
引用消息定向路由 — 在 QQ 中引用(回复)某条消息时,消息会自动路由回发送被引用消息的那个实例(基于 ref_idx 映射,60 分钟 TTL;未命中时按被引用内容中的署名唯一匹配兜底)。也就是说,想给某个特定实例发消息,直接引用它之前发的消息回复即可。
架构
QQ 用户
│
├─ 发消息 → QQ Bot 服务器 → WebSocket
│ │
│ ┌──────────▼──────────┐
│ │ pi-qq-integration │
│ │ ws-client.ts │
│ │ ↕ WebSocket │
│ │ command-handler.ts │
│ │ ↕ #cmd 解析 │
│ │ index.ts │
│ │ ↕ sendUserMessage│
│ └──────────┬──────────┘
│ │
│ ┌──────────▼──────────┐
│ │ pi 引擎 │
│ │ 处理 prompt 并回复 │
│ └──────────┬──────────┘
│ │
└─────── REST API ←──── 回复内容两个独立通道:
- WebSocket — 接收 QQ 消息(长连接,带心跳和断线重连)
- REST API — 发送回复到 QQ,按会话类型 POST 到对应端点:
/v2/users/{openid}/messages(c2c)、/v2/groups/{group_openid}/messages(群)、/channels/{channel_id}/messages(频道)
pi Slash 命令
| 命令 | 说明 |
|------|------|
| /qq-connect | 手动连接 QQ Bot |
| /qq-disconnect | 断开 QQ Bot 连接 |
| /qq-status | 查看连接状态概览(角色、锁、WebSocket、Token) |
| /qq-diagnose | 查看详细诊断信息 |
| /qq-logs | 查看最近 30 条日志 |
| /qq-logs-path | 查看日志文件路径 |
| /qq-logs-clear | 清空日志文件 |
| /qq-target | 设置/查看默认 QQ 转发目标 |
QQ 命令
在 QQ 中给机器人发送的消息,如果不以 # 开头,会直接作为 prompt 发给 pi。
| 命令 | 说明 |
|------|------|
| #help | 显示帮助 |
| #sessions [页码] | 跨项目列出全部 session,每页 10 条,最近使用在前 |
| #history [N] | 查看当前实例 session 的最近 N 条消息(默认 5) |
| #target | 将当前 QQ 会话设为默认转发目标 |
| #settings | 查看/修改转发设置(#setting 为别名) |
| #instances | 列出在线实例(ID、角色、认领会话的名字/最近消息摘要) |
| #to <PID/名称> [内容] | 查看当前绑定实例 / 切换会话到指定实例 / 向指定实例定向发送内容 |
| #create <序号/名称> | 创建新实例并复用指定 session |
| #create new [--dir <目录>] | 创建全新 session 的新实例(可指定工作目录)|
| #close <PID> [PID...] | 关闭实例(支持空格分隔多个 PID) |
桌面端消息转发
开启桌面端转发(#settings forwardMessages on)后,桌面端输入的消息会同步转发到 QQ。目标按优先级选择:
- 最近一条 QQ 消息来源的会话(收到 QQ 消息时会自动更新
defaultSession) - 手动设置的默认目标(
/qq-target或 QQ#target)——仅在尚未收到任何 QQ 消息时生效
注: 从 QQ 转发进 pi 的消息会带来源标签前缀(私聊
[QQ]、群聊[QQ群])。该前缀也用于识别并跳过桌面端回响,避免转发回环。
/qq-target c2c <用户openid> [备注] # 私聊(备注可选)
/qq-target group <群openid> [备注] # 群聊
/qq-target channel <频道id> [备注] # 频道
/qq-target # 查看当前目标(别名:show)
/qq-target clear # 清除#settings 示例
你: #settings
Bot: ## ⚙️ QQ Bot 设置
| 选项 | 状态 | 说明 |
| forwardMessages | ❌ 关 | 桌面端消息转发到 QQ |
| forwardTools | ✅ 开 | 工具调用转发到 QQ |
| lastMessageOnly | ❌ 关 | 只转发整次回复的最后一条 assistant 回复 |
你: #settings forwardTools on
Bot: ✅ **工具调用转发** 已开启,同时 `lastMessageOnly` 已自动关闭。
你: #settings lastMessageOnly on
Bot: ✅ **只转发最后一条回复** 已开启,assistant 整次运行仅发送一条最终回复;`forwardTools` 已自动关闭。文件结构
pi-qq-integration/
├── index.ts # 入口:初始化、事件、slash 命令
├── constants.ts # 集中常量(路径、URL、超时值)
├── config.ts # 配置文件读写(原子写入)
├── auth.ts # Token 管理 + 自动刷新
├── lock.ts # 文件锁(O_EXCL 原子创建)
├── ws-client.ts # WebSocket 客户端
├── api-client.ts # REST API 客户端
├── ipc.ts # IPC(leader-follower 委派;Unix socket / Windows 命名管道)
├── registry.ts # 实例注册表(原子写入)
├── routing.ts # 引用消息路由纯函数(ref_idx + 署名兜底)
├── validation.ts # session/sessionKey 校验、参考名清洗
├── session-manager.ts # Session 浏览
├── command-handler.ts # #命令解析
├── logger.ts # 文件日志(自动截断)
├── types.ts # 类型定义
└── package.json多实例细节
~/.pi/agent/
├── qq-integration.lock # 文件锁(O_EXCL 原子创建)
│ └─ JSON: { pid, startedAt, heartbeatAt } (心跳每 30 秒更新)
└── qq-integration/
├── registry.json # 实例注册表(原子写入)
└── instances/
└── <pid>.sock # IPC Unix socket(leader;Windows 为命名管道)- 第一个实例获取锁 → 成为 leader → 连接 QQ Bot
- 后续实例检测到锁 → 成为 follower → 通过 IPC 连接 leader
- leader 崩溃或退出后 PID 失效 → follower 在重连循环中自动接管锁升级为 leader(故障转移);
role: follower强制跟随时不升级 - leader 宕机期间 follower 静默重试(仅写日志,不刷 UI 提示),连接恢复时才通知
日志
所有调试日志写入 ~/.pi/agent/qq-integration.log。使用 /qq-logs 查看最近 30 条,/qq-logs-path 查看路径。日志文件达到 5 MB 自动截断。
注意事项
- Token 安全 — Token 有效期约 2 小时,自动刷新。连续 3 次刷新失败后自动断开并通知。
- 消息频率 — 主动消息每月每用户/群限 4 条(QQ 官方平台限制),被动回复较宽松。
- Session 管理 — 用
#create创建新实例(复用 session 或全新开始),#sessions列出全部 session,#close关闭实例。实例内不再支持会话切换(用#create+#to替代)。 - 设置持久化 —
#settings变更保存到配置文件,/reload不丢失。 - 群聊消息 — 仅接收 @机器人的消息。
- 配置文件 — 含 AppSecret,勿提交 git。
开发
cd ~/.pi/agent/extensions/pi-qq-integration
npm install # 安装依赖
npm run build # 编译 TypeScript
npm run typecheck # 仅类型检查
npm test # 运行测试套件(node:test,无额外开发依赖)
# 编辑代码后在 pi 中 /reload 热重载依赖 — 唯一的运行时第三方依赖是 ws(WebSocket 客户端,用于 ws-client.ts),其余全部使用 Node.js 内置模块。
贡献者
感谢 @illusionlie 报告 Windows IPC bug (#1) 并提交修复 PR (#2)。
