dsh-adapter-qq
dsh-adapter-qq 是针对 DeepSeek Harness (DSH) 深度定制的 QQ 官方机器人(C2C 单聊模式)适配器插件。
通过本插件,你可以在手机或桌面 QQ 聊天窗口中直接与 DSH Agent 进行完整对话,享受 DSH 的全量编码与执行能力(文件读写、Shell 执行、代码运行、子代理、多步规划、工作流),并实现与 DSH Web UI 实时双向同屏联动。
当前插件版本:0.2.3。本次更新:/usage [日|月|年|累计] 支持统计范围切换,新增费用/调用/Token/缓存等统计卡片与最近 30 天用量热力图;模型名使用计费目录显示名,站点使用中转登记名称并对未知域名脱敏;渲染图片后的文字说明改为默认关闭(sendOverviewCaption)。此外新增 GitHub Actions 自动发布 npmjs + GitHub Packages。0.2.1 起支持 官方扫码绑定:设置 → 插件 → QQ 机器人 → 「生成绑定二维码」。详见 CHANGELOG.md。
兼容性:面向 DSH 0.2.1-rc.3(engines.dsh: >=0.2.1-rc.3 <0.3.0),Node.js ≥ 20。
已适配 DSH 0.2.1 的 SessionPromptRequest.mode(queue/steer)、ApprovalRequestEvent.agent、permissionPresets.catalog()、skills 服务与 sessionTitle/sessionQuery 标题读取;旧版本 DSH 不再保证兼容。
🆕 0.2.3 更新摘要
/stats 统计卡片:会话统计改为 Typst 卡片(8 张指标卡 + Token 明细表),与 /usage 视觉统一。
- 菜单动态预设:底部菜单新增「模型与思考」「权限模式」子菜单,按当前模型的思考等级与已配置权限动态生成带参数项(
/effort high、/permission workspace-write);原交互式 /effort、/permission 保留。
/usage 范围与可视化:/usage 日|月|年|累计(默认本月);费用/调用/Token/平均成本/缓存命中率/输入输出比/思考占比/峰值日统计卡片;最近 30 天费用热力图;模型名取计费目录显示名,站点名取中转登记名称,未登记域名脱敏。
- 图片说明默认关闭:
/usage、/status、/tasks、/jobs、/stats 发完图片后不再补发文字块;需要时在设置中开启 sendOverviewCaption。
- CI 自动发布:
.github/workflows/publish.yml 在 v* tag 或手动触发时先测试,再发布 npmjs 与 GitHub Packages(GitHub Packages 使用 @<owner>/dsh-adapter-qq 作用域副本)。
- 此前 0.2.2 能力:会话列表引用块层级、路径/预设/权限可读名称、
/status /tasks /jobs、官方扫码绑定。
🌟 核心特性
- 📱 QQ 官方 OpenAPI v2:基于 WebSocket Gateway 长连接(接收
C2C_MESSAGE_CREATE 与 INTERACTION_CREATE)+ OpenAPI HTTP 发送消息,无需第三方逆向协议,稳定合规。
- 🔄 实时双向同屏同步:
- 在 QQ 中提问,Web UI 对应会话实时展现提问并同步生成结果。
- 在 Web UI 中提问或执行操作,QQ 端实时推送同步进展与回复。
- 🚦 双向审批联动(Approval Waterfall):
- 遇到超权限操作(如文件修改、系统命令等)时,审批卡片同时推送至 QQ 与 Web UI。
- 支持在 QQ 交互按钮上一键点击
[允许 (本次)] 或 [拒绝],两端任一端处理立即同步结算。
- ❓ 多问题 / 多选提问支持:
ask_user_question 一次提交多个问题时按「第 1/3 题」向导逐题作答,全部答完后一次性提交完整答案批次(修复「连续多个提问只收到第一个」)。
- 多选题显示
✅ 选中状态,可反复点选、🗑️ 清空,或直接回复 /answer <ID> A,B,最后点 ✅ 提交选择。
- 🎮 交互式操作板(InlineKeyboard):
- 支持在聊天中生成交互式按钮面板,一键切换会话、选择预设、切换权限,无需繁琐输入。
- 🗂️ 分页会话列表 + emoji 会话标识:
- 会话列表跨工作区展平分页(默认每页 6 个,可配置),每页内为每个会话分配互不重复的 emoji(🍎🍊🍋…)作为按键标识,列表里在会话名后附加同一 emoji。
- 工作区路径可按配置显示完整路径或仅最后一级文件夹(
sessionPathDisplay,默认 tail)。
- 同一工作区下的会话合并为一个
> 引用块,形成「工作区 → 会话」的层级;会话名后的预设/权限使用可读名称(如 标准模式 / 工作区写入),不再直接显示 standard / workspace-write 这类 ID;自定义预设仍显示其 DSH 名称。
/current 的预设/权限同样使用可读名称。
- 支持点击按键、
/switch <序号>、/switch <emoji>、/switch <标题关键字> 三种切换方式。
- 🧭 任务与代理状态图片(Typst 渲染):
/status(/状态、/代理):一张图查看主代理状态(标题/模型/预设/权限/目录)、团队成员或子代理状态,以及正在进行的后台任务。
/tasks(/任务、/任务管理):一张图查看 DSH「任务」页的定时/自动化任务(规则、状态、计划时间、绑定会话)。
/jobs(/后台任务):仅在启用官方持久终端(@deepseek-ai/dsh-terminal)时自动注册,查看运行中的后台任务。
- 官方团队插件(Agent Teams)启用时,
/status 使用其 roster 渲染 Lead/成员角色与状态;未启用时回退到普通子代理列表。
- 示例(主代理 + 团队成员 + 后台任务):
代理与后台任务状态图
📸 运行效果展示 (Showcase)
1. 工作区与会话列表 (/sessions) | 2. Agent 交互提问 (ask_user_question) |
|---|
| 工作区与会话列表(引用块层级) | Agent 交互提问 |
| 层级化对齐 DSH 侧边栏,支持按键一键切换 | 紧凑 A/B/C/D 操作板,点击即回传 Agent |
3. 双向权限审批联动 (/approve / /reject) | 4. 实时工具调用执行进度 (可选聚合) |
|---|
| 双向权限审批 | 工具调用执行 |
| QQ 与 Web UI 实时互斥结算,绝不悬挂 | 工具执行进度秒级感知,多操作自动聚合防刷屏 |
5. 会话统计数据 (/stats 统计卡片) | 6. 模型选择与翻页 (/model 操作板) |
|---|
| 统计卡片 | 模型切换操作板 |
| 轮次、步数、LLM耗时、TTFT及缓存命中率 | 支持多供应商模型识别与上一页/下一页翻页 |
7. 思考等级管理 (/effort 操作板) | 8. QQ 图片同步至 Web UI 聊天气泡 |
|---|
| 思考等级操作板 | QQ 图片同步至 Web UI |
| 支持 off/low/medium/high/xhigh/max 实时切换 | QQ 发送图片原生呈现在 Web UI 聊天流 |
| 9. QQ 文件接收并保存至工作区 |
|---|
| QQ 文件接收保存 |
| QQ 发送文件自动保存至 uploads/ 并通知 Agent |
📋 架构设计
QQ 开放平台 (q.qq.com)
│
├─ WebSocket Gateway ───────▶ QQGatewayClient (lib/qq/gateway.js)
│ (Hello, Heartbeat, │ 分发 C2C_MESSAGE_CREATE / INTERACTION_CREATE
│ Identify, Resume) ▼
│ MessageBridge (lib/sync/message-bridge.js)
├─ HTTP REST API ◀────────── ├─ 指令解析器 (/sessions, /switch, /skills, /mcp, /render, /send ...)
│ (POST /v2/users/.../messages) ├─ 交互操作板构建器 (lib/ui/keyboard.js + lib/ui/emoji.js)
│ (POST /v2/users/.../files) ├─ 消息流式分段与清洗
│ (PUT /v2/menu 快捷菜单) ├─ 富媒体出站(图片/文件转发、渲染图回传)
│ ▼
│ SessionManager (lib/sync/session-manager.js)
│ │ 会话分页 / emoji 分配 / 标题与权限读取
│ ▼
│ DeepSeek Harness 核心运行时 (Cordis Framework)
│ ├─ ctx.sessions / ctx.sessionController (会话与 prompt)
│ ├─ ctx.on('session/event') (双向消息监听)
│ ├─ ctx.on('approval/request') (双向审批竞态)
│ ├─ ctx.skills / ctx.permissionPresets
│ └─ ctx.tools (qq_render_text_image / qq_send_file)
│ ▲
├───────────────────────────── ApprovalHandler (lib/sync/approval-handler.js)
├───────────────────────────── AdminInventory (lib/sync/inventory.js)
│ └─ POST /dsh-mcp-manager/api(技能/MCP 启停;缺失则只读降级)
└───────────────────────────── Render pipeline (lib/render/*)
└─ Typst(内嵌)→ Edge/Chrome headless → Pillow → SVG 兜底
🚀 快速上手
1. 准备 QQ 开放平台机器人凭证
- 前往 QQ 开放平台官网 注册并登录,创建机器人应用:
- 个人开发者创建的默认单聊机器人即可直接使用,无需复杂配置。
- 在 开发设置 中获取:
AppID(机器人应用 ID)
AppSecret(开发者密钥)
- 机器人调试:若机器人尚未公开发布上线,建议开启沙箱环境 (
sandbox: true) 进行测试。
🚀 安装与部署
本插件是标准 DSH Bundle 插件包,声明了 dsh.bundle.patch 和 dsh.client,通过 DSH 官方 CLI 命令一行即可完成安装与自动挂载:
1. 安装插件
从 npm 官方源安装(推荐):
dsh plugin --profile web add dsh-adapter-qq
或从 GitHub 仓库安装:
dsh plugin --profile web add github:jixishi/dsh-adapter-qq
卸载插件:
dsh plugin --profile web remove dsh-adapter-qq
2. 在 DSH Web UI 中配置
安装完成后,启动 DSH Web 界面(默认 http://127.0.0.1:3080),进入 设置 (Settings) → 插件(Plugins) 页面,点击顶部的 【QQ 机器人】 tab 进行配置:
推荐:扫码绑定 —— 点击「生成绑定二维码」,用手机 QQ 扫码并按提示确认;成功后会自动填入 AppID、AppSecret 与绑定 OpenID 并保存。二维码约 2 分钟有效,过期可重新生成。若 q.qq.com 拒绝或网络异常,界面会显示 [code] message、retcode 与 detail,不会静默失败。
DSH 0.2.1 的设置入口是「设置 → 插件」页内的 tab(与本机 CliProxyAPI 等插件一致);旧版本的「设置 → QQ 机器人卡片」已不存在。配置字段全部声明为 volatile,保存后会写入 profile patch 并即时热应用(修改 AppID/AppSecret/沙箱后自动重连,无需重启 DSH);仅升级插件版本后 host 半更新需重启一次。版本更新记录见 CHANGELOG.md。
| 配置项 | 说明 | 默认值 |
|---|
enabled | 是否启用 QQ Bot 适配器 | true |
appId | 填写 QQ 开放平台的 Bot AppID | "" |
clientSecret | 填写 QQ 开放平台的 AppSecret(密文遮罩) | "" |
sandbox | 是否连接沙箱开发环境(测试期间推荐勾选) | false |
userOpenid | 绑定的专属用户 OpenID(留空将在收到首条消息时自动绑定) | "" |
defaultPreset | 新建会话默认 Agent 预设 | "standard" |
defaultCwd | 新建会话默认工作目录(留空使用当前 DSH 工作区) | "" |
autoRegisterMenu | 启动后自动向 QQ 开放平台注册底部自定义快捷菜单 | true |
markdown | 消息回复优先使用 Markdown 渲染 | true |
syncToolCalls | 是否同步推送工具调用执行进度(防刷屏,默认关闭) | false |
toolCallAggregateWindowMs | 工具调用聚合推送窗口时间(毫秒,默认 30000ms / 30秒) | 30000 |
sessionPageSize | 会话列表每页数量(QQ 操作板建议 ≤6) | 6 |
sessionPathDisplay | 会话列表工作区路径显示:tail 仅最后一级文件夹 / full 完整路径 | tail |
autoSendAttachments | Agent 回复中的图片/文件自动转发到 QQ |
保存后,插件会立即热重载配置并自动建立 WebSocket 连接,无需重启 DSH。
💬 交互指令与操作说明
在 QQ 单聊窗口中,您可以直接发送以下指令或在底部菜单/操作板中点击按钮:
1. 会话管理与工作区导航
| 指令 | 简写/别名 | 功能说明 |
|---|
/sessions [页码] | /会话列表, /list | 分页展示所有会话(跨工作区展平),每页内每个会话带互不重复的 emoji 标识,操作板可点击切换/翻页 |
/new | /新建会话, /create | 启动交互式新建会话向导:选择已有工作区(本地/远程)或进入目录浏览器 |
/switch <序号|emoji|ID> | /切换 <…> | 切换当前活跃会话(支持全局序号如 /switch 3、当前页 emoji 如 /switch 🍊、会话 ID 前缀或标题关键字) |
/current | /当前会话, /info | 查看当前活跃会话的详细信息与操作板 |
/status | /状态, /代理 | 图片查看主代理、团队成员(启用 Agent Teams 时)/子代理状态,以及正在进行的后台任务 |
/tasks | /任务, /任务管理, /schedule | 图片查看 DSH「任务」页的定时/自动化任务(规则、状态、计划时间、绑定会话) |
/jobs | /后台任务 | 图片查看运行中的后台任务;仅在启用官方持久终端时自动注册 |
/usage [日|月|年|累计] | /用量, /费用, /账单 | 图片查看指定范围的费用/调用/Token/缓存指标、模型/站点分布与 30 天热力图;仅在安装 @kenz1117/dsh-ui-usage-billing 时自动注册 |
新建会话交互向导流程:
- 工作区选择 (第 1 步):发送
/new,操作板展示所有已有工作区(如 📁 免费:~ (远程), 📁 qq-bot, 📁 AutoAim)及【🔍 浏览并选择目录】。
- 目录选择与浏览 (第 2 步):支持按键深入子目录、
⬆️ 上级目录、➕ 新建目录、📄 上页/下页 翻页。
- 完成创建:点击【✅ 选定当前目录创建】,即可完成会话创建并自动绑定为活跃会话!
2. 预设、模型与权限指令
| 指令 | 说明 |
|---|
/model | 查看当前会话模型及所有可用模型列表,附带一键切换操作板 |
/model <名称或序号> [供应商] | 为当前会话切换 AI 模型(如 /model gpt-5.6-luna 或 /model 2) |
/effort [等级] 或 /思考 | 查看或切换思考等级(off, low, medium, high, xhigh, max),附带操作板 |
/stats 或 /统计 | 以 Typst 统计卡片 图片展示当前会话统计(轮次/步数、LLM/工具耗时、首字延迟、生成速度、缓存命中率、Token 明细),对齐 WebUI 底栏 |
/preset | 显示当前预设及所有动态获取的可用预设列表(内置 + 自定义),附带切换按钮 |
/preset <名称> | 为当前会话切换预设(如 /preset ptc,未产生交互前可换) |
/permission | 显示当前权限级别及切换操作板 |
/permission <模式> | 切换权限模式:只读 (read-only)、工作区 (workspace-write)、全系统 (danger-full-access) |
3. 技能 / MCP / 渲染与文件发送
| 指令 | 说明 |
|---|
/skills [页码] 或 /技能 | 技能管理:分页列出技能(名称/来源/可调用性/启停状态),点击进入详情,支持 ✅/⛔ 状态展示 |
/skill <名称> | 查看单个技能详情(来源、provider、路径、适用场景、模型/用户可调用性) |
/skill on|off <名称> | 启用 / 停用技能(需安装 @xxxyz/dsh-mcp-manager,否则只读并提示) |
/mcp [页码] 或 /服务 | MCP 服务管理:分页列出服务(传输、层级、加载状态、工具数) |
/mcp <ID或名称> | 查看单个 MCP 服务详情与工具清单 |
/mcp on|off <ID> | 启用 / 停用 MCP 服务 |
/mcp restart <ID> | 重启 MCP 服务 |
/render [文本] 或 /渲染 | 把文本/Markdown 渲染成图片并发回 QQ;不带参数时渲染当前会话最近一条 Agent 回复 |
/send <路径> 或 /发送文件 | 把本地文件发送到 QQ(相对路径按当前会话工作目录解析) |
Agent 可调用工具(由插件注册到 DSH):
| 工具 | 说明 |
|---|
qq_render_text_image | 把 Markdown/纯文本渲染成图片(text 必填;title/theme/width/send/filename 可选),默认同时发送到当前绑定的 QQ 会话,返回本地文件路径与尺寸 |
qq_send_file | 把本地文件或 base64 内容发送到 QQ(path 或 data_base64,as_image/filename/msg_id 可选) |
渲染引擎优先级:内嵌 Typst(霞鹜新晰黑 + Google 全彩 Emoji)→ 本机 Edge/Chrome 无头截图 → Pillow(需 Python + Pillow)→ 纯 SVG 兜底。可用环境变量 QQ_ADAPTER_BROWSER 指定浏览器路径、QQ_ADAPTER_PYTHON 指定 Python 解释器。
4. 实时执行同步
在活跃会话中,Agent 的所有实时执行动作均会推送到 QQ:
- 🛠️ 工具调用过程提示:如
⚙️ [Agent 正在执行] 调用工具: pwsh ...。
- 💬 最终思考与回复:清洗内部控制标记后完整呈现,长文本自动智能分段,且被动回复过期时自动优雅降级为主动消息,避免漏发。
- 🖼️ 回复中携带的图片/文件会自动转成 QQ 富媒体消息(
autoSendAttachments 可关闭)。
5. 执行控制与辅助指令
| 指令 | 说明 |
|---|
/cancel 或 /stop | 中止当前 Agent 正在运行的轮次 |
/approve [ID] | 批准待审批请求(支持操作板一键点击) |
/reject [ID] | 拒绝待审批请求(支持操作板一键点击) |
/answer <ID> <选项> | 回答 Agent 的提问;多选题可回复 A,B 或点击操作板逐个选择后提交 |
/menu | 手动强制向 QQ 开放平台同步底部快捷菜单 (PUT /v2/menu) |
/help | 显示使用帮助菜单与全局快捷操作板 |
4. 自由对话
在设置活跃会话后,发送任意非 / 开头的文本,将直接转发给 DSH Agent:
- Agent 思考与执行过程在 QQ 与 Web UI 实时同步。
- 回复内容支持 Markdown 代码高亮、表格与长文本自动分段。
- Web UI 中的提问与操作亦会实时推送到 QQ 聊天中。
🧪 单元测试
本项目内置完整的单元测试套件(覆盖 API 客户端、媒体嗅探/富媒体上传、InlineKeyboard 与 emoji 操作板、会话分页、Gateway 网关协议、审批流与多问题/多选提问、消息桥接、渲染引擎与 agent 工具):
# 运行全部测试
pnpm test
测试结果(DSH 0.2.1-rc.3 / Node 26,本机无头浏览器受限时浏览器用例会跳过):
✔ QQApiClient (22 tests passed)
✔ QQ media helpers (35 tests passed)
✔ KeyboardBuilder (19 tests passed)
✔ Session emoji palette (5 tests passed)
✔ SessionManager (17 tests passed)
✔ QQGatewayClient (6 tests passed)
✔ QQ scan-to-bind protocol (11 tests passed)
✔ ApprovalHandler / multi-question (5 tests passed)
✔ MessageBridge (27 tests passed)
✔ Task overview (11 tests passed)
✔ Usage billing integration (12 tests passed)
✔ Render engines (33 passed, 1 skipped)
✔ Typst engine / markdown conversion (7 tests passed)
✔ qq_render_text_image tool (14 tests passed)
✔ AdminInventory (27 tests passed)
✔ qq_send_file tool (20 tests passed)
ℹ tests 277
ℹ pass 276
ℹ skipped 1
ℹ fail 0
📦 自动发布(GitHub Actions)
工作流:.github/workflows/publish.yml
- 触发:推送
v* tag,或在 Actions → Publish → Run workflow 手动执行。
- 流程:
pnpm install --frozen-lockfile → pnpm test → 校验 tag 与 package.json 版本一致 → 打包一次 → 发布 npmjs(OIDC)→ 同一产物准备 GitHub Packages 副本 → 再发布。
- npmjs(可信发布 / Trusted Publishing):发布
dsh-adapter-qq@<version> 到 https://registry.npmjs.org/,使用 GitHub OIDC,不需要 NPM_TOKEN。
- 前置条件(npm 官方要求):本仓库
package.json 的 repository.url 必须与仓库完全一致(当前为 git+https://github.com/jixishi/dsh-adapter-qq.git);workflow 文件名必须与 npmjs.com 上的配置一致(当前 publish.yml);workflow 需声明 permissions: id-token: write;npm CLI ≥ 11.5.1(workflow 已自动校验);仅支持 GitHub 托管 runner。
- workflow 会先清除
.npmrc 中任何 _authToken,并在检测到 NODE_AUTH_TOKEN 时直接失败——否则 token 会静默覆盖 OIDC。
- npmjs.com 的 Trusted Publisher 配置需在 2 天内完成首次成功发布才会从
Pending validation 转为已生效;过期需删除重建。
- 首次发布由 OIDC 自动生成 provenance,无需
--provenance。
- GitHub Packages:发布
@<owner>/dsh-adapter-qq@<version> 到 https://npm.pkg.github.com/,使用自动注入的 GITHUB_TOKEN(workflow 已声明 packages: write)。GitHub Packages 的 npm registry 只接受作用域包,因此 .github/scripts/prepare-gh-package.mjs 会在 CI 中把包名与 cordis.patch.yml 改成 @<owner>/dsh-adapter-qq 后再打包;仓库内的默认包名保持 dsh-adapter-qq 不变。
- 去重:目标 registry 已存在同版本时自动跳过,重复运行安全。
- 补发已存在的 tag:早于本 workflow 的 tag(如
v0.2.2)不会自动触发;在 Actions 里手动跑一次 Publish 即可补发(版本取自 package.json)。
- 从 GitHub Packages 安装:
dsh plugin add @<owner>/dsh-adapter-qq@<version>(作用域副本的 bundle patch 已同步改写)。
❓ 常见问题排查 (Troubleshooting)
- 收到报错
11255 或发消息无响应?
- 检查
sandbox 配置是否与后台所处环境(测试沙箱 vs 正式)一致。
- 检查 AppID 与 AppSecret 是否填写正确。
- 提示 DNS 解析失败或连不上
bots.qq.com?
- 如果开启了代理软件(如 Clash、Shadowrocket TUN 模式等带有 fake-ip 功能),请确认
bots.qq.com 与 *.qq.com 直连,避免 fake-ip 解析异常拦截握手请求。
- 切换预设提示
session has already started; its agent preset is fixed?
- DSH 原生架构约定:会话产生第一轮对话后,其 Agent 预设插件树即固化,不可热变更预设。如需使用其他预设,请使用
/new [目录] <预设名> 创建新会话。
- 审批按钮点击无反应?
- 检查审批是否已在 Web UI 端先行处理;或者审批已超时关闭。两端任意一端处理后,状态会自动同步并提示已结算。
- QQ 发图报
Declared image type does not match its bytes.?
- 0.2.0 已修复:插件改为按字节魔数判定真实图片格式(png/jpeg/gif/webp),不再信任 QQ 的
content_type。若仍出现,请确认插件版本 ≥ 0.2.0 且 DSH 为 0.2.1-rc.3。
/skills 或 /mcp 提示只读 / 未安装管理器?
- 启停能力依赖
@xxxyz/dsh-mcp-manager(其 HTTP API 必须可访问)。未安装或未启用时,菜单自动降级为只读列表;安装后发送 /skills 或 /mcp 刷新即可。
/render 很慢或提示回退引擎?
- 默认使用内嵌 Typst(无需系统安装任何东西),中文与全彩 Emoji 由随包字体渲染,通常几十毫秒完成;若 Typst 不可用才回退本机 Edge/Chrome 无头截图 → Pillow → SVG。可用
QQ_ADAPTER_BROWSER 指定浏览器路径(设为 off 跳过浏览器),QQ_ADAPTER_PYTHON 指定 Python。
- 若 Typst 报错,插件日志会打印最后三行 Typst 诊断(
[adapter-qq] Typst 渲染失败 ...)。
- 发送大文件失败?
- QQ 单聊文件软限制 200MB,>5MB 会自动走分片上传(prepare → 分片 PUT → part_finish → merge);若网络中断请重试。图片 >20MB 会被 QQ 降级为文件类型上传。
📄 开源许可证
本项目基于 MIT License 开源。