🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

QQ群聊通道 104laiye/dsh-qq-group-plugin

DeepSeek Harness
104laiye13 天前有提交已提供中文文档扫描:含敏感能力

在QQ群里@机器人,用手机远程指挥电脑上的智能体

29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/24 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add 104laiye/dsh-qq-group-plugin
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么[目录]—
dsh 原生插件 · platform
暂无时间戳·判据 →
装得上吗[实装验证]—
本站尚未做安装检查
暂无时间戳·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 13 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 47 处,展示前 45 条)
  • 发起网络请求
    client.js:151
    void fetch(`${PREFIX}/client-error`, {
  • 发起网络请求
    client.js:530
    const response = await fetch(path, {
  • 写入本地文件
    lib/log.js:54
    mkdirSync(dirname(logFile), { recursive: true })
  • 写入本地文件
    lib/log.js:78
    appendFileSync(logFile, line)
  • 读取本地文件
    lib/log.js:87
    if (statSync(logFile).size <= MAX_LOG_BYTES) return
  • 写入本地文件
    lib/log.js:92
    renameSync(logFile, `${logFile}.1`)
  • 写入本地文件
    lib/paths.js:79
    mkdirSync(workspace, { recursive: true })
  • 写入本地文件
    lib/paths.js:94
    mkdirSync(join(home, WORKSPACE_DIR_NAME), { recursive: true })
  • 写入本地文件
    lib/paths.js:177
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/paths.js:179
    writeFileSync(probe, 'ok', 'utf8')
  • 删除本地文件
    lib/paths.js:180
    rmSync(probe, { force: true })
  • 写入本地文件
    lib/runtime.js:2129
    writeFileSync(path, plan.text, 'utf8')
  • 读取本地文件
    lib/runtime.js:3073
    if (!existsSync(entry.path)) {
  • 读取本地文件
    lib/runtime.js:3115
    info = statSync(path)
  • 读取本地文件
    lib/routes.js:264
    const text = readFileSync(logPath(), 'utf8')
  • 写入本地文件
    lib/media.js:73
    mkdirSync(dir, { recursive: true })
  • 发起网络请求
    lib/media.js:174
    const response = await fetch(url, { signal: AbortSignal.timeout(30_000) })
  • 写入本地文件
    lib/media.js:190
    writeFileSync(path, data)
  • 读取本地文件
    lib/session-index.js:122
    const raw = await readFile(join(storeDir, name), 'utf-8')
  • 读取本地文件
    lib/session-index.js:174
    const entries = await readdir(root, { withFileTypes: true })
  • 读取本地文件
    lib/session-index.js:281
    await stat(join(indexDir, name))
  • 读取本地文件
    lib/session-index.js:291
    const entries = await readdir(join(home, 'sessions', folder), { withFileTypes: true })
  • 读取本地文件
    lib/state.js:295
    text = await readFile(this.#file, 'utf8')
  • 写入本地文件
    lib/state.js:310
    renameSync(this.#file, `${this.#file}.corrupt`)
  • 写入本地文件
    lib/state.js:358
    mkdirSync(dirname(this.#file), { recursive: true })
  • 写入本地文件
    lib/state.js:365
    writeFileSync(temp, `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 })
  • 删除本地文件
    lib/state.js:393
    unlinkSync(temp)
  • 读取本地文件
    verify-ack.mjs:11
    const src = readFileSync(new URL('./lib/runtime.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-ack.mjs:12
    const settingsSrc = readFileSync(new URL('./lib/settings.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-ack.mjs:13
    const clientSrc = readFileSync(new URL('./client.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-behavior.mjs:12
    const src = readFileSync(new URL('./lib/runtime.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-groups.mjs:9
    const runtimeSrc = readFileSync(new URL('./lib/runtime.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-groups.mjs:113
    const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'))
  • 读取本地文件
    verify-groups.mjs:114
    const routesSrc = readFileSync(new URL('./lib/routes.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-groups.mjs:115
    const credSrc = readFileSync(new URL('./lib/credentials.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-groups.mjs:116
    const clientSrc = readFileSync(new URL('./client.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-groups.mjs:117
    const indexSrc = readFileSync(new URL('./index.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-member-session.mjs:16
    const runtimeSrc = readFileSync(new URL('./lib/runtime.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-member-session.mjs:17
    const clientSrc = readFileSync(new URL('./client.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-persona.mjs:14
    const runtimeSrc = readFileSync(new URL('./lib/runtime.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-persona.mjs:15
    const settingsSrc = readFileSync(new URL('./lib/settings.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-persona.mjs:16
    const clientSrc = readFileSync(new URL('./client.js', import.meta.url), 'utf8')
  • 读取本地文件
    verify-persona.mjs:17
    const indexSrc = readFileSync(indexPath, 'utf8')
  • 读取本地文件
    verify-persona.mjs:56
    check('prompt.js 仍接受 persona 参数(兼容既有测试)', /persona = ''/.test(readFileSync(new URL('./lib/prompt.js', import.meta.url), 'utf8')))
  • 读取本地文件
    verify-title.mjs:12
    const routerSrc = readFileSync(new URL('./lib/router.js', import.meta.url), 'utf8')
扫描于 2026/11/4(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
展开完整介绍(127 字)↓

DeepSeek Harness 的 QQ 群聊增强通道(fork of xcisxc29/dsh-qq-plugin):在 QQ 群里 @ 机器人就能远程指挥你电脑上的 agent。每个群友独立会话,人设走系统提示段;私聊群聊、图片文件双向、主动推送。

README

由 DeepSeek 最新模型翻译生成
dsh-qq-group-plugin 在 QQ 里用手机指挥这台电脑上的 DeepSeek Harness 智能体——私聊可以,在群里 @ 它也可以。 走腾讯官方 QQ 机器人通道(api.bot.qq.com,扫码绑定),不需要公网 IP、不需要反向代理,中间也没有第三方协议客户端。绑定一次,之后一直有效。 能在当前的 DSH 桌面端上跑 —— 针对 DSH 0.2.0-rc.2 开发和实测。 这是 fork 基于 xcisxc29/dsh-qq-plugin v1.0.5 改造,加的是群聊支持。原版只做 1:1 私聊,群消息直接丢弃。改动范围见相对上游改了什么;版权与许可沿用上游 MIT,原作者声明保留在 LICENSE。 包名、服务名、会话目录、状态目录、凭据 scope 全部加了 -group / _groups 后缀,所以本包与上游可以同装在一个配置档里,互不覆盖。 这是 dsh-wechat-plugin 的 QQ 版本,功能与它对齐;有几处有意不同,因为 QQ 协议本来就不需要微信那套机器(见与微信版的差异)。 本仓库目前只有中文 README。
展开完整文档(README 剩余 1 节)
dsh-qq-group-plugin

在 QQ 里用手机指挥这台电脑上的 DeepSeek Harness 智能体——私聊可以,在群里 @ 它也可以。

走腾讯官方 QQ 机器人通道(api.bot.qq.com,扫码绑定),不需要公网 IP、不需要反向代理,中间也没有第三方协议客户端。绑定一次,之后一直有效。

能在当前的 DSH 桌面端上跑 —— 针对 DSH 0.2.0-rc.2 开发和实测。

这是 fork

基于 xcisxc29/dsh-qq-plugin v1.0.5 改造,加的是群聊支持。原版只做 1:1 私聊,群消息直接丢弃。改动范围见相对上游改了什么;版权与许可沿用上游 MIT,原作者声明保留在 LICENSE。

包名、服务名、会话目录、状态目录、凭据 scope 全部加了 -group / _groups 后缀,所以本包与上游可以同装在一个配置档里,互不覆盖。

这是 dsh-wechat-plugin 的 QQ 版本,功能与它对齐;有几处有意不同,因为 QQ 协议本来就不需要微信那套机器(见与微信版的差异)。

本仓库目前只有中文 README。

一句话要一个文件,它就出现在手机上:在 QQ 里说「把我电脑上桌面那张 DSH 自画像发过来」,智能体在电脑上找到那个文件、发回来,并在下面回一句「已发送 ✅ 桌面上的「DSH 自画像.png」(29 KB,PNG)」。
输入框右边那个 + 是附件入口——图片、视频、语音、文件都从那里发进去(见媒体双向)。

功能

- 群里 @ 它就行(本 fork 的核心改动):GROUP_AT_MESSAGE_CREATE 事件一律放行,每个群友独立会话,同一个群里各聊各的互不串台。
- 文字双向:QQ 消息变成 DSH 提示词,回复发回 QQ。
- 图片、文件、语音进来,图片、视频、文件出去:收到的附件落盘到会话工作区并交给智能体;智能体用 send_to_qq 把本机文件发回来。超长回复自动转成 .md 文件发回手机。
- 一个 QQ 对话,多个 DSH 会话:/new、/list、/switch、/current、/cancel,或者直接说「换个对话」。列表分会话夹与会话两层。
- 模型与推理等级也能在手机上换:/model 列出模型和各自的推理等级, /model 2、/model 等级 high 直接切换,对下一步生效。
- 在手机上回答权限与提问:权限审批回「允许」/「拒绝」(或数字选项),智能体的二选一/多选提问带编号发到 QQ,回个数字就行——离开电脑时回合不会再卡住。
- 主动推送:notify_qq 让这台机器上的任意会话都能给你发消息,这正是「干完了告诉我」的实现。实测可用:连发十条消息全部送达,其中后六条走的就是主动推送。
(腾讯对主动推送的规则会变,插件不假设额度;任何原因没送达都会进队列,等你下次说话时先补发。)
- 定时任务:用 DSH 宿主自带的 schedule_create / schedule_list / schedule_delete / schedule_update,说「23:12 叫我」就行。插件不重复实现 DSH 已有的能力,只做通道。
- 设置页:设置 → QQ,九个设置项、带原生文件夹选择器、带诊断区。

⚠️ 群聊有两条平台限制,不是插件的毛病:被动回复窗口在群里是 5 分钟 / 最多 5 次(私聊是 60 分钟);主动推送需要群主在手机 QQ 里给机器人开「主动推送消息能力」,没开时 notify_qq 报 40034105 无权限。两条路会同时断掉,表现是群里彻底静默。
详见 用户手册里的群聊一节与下面的安全。

安装

给 DSH 桌面端用的,装在一台一直开着的机器上。它需要 DSH 的工作区、工具与 UI 服务——也就是标准的桌面端组合。

| DSH 桌面端 | @deepseek-ai/dsh-desktop 0.2.0-rc.2 或更高 |
| 手机 | 能装手机 QQ,用来扫一次二维码 |
| QQ 机器人 | 不需要事先注册。机器人应用是那次扫码当场创建的,不必提前准备 AppID/AppSecret |
| 腾讯的规则 | 未认证的机器人仅管理员可用——也就是只有你自己能用,这正是「私人遥控器」要的 |

打开侧边栏的 plugin 入口,选 添加插件。输入框接受包名、Git 地址、tarball 或本地路径。

要装的这个名字是 dsh-qq-group-plugin

仓库与包同名,没有需要对上的东西——但 -group-plugin 这一串很容易漏掉。
把 dsh-qq-group-plugin 复制过去,别手打。 安装命令必须与包名逐字一致。

在终端里就是一行(你用的配置档是 web 就把 --profile desktop 换成 --profile web):

dsh plugin --profile desktop add dsh-qq-group-plugin

从 npm 装 —— 不用配置任何东西

dsh-qq-group-plugin

需要指定版本就写 dsh-qq-group-plugin@1.0.5-groups.1。
⚠️ 本包还没发到 npm。 在它上线之前,用下面的 Git 地址或 tarball 安装,别照着这个包名敲。

从 Git 地址安装 —— 目前最省事的一条路

https://github.com/104laiye/dsh-qq-group-plugin

从本地目录安装 —— 没有构建步骤要等

C:\path\to\dsh-qq-group-plugin

指到放着 package.json 的那个目录,它声明的包名是 dsh-qq-group-plugin。

从 tarball 安装

npm pack
→ dsh-qq-group-plugin-1.0.5-groups.1.tgz

把那个 .tgz 的绝对路径粘进 添加插件。

改用命令行安装

界面底下驱动的就是 pnpm,所以同样的事也能在终端里做:

dsh plugin --profile desktop add https://github.com/104laiye/dsh-qq-group-plugin
dsh plugin --profile desktop add C:\path\to\dsh-qq-group-plugin

然后得自己启用这个 bundle——也就是 立即启用 替你做的事——改 ~/.dsh/profiles/desktop/package.json:

{
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-qq-group-plugin"
]
}
}
}

等安装结束,点 立即启用,重启 DSH。

开始使用

重启 DSH 后打开 设置 → QQ,点 开始扫码。用手机 QQ 扫二维码并在手机上确认。

扫码这一步不用先去腾讯开放平台注册。 机器人应用是那次扫码当场创建的, 不需要事先准备 AppID/AppSecret,也不需要公网 IP 或反向代理。

凭据直接写进 DSH 的凭据存储——插件自己的状态文件里只有 AppID,没有 AppSecret。
绑定后通道会自动连接:在 QQ 里给机器人发消息即可开始对话。

上面这张是装上之后真正在用的样子:agent 在电脑上整理好一份 13 首的《秋日诗歌选》,把 docx 和 pdf 两个文件直接发到手机上;同一条对话里问一句「告诉我,我现在电脑时间」,它答 2026-10-13 22:43:28 星期二,还顺手问要不要设个提醒。

这一刻电脑是锁屏的——手机上的时间是 22:43,锁屏界面上的时间也是 22:43:

锁屏不会让 agent 停下来,所以你走开之后它还在干活,而手机上的对话照常推进。
反过来也一样成立:锁屏也正是你离开时该做的事(见安全)。

使用

直接发消息就会到达 agent:

你好

下面按能力分块,每块都配一张真机截图说明它长什么样、在证明什么。

会话管理(手机上)

一个 QQ 对话,背后是任意多个 DSH 会话。/list 打开本工作区的会话,每屏 10 条:

这张图一次证明四件事:一屏 10 条、每行末尾一个 6 位短 id(7cee80、4b55e1…)、 当前会话标着「← 当前」、以及底部那句提示。列表还会告诉你其它会话夹里还有 89 个对话。

/list all 是上面那一层——会话夹(跨项目/工作区),每个夹子带会话数;回编号或名字就进入,进去之后看到的还是会话列表(图里回的是 1,于是进了「QQ 会话」):

进会话夹只改浏览位置,不改绑定——真要切过去,还要在里面再选一个会话。

裸数字就是 /switch <数字>:列表就在眼前时不用打 /switch,直接回 2 就行,而且它会告诉你切到了哪个(连短 id 一起回,你能对上是不是那一行):

★ 引用冻结编号:长按引用那条列表消息再回数字,就按你引用的那一屏解析。
列表在这期间变了也不会切错会话——编号冻结在那条消息里。列表底部自己就这么提示:「引用这条消息再回编号,可以避免编号过期。」

大白话也行。 下面这张是发「查看所有会话」(不是指令):

agent 判的是意图而不是匹配固定规则:它认出了这是「列会话」,于是列出了会话夹,还告诉你下一步可以回编号、也可以回「查看其余」。切换成功或失败它也都会说。

用这些指令控制你在和哪个 DSH 会话说话:

| 指令 | 作用 |
| /new [标题] | 新建对话。后面跟的文字就是标题:/new 修复登录 会开一个叫「修复登录」的对话 |
| /list | 直接进 QQ 工作区那一层(每屏最多 10 条) |
| /list all | 列出本机的会话夹(工作区),每个一行、带会话数;回复编号或名字进入 |
| /switch 3 | 切到那一屏的第 3 个 |
| /switch e716f0 | 按行尾那个短 id 切——跟编号无关,永远不会过期 |
| 回复「查看其余」 | 往下翻十条(两层都能用,一直翻到底)。编号跨屏连续(1–10,然后 11–20) |
| 直接回 3、名字或行尾 id | 列表就在眼前时不用打 /switch |
| 引用列表消息 → /switch 3 | 按那一屏的编号切,编号冻结在那条消息里 |
| /model | 看有哪些模型,以及每个模型的推理等级,标出当前用的那个 |
| /model 2 | 切到列表里的第 2 个,也可以直接发模型名字 |
| /model 等级 high | 换当前模型的推理等级(等级名字就是列表里印的那些) |
| /model 2 等级 high | 换模型的同时指定等级 |
| /current | 显示当前在哪个对话 |
| /cancel | 中断正在跑的任务 |
| /help | 显示这份列表 |

空格是可选的:/switch3、/switch 3、/switch:3 意思相同——这些指令是在手机键盘上敲的,掉空格是常态。只是以指令名开头的词不算指令,所以 /news 不是 /new。

编号会过期:会话在你读列表时还在跑,等你回「3」时第 3 行可能已经换人了。所以每行末尾都带一个 最多 6 个字符的短 id,直接回它或 /switch 都收;或者引用那一屏的列表消息再回编号,编号就按那条消息印的算。

列表分两层,每屏 10 条:/list 直接进本工作区的会话;/list all 列出会话夹(工作区),回编号或名字进入。两层都用「查看其余」往下翻十条,编号跨屏连续(1–10,然后 11–20),翻到底会明说而不是继续邀请你翻。进会话夹只改浏览位置,不改绑定——真要切过去,还要在里面再选一个会话。

模型与推理等级

/model 列出有哪些模型(带「(当前)」「(默认)」标记)以及每个模型的推理等级。
/model <名字|编号> 切模型;/model 等级 high 只改推理等级;/model 2 等级 high 一起改。
切换对下一步生效。

推理等级的取值来自宿主适配器,本机自带的 DeepSeek 适配器发布的是 off / low / high / max (清单里印成 Off / Low / High / Max)。/model 等级 后面写的就是这些名字,大小写不敏感;中文的「高」「低」不在取值里——等级名字就是列表里印的那些。

也可以直接用大白话说,例如「换个对话」「我有哪些对话」「停下」。agent 判的是意图而不是匹配固定规则,而且切换会告诉你成功还是失败。

媒体双向:图片、视频、语音、文件

收:手机发图片 / 视频 / 语音 / 文件给 agent。语音用服务端转写,你无感。
Word、Excel 这类文档附件也能读。

下面是发一张狗的照片过去、只问一句「这是什么」:

图里值得注意的不是它认出了狗,而是那两处只有真看过图才知道的细节:黄身橙嘴的鸭子玩具、画面左边人的腿,以及它主动指出照片被横过来了(拍照时手机拿反了)。

发一份 PDF 过去、同样只问一句「这是什么」:

文档类附件也能读:它说出了这是一份 5 页的招新任务文档、由 MarkText 导出,并按「第一部分 环境配置 / 第二部分 用 AI+工程规范 / 第三部分 传统视觉 OpenCV」把内容概括了一遍。

发:agent 用 send_to_qq 把电脑上的文件发到手机——图片显示成图、视频显示成可播放的片段、其它变文件附件:

这就是本页顶部那张封面图在讲的事,也是一次完整的取件:说清楚要哪个文件,它在电脑上找到、发回来,并且回一句带文件名与大小的确认,你一眼能看出发的是不是你要的那个。
★ 超长回复会自动转成 .md 文件发回手机(默认上限 4000 字,可调;0 = 不限制):

手机上一屏读不完的东西,转成文件比刷长消息好用得多——不截断,也不拆成十几条刷屏。
阈值就是设置页里的「单条回复字数上限」。

语音:手机按住说话,agent 收到的是文字(服务端转写,不需要你多做什么):

图里那条 3 秒的语音气泡下面,直接就是一份完整的天气回答——中间那一步(把语音变成文字)你在手机上完全看不到,也不需要看到。

交互

这三件事没有配图——它们是同一条对话里的一问一答,截出来的图跟上面那些几乎一样,所以用文字说清楚更好。它们在手机上收到的是这样:

- 权限审批:agent 要动你的文件时,QQ 里会出现一条待批准的请求,带上它打算做什么。
你回 「允许」、「拒绝」,或者回数字选项都算回答;答完任务接着跑。
(想让这种提示真的出现,权限预设得是能弹提示的那两个——见设置。)
- 二选一/多选提问:agent 的提问会带编号选项发过来,回个数字就行。
- 引用当上下文:长按引用它的某条回答再说话,例如「这条里的第二点展开说」,它知道「这条」是哪一条,也知道「第二点」指哪个。

主动性:干完了告诉你

★★ notify_qq:这台机器上任意会话都能主动推消息给你——「干完了告诉我」就是靠它。
下面左边是桌面端在干这个活儿的会话,右边是手机 QQ上收到的结果:

注意两边不是同一个会话:干活的是桌面端那个会话,收消息的是你绑定的 QQ 对话。
这正是 allowCrossSessionNotify 默认开着的原因——不放开这一条,干活的会话就报不了自己的结果。

实测可用:实测连发十条消息全部送达,其中后六条走的正是主动推送。
(腾讯对主动推送的规则会变,插件不假设额度;任何原因没送达都会进队列,等你下次说话时先补发。)

定时任务走的是 DSH 宿主自带的 schedule_create / schedule_list / schedule_delete / schedule_update——插件不重复实现 DSH 已有的能力,只做通道。说人话就行:

到点它真的会推一条过来(这是主动推送,不是你在问它):

「每天早上 9 点提醒我今天要做什么」「每小时给我发一次当前时间」「看看我设了哪些定时任务」都归这条。看有哪些定时任务就是 schedule_list,删和改也一样。

可靠性

- 归档或消失的会话会自动换绑,并给你一句提示(不是把消息吞掉):原对话被归档了 → 新建一个接上,你收到通知。
- 状态写入在 Windows 上有重试与退避(应对「文件被占用」那类 EPERM)。
- 空内容/未知帧类型的入站消息留日志(不再零痕迹)。

agent 能用的三个工具

| 工具 | 作用 |
| send_to_qq | 把本机文件发到提问的那个对话。图片变照片、视频变可播放片段、其它变文件附件 |
| notify_qq | 从任意会话推送到你当前所在的 QQ 对话。这是「干完了告诉我」的实现,实测可用(连发十条全部送达,其中后六条是主动推送) |
| qq_session_control | 查看/切换/新建/中断对话,以及查看或切换模型与推理等级 |

名字里的 qq_ / _qq 是有意的:工具名在宿主作用域下全局唯一,而微信版已经占了 session_control。两个插件抢同一个名字,后注册的那一方会静默失败。

这三个是插件给的。定时任务不在其中,因为它不需要插件实现:它走 DSH 宿主自带的 schedule_create / schedule_list / schedule_delete / schedule_update,插件只负责把结果发到 QQ 这条通道上。

设置

设置 → QQ,按页面上的顺序一共六组:

- 帮助 —— 页面上那个「打开使用手册」按钮,打开的是用户手册(docs/HANDBOOK-USER.md,指令与设置项都以它为准)
- 连接 —— 通道开关、扫码绑定、已绑定账号、解绑
- 权限 —— QQ 会话的权限预设(只有 auto 和「跟随 DSH 设置:和桌面端一样」还可能弹审批提示)
- 行为设置 —— 见下表
- 指令 —— 页面上印的斜杠指令速查(/help、/new、/list、/switch、/current、/cancel、/model)
- 诊断 —— 日志尾、工作区路径、会话数、待处理交互

这是设置页的全貌(下面几张是把它分段放大):

这是页面顶部两张卡片,也是你第一次装完会看到的东西——「帮助」与「连接」:

扫码绑定就在这张图的下半部分:点「重新扫码」,用手机 QQ 扫一扫并在手机上确认。
你不需要事先去腾讯开放平台注册,也不需要准备 AppID/AppSecret——机器人应用是那次扫码当场创建的。
「已绑定账号」那一行是绑定之后的样子(AppID ← 一个不可逆的指纹 · 绑定时间),旁边「已连接」是通道此刻的状态。

中间两组是权限与指令速查:

权限预设是三个中文选项,图里选中的是默认的那个:

| 选项 | 含义 |
| 完全访问:不询问,直接执行 | 默认。智能体不再问你——问了的话消息发到 QQ,而任务会一直等你回答 |
| 自动审核:电脑上判断 | 让电脑上那套策略来判,可能弹提示 |
| 跟随 DSH 设置:和桌面端一样 | 和桌面端完全一致,可能弹提示 |

只有后两个还可能把权限提示发到 QQ。想验证「权限审批能不能回流到手机」这件事,就把这里切成能弹提示的那个预设——那时候你手机上会收到一条待批准的请求, 回「允许」/「拒绝」,或者回数字选项都算回答。

<img src="docs/images/settings-b.png" width="620" alt="设置页的「指令」组:「斜杠指令」表格列出 /help、/new [标题]、/list、/switch <编号>、/model [名字]、/current、/cancel 及各自说明,底部写「分隔符可用「:」或直接省略,例如 /switch1。」;下面「说大白话也可以」一段说明直接说「换个对话」「看下有哪些对话」「停一下」都行">

这一组就是 /help 在设置页里的样子,指令与设置项都以用户手册为准。
下面那句「说大白话也可以」也是真的:DSH 会先说明它要做什么,你同意后再执行——想跳过这一步,把上面的「会话操作先确认」关掉。

页面下半部分的行为设置与会话文件夹路径:

会话文件夹这一项带原生文件夹选择器(就是那个「选择…」按钮)。
输入框里是你填的原文,右边「当前生效」是实际在用的路径——两者分开是有意的,填错时你能看到自己填了什么去改,同时知道现在实际在用哪个。

最后是诊断区,出问题时的第一条线索:

<img src="docs/images/settings-c.png" width="620" alt="设置页的「诊断」组:日志文件 C:\Users\XCISXC\.dsh\qq\boot.log、会话工作目录 C:\Users\XCISXC\.dsh\dsh_qq、对话数 1、待回答交互 0、被动回复限流 4 次/1 小时;下面「日志末尾」是一个可滚动的日志框,里面有 sdk info [qqbot:api] <<< Status: 200 OK 与 TraceId 等行,最后一行是 send_to_qq: path=…DSH 自画像.png -> 文本已发送;已发送图片 DSH 自画像.png">

诊断区给的是日志路径 + 末尾日志,所以大多数问题你自己就能看出是发失败了、限流了,还是附件没落盘。图里最后一行正好是一次成功的 send_to_qq。

把这些卡片加起来,一共九个设置项:

| 设置 | 默认 | 说明 |
| permissionPreset | danger-full-access | QQ 会话的权限预设。权限提示发到手机上会让任务一直等你回答,所以默认不设闸——见安全 |
| requireConfirmation | 开 | 智能体执行会话操作前是否先问你一次 |
| allowCrossSessionNotify | 开 | 关掉后 notify_qq 只能推给调用者自己的会话(更严的姿态) |
| mergeWindowMs | 10000 | 纯附件消息先停这么久,等你补一句指令;0 = 不等待 |
| autoReplyAttachments | 开 | 窗口内没等到指令时,是否把附件交给智能体。关掉不是忽略附件,而是等用户说话 |
| maxReplyChars | 4000 | 超过就作为 .md 文件发送;0 = 不限制 |
| settleMs | 1200 | 连续流片段之间静默多久就发出去 |
| presenceNote | 一段中文说明 | 随每条消息交给智能体:你在手机上、看不到这台电脑的屏幕,要看东西就直接发 |
| workspacePath | 空 = $DSH_HOME\dsh_qq_groups | 会话文件夹。必须是绝对路径;填错只会「没生效」,绝不会让插件起不来 |

设置会持久化,重启后仍是你选的那份。老状态文件(没有 settings 块)照常可读。

每一项设置只定义在一处——lib/settings.js 的 SETTINGS_SCHEMA,每项一个校验器加一个 default。加载归一、落盘、设置页快照与往返测试全部由它派生,所以加一项设置就是在那张表里加一行,其余各处不可能各走各的。
(微信插件踩过这条故障:三份手抄名单各改各的,加设置时漏掉一份就会静默丢字段,而且每次写盘都重新加载并重新规范化,于是下一次写盘把丢失持久化了。
上游为这件事写了一条断言,把它当「没有的那个编译器」;这个 fork 没有把那套测试带过来,所以口径是:加设置时自己盯住 SETTINGS_SCHEMA 这一处。)

workspacePath 旁边显示的是实际生效的路径,而输入框里是你填的原文。两者分开是有意的:填错时你能看到自己填了什么去改,同时知道现在实际在用哪个。

⚠️ 改路径不搬动已有的对话。 它们留在原来的文件夹,只有之后新建的用新路径。
这是唯一安全的做法——宿主在采用已存在会话时比对 cwd,不一致会抛 ApiSessionCwdConflict,那个会话就永远接不回来了。

文件夹布局

| 用途 | 路径 |
| 会话工作区(桌面端显示为「QQ 会话」) | $DSH_HOME\dsh_qq_groups(可用 workspacePath 改) |
| 入站媒体 + 长回复 .md | <会话工作区>\媒体 |
| 插件状态与日志 | $DSH_HOME\qq-groups\state.json、$DSH_HOME\qq-groups\boot.log |

出问题了看哪里

| 现象 | 先看哪里 |
| 设置页看不到 QQ 区块 | 客户端插件没加载。看 %APPDATA%\@deepseek-ai\dsh-desktop\logs\crash--web-boot.log 的 renderer console 段 |
| 整个应用起不来 | 同上。那条致命错误本身信息量很少,真正的原因在 renderer console 里 |
| 机器人不回消息 | boot.log 里有没有 入站;GET /.dsh-qq-group-plugin/status 的 errors 数组 |
| 图片/语音没反应 | boot.log 里找 附件下载失败 或 附件已停靠 |
| 「发不出去」 | 看 boot.log 里有没有 待发已入队——主动推送的规则可能变,插件不假设额度;没送达的消息会在你下次说话时补发 |

调试用的 HTTP 端点都在 /.dsh-qq-group-plugin/ 下:status、log、settings、 permission-presets、accounts、login、start、stop 等。

与微信版的差异

功能上对齐,但有几处是有意不同,因为 QQ 协议给了微信那边没有的东西:

| 引用消息 | QQ 的 msg_elements 直接给被引正文,所以微信那套 quoteHistory 缓存不需要 |
| 语音 | QQ 服务端直接给 voice_wav_url + asr_refer_text,不需要 SILK 解码,也没有随之而来的那句免责 |
| 待发队列 | 微信因为 iLink 不允许主动发而必须排队;QQ 主动推送可用,队列的用途是把没送达的消息补发(网络、平台拒绝、规则变化都算),不是某一种失败的兜底 |
| 工具名 | 见上文(宿主作用域全局唯一) |
| 安装 | 没有构建步骤,也没有 allowBuilds 询问:本插件就是普通 JavaScript,Git 安装直接打包就能跑 |

安全

⚠️ 这一节和上游不一样,请读完。 上游讲的是「只有你能碰到它」——因为它只做 1:1 私聊。
群聊版把这句话拆掉了:机器人被拉进群之后,群里任何成员 @ 它,都能在这台电脑上读写文件、执行命令。默认权限预设是 danger-full-access,也就是不弹审批。

只有你能碰到它。 通道只跟腾讯官方的 QQ 机器人服务说话,没有别的东西——没有第三方服务,中间也没有自建中转。机器人是一个独立的应用,管理员是你的 QQ 账号,而且是你自己扫码创建的;未认证的机器人仅管理员可用。私聊这一面,它不是一个能发出去的 QQ 名片:没有地方能搜到它,也没有人能加它。所以私聊没有白名单——平台自己的规则就是白名单。

但群里不一样。 群是别人也能进来的地方,而 @ 一下就是一条能驱动智能体的指令。
当前实现不区分发言人,也不检查群 id,所以只要机器人在群里,那个群的每个成员都有和你在私聊里一样的权限。三个收紧的方向,都在 lib/runtime.js 的 #handleInbound 里、 perMemberSession 那段附近:

- 群 id 白名单——只认你自己那个群
- 发言人 member_openid 白名单——只认你自己的 QQ 号
- 把群会话的权限预设调低——即使被 @ 也不弹审批之外的事(见设置)

AppSecret 是长期密钥,就按长期密钥对待。 它以 grant 记录写进 DSH 的凭据存储,而不是写进插件的明文状态文件(那里只有 AppID)。要轮换就回设置页重新绑定一次。

还有三件事是真的,值得知道:

QQ 来的对话默认全权限运行——智能体动手前不问。这是有意的:权限提示会发到 QQ,然后任务就在那里等你,于是在手机上每条命令都会卡在你早已走开的那个对话里。
想要和坐在电脑前一样的护栏,就把设置页里的「QQ 会话的权限预设」改成 auto (或改成跟随 profile 自己的策略)。

智能体以你的身份运行。 它能执行命令、读写文件,用的是你这个用户的权限——它本来就是干这个的,也就是说这台机器上你能做的事它都能做。所以:走开之前扫一眼你让它干的是什么,离开时锁屏。锁屏不会让智能体停下来,但能挡住路过的人。

默认任意会话都能推送到你的 QQ。 这是「干完了告诉我」能成立的原因:干活的那个会话通常不是你 QQ 对话绑定的那个,不放开这一条它就报不了自己的结果。关掉 allowCrossSessionNotify 就回到更严的规则:只有绑定的那个会话能发。

文档

| docs/HANDBOOK-USER.md | 用户手册——设置页那个帮助按钮打开的就是它,指令与设置项都以它为准(中文) |
| docs/POSTMORTEM.md | 每一个真实踩过的坑——每一条都付了代价,也每一条都是一个检查器存在的理由(中文) |
| docs/SETTINGS-CONTRACT.md | 设置页背后的宿主/客户端路由契约,逐条读自真实调用点(中文) |
| docs/RELEASING.md | 一次版本怎么发:tag、OIDC,以及一次性的 Trusted Publisher 配置(中文) |
| docs/STEP3-能力调研与实现规格.md | QQ 交互消息与流式的能力调研。状态:暂缓,未实现——当前代码里没有任何按钮、也没有流式;调研结论是真的,留着给将来重启这项工作用(中文) |

开发

普通 JavaScript,没有构建步骤,没有转译器。manifest 里不写 engines 范围——本插件只需要跑在已经在场的那个 DSH 宿主里。

验证脚本在仓库根目录,六个都可以离线跑,不依赖网络、不依赖宿主、不需要凭据:

node verify-groups.mjs # 群支持的静态结构、标识符一致性、状态目录隔离
node verify-behavior.mjs # @ 判定行为(含现场故障回归用例)
node verify-ack.mjs # 即时确认的时机与不阻断
node verify-persona.mjs # 人设走系统提示段、不随消息附带
node verify-member-session.mjs # 会话键三段格式、发送目标只取第 2 段
node verify-title.mjs # @ 标记剥离(含现场故障原文)

当前基线 130 项断言:25 + 27 + 12 + 23 + 25 + 18,全绿。改代码后必须全绿。

fork 没有继承的那些部分

上游仓库里有 scripts/(三个大套件)、tools/(四个常设检查器)、smoke/(四个探针)和 .github/workflows/(CI 与发布)。这个 fork 一个都没有带过来,所以:

- 上游 README 里那些「822 / 108 / 60 项检查」「CI 徽章」「npm ci 后跑 tools/」的说法, 在本仓库不成立,已从上面删掉。
- 本仓库的测试就是那六个 verify-.mjs,总共 130 项。
- 没有 CI、没有自动发布。要不要补齐,见相对上游改了什么。

常设检查器去哪了

tools/ 里那四个检查器是上游为它们自己的事故写的(未导入的引用、未使用的导入、文档里的测试数量漂移、跨插件共享资源)。这个 fork 没有搬,所以上面提到的那些闸在这里都不存在。

如果要恢复,得从上游取;但要注意 check-doc-counts.mjs 会去读 README.md、 docs/RELEASING.md 和 publish.yml,而这三样本仓库里都没有或已经改过,直接搬过来会立刻报错。

相对上游改了什么

基于 xcisxc29/dsh-qq-plugin v1.0.5。

| # | 改动 | 主要文件 |
| 1 | 全链路改名:包名、路由前缀、凭据 scope、客户端模块 id、服务名——九处标识符必须完全一致 | 全部 |
| 2 | 群聊支持:认 GROUP_AT_MESSAGE_CREATE 事件,群里 @ 就回 | lib/runtime.js #handleInbound |
| 3 | 每人独立会话:同一个群里不同群友各聊各的,互不串台 | lib/state.js conversationKey、lib/runtime.js |
| 4 | 人设走系统提示段,全局生效 | index.js registerPersonaSection |
| 5 | 标题清理:剥掉 <@openid> 标记,否则会话标题里全是那串 id | lib/router.js deriveSessionTitle |
| 6 | 即时确认(默认关闭) | lib/runtime.js |
| 7 | 维护路由 POST /rename-sessions:批量改会话标题 | lib/routes.js |

因此与上游的隔离

包名、服务名、会话目录、状态目录、凭据 scope 全部加了独立后缀:

| | 上游 | 本 fork |
| 包名 / 模块 id | dsh-qq-plugin | dsh-qq-group-plugin |
| 服务名 | qqChannel | qqGroupChannel |
| 路由前缀 | /.dsh-qq-plugin | /.dsh-qq-group-plugin |
| 会话工作区 | $DSH_HOME\dsh_qq | $DSH_HOME\dsh_qq_groups |
| 状态与日志 | $DSH_HOME\qq\ | $DSH_HOME\qq-groups\ |
| 凭据 scope | dsh-qq-plugin/app-<id> | dsh-qq-group-plugin/app-<id> |

这样两份可以同装在一个 profile 里:会话 cwd 不冲突(宿主在采用已存在会话时比对 cwd,不一致会抛 ApiSessionCwdConflict),state.json 也不会互相覆盖。
代价是两边的会话、绑定、凭据完全不共享——各绑各的。

⚠️ 这里有一处需要注意:node_modules 目录没有被提交进仓库(见 .gitignore),所以从 Git 安装时 pnpm 会自己解析依赖。上游文档里那句「Git 安装直接打包就能跑」在依赖装得上时成立;装不上就退回 tarball。

许可

MIT —— 见 LICENSE。
预览分享卡片长什么样 ↓104laiye/dsh-qq-group-plugin
分享 · DeepSeek Harness Hub
104laiye/dsh-qq-group-plugin

在QQ群里@机器人,用手机远程指挥电脑上的智能体

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部