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

QQ 桥接 flyinstar/dsh-qq-bridge

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

@qqbot/dsh-plugin-qq — QQ ↔ DSH 桥接插件

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

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

该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add flyinstar/dsh-qq-bridge
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · platform
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 11 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包@qqbot/dsh-plugin-qq(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/30 00:33:16

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

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

读写/删除本地文件发起外部网络请求
查看扫描证据(共 70 处,展示前 65 条)
  • 写入本地文件
    index.js:693
    void mkdir(dirname(reminderRoot), { recursive: true })
  • 读取本地文件
    index.js:785
    names = readdirSync(dir);
  • 读取本地文件
    index.js:792
    const parsed = JSON.parse(await readFile(join(dir, name), 'utf8'));
  • 写入本地文件
    index.js:823
    await mkdir(dir, { recursive: true });
  • 读取本地文件
    index.js:2701
    sketch = perceptualHash(await readFile(resolve(cwd, path)));
  • 写入本地文件
    index.js:4559
    void mkdir(stickerRoot, { recursive: true }).catch((error) => {
  • 发起网络请求
    client.js:1864
    const response = await fetch(REMINDER_TASKS_PATH, {
  • 发起网络请求
    client.js:2026
    const response = await fetch(SESSION_ROUTE_PATH, {
  • 发起网络请求
    client.js:2058
    const response = await fetch(SESSION_ROUTE_PATH, {
  • 读取本地文件
    image.js:166
    const info = await stat(target).catch(() => undefined);
  • 读取本地文件
    image.js:170
    bytes = await readFile(target);
  • 读取本地文件
    media.js:289
    const info = await stat(target).catch(() => undefined);
  • 读取本地文件
    media.js:293
    return readFile(target);
  • 读取本地文件
    media.js:330
    entries = await readdir(directory, { withFileTypes: true });
  • 读取本地文件
    media.js:338
    const info = await stat(full).catch(() => undefined);
  • 删除本地文件
    media.js:344
    await unlink(stale.full).catch(() => {});
  • 读取本地文件
    media.js:375
    const existing = await stat(target).catch(() => undefined);
  • 写入本地文件
    media.js:377
    await utimes(target, new Date(), new Date()).catch(() => {});
  • 写入本地文件
    media.js:381
    await writeFile(target, built.png);
  • 写入本地文件
    media.js:403
    await mkdir(directory, { recursive: true });
  • 读取本地文件
    media.js:404
    const existing = await stat(target).catch(() => undefined);
  • 写入本地文件
    media.js:407
    await utimes(target, new Date(), new Date()).catch(() => {});
  • 写入本地文件
    media.js:409
    await writeFile(target, bytes);
  • 读取本地文件
    sticker-frames.js:68
    const entries = await readdir(stickerRoot, { withFileTypes: true }).catch(() => []);
  • 写入本地文件
    sticker-frames.js:86
    await mkdir(sheets, { recursive: true }).catch(() => {});
  • 读取本地文件
    sticker-frames.js:91
    const bytes = await readFile(join(stickerRoot, name));
  • 读取本地文件
    sticker-frames.js:117
    const existing = await readFile(target).catch(() => undefined);
  • 写入本地文件
    sticker-frames.js:121
    await writeFile(target, built.png);
  • 读取本地文件
    sticker-frames.js:127
    const entries = await readdir(sheets, { withFileTypes: true }).catch(() => []);
  • 删除本地文件
    sticker-frames.js:130
    await unlink(join(sheets, entry.name)).catch(() => {});
  • 读取本地文件
    napcat.js:320
    if (!existsSync(dir)) return { found: false, reason: `目录不存在:${dir}` };
  • 写入本地文件
    napcat.js:410
    await copyFile(found.file, backup);
  • 读取本地文件
    napcat.js:460
    if (existsSync(configDir)) {
  • 读取本地文件
    sticker.js:60
    return readdirSync(stickerRoot, { withFileTypes: true })
  • 读取本地文件
    sticker.js:273
    const occupied = existing.includes(fileName) || (await stat(target).catch(() => undefined)) !== undefined;
  • 写入本地文件
    sticker.js:277
    await mkdir(stickerRoot, { recursive: true });
  • 读取本地文件
    sticker.js:354
    const size = (await stat(join(stickerRoot, found)).catch(() => undefined))?.size;
  • 读取本地文件
    sticker.js:360
    if ((await stat(targetPath).catch(() => undefined)) !== undefined) {
  • 读取本地文件
    sticker.js:363
    const size = (await stat(sourcePath)).size;
  • 写入本地文件
    sticker.js:364
    await rename(sourcePath, targetPath);
  • 写入本地文件
    sticker.js:379
    await rename(targetPath, sourcePath).catch(() => {});
  • 写入本地文件
    sticker.js:383
    await rename(targetPath, sourcePath).catch(() => {});
  • 发起网络请求
    key-rotation.js:72
    const response = await fetch(url, {
  • 写入本地文件
    memory.js:314
    await mkdir(paths.logDir, { recursive: true });
  • 写入本地文件
    memory.js:315
    await appendFile(file, `${JSON.stringify(line)}\n`, 'utf8');
  • 写入本地文件
    memory.js:326
    await mkdir(paths.dir, { recursive: true });
  • 写入本地文件
    memory.js:489
    await mkdir(memoryRoot, { recursive: true });
  • 读取本地文件
    memory.js:607
    const info = statSync(absolute);
  • 读取本地文件
    memory.js:611
    const fresh = { key, text: readFileSync(absolute, 'utf8') };
  • 读取本地文件
    memory.js:672
    months = readdirSync(memoryPaths(key).archiveDir)
  • 写入本地文件
    memory.js:729
    await mkdir(memoryRoot, { recursive: true });
  • 读取本地文件
    memory.js:862
    const info = statSync(absolute);
  • 读取本地文件
    memory.js:865
    return { text: readFileSync(absolute, 'utf8'), key: `${info.size}:${info.mtimeMs}` };
  • 写入本地文件
    memory.js:1197
    await mkdir(dirname(absolute), { recursive: true });
  • 删除本地文件
    memory.js:1378
    for (const old of kept.slice(0, Math.max(0, kept.length - HISTORY_KEEP))) await unlink(join(dir, old)).catch(() => {});
  • 写入本地文件
    filestore.js:22
    await writeFile(temp, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
  • 写入本地文件
    filestore.js:23
    await rename(temp, absolute);
  • 写入本地文件
    filestore.js:33
    await writeFile(temp, text, 'utf8');
  • 写入本地文件
    filestore.js:34
    await rename(temp, absolute);
  • 写入本地文件
    filestore.js:47
    await writeFile(temp, bytes);
  • 写入本地文件
    filestore.js:48
    await rename(temp, absolute);
  • 读取本地文件
    filestore.js:70
    return await readFile(absolute, 'utf8');
  • 读取本地文件
    filestore.js:103
    return await readdir(absolute);
  • 读取本地文件
    docfile.js:57
    info = statSync(absolute);
  • 读取本地文件
    docfile.js:67
    text = readFileSync(absolute, 'utf8');
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-llm@deepseek-ai/dsh-tools@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

README

由 DeepSeek 最新模型翻译生成
展开完整文档(README 剩余 1 节)
@qqbot/dsh-plugin-qq — QQ ↔ DSH 桥接插件

个人自用项目,顺手传到 GitHub 方便朋友下载。文档里的配置与取舍都是照着我这一台机器的用法写的,没有做成通用插件,也不保证开箱即用 ——想拿去玩的话,照着文档慢慢改就行。

把 QQ(通过 OneBot v11,如 NapCat / Lagrange / go-cqhttp)接到 DeepSeek Harness:

- 入站:QQ 私聊或群里 @机器人 的消息 → 交给一个专属的 DSH 智能体会话处理 → 结果自动发回 QQ。
- 出站:任何 DSH 智能体(包括 Web UI 里的主会话)都能调用 qq_send_* 主动发消息 / 图片。
- 像群友一样说话:几条消息攒成一轮、回复拆成短气泡、按打字节奏发出、引用 / @ 指向该指的人。
- 它自己的小动作:群里刷同一个字时跟着复读;安静下来后偶尔主动冒个泡;聊起来之后免 @ 接话、回完再补一句;别人撤回消息时会清掉引用(默认假装没看到)。
- 图片与表情包:能 read_image 真的看图(动图会额外拆一张分镜图,不只看到第一帧);能发表情包;能把你发的表情存进自己的收藏目录。
- 定时提醒:让它在明早 8 点提醒谁、每周一 @ 谁开会 —— 到点由插件直接发,重启不丢。
- 长期记忆:每句话落盘,每天由独立摘要会话整理成「这个群记得什么」;聊天时按当前消息检索相关条目(含全局人物表与梗),不再只读文件开头,文件满了会滚进 archive/ 而不是删掉。

它能做什么

| 能力 | 一句话 | 细节 |
| 双向聊天 | 一个 QQ 会话 = 一个持久 Session,重启后 resume,聊天记忆不丢 | 会话与轮次 |
| 人格与表达 | 「是谁」写 PERSONA.md,「怎么说」写 STYLE.md,都热读 | 人格与表达 |
| 群友式说话 | 攒批、气泡条数(模型自己写)、分条与打字延迟、私聊「正在输入」、引用 / @、[[@昵称]] | 说话方式与节奏 |
| 自动复读 | 群里刷同一个字 / 同一张表情时,插件不经过模型跟着发 | 自动复读 |
| 主动开口 | 冷场冒泡、免 @ 接话、回完补一句(私聊永远不主动打扰) | 主动开口 |
| 图片与表情包 | 看图(动图拆分镜图)、发表情、存表情;链接 / 视频 / 语音 / 戳一戳各有下场 | 图片与感知 |
| 被撤回的消息 | 清引用是安全层;要不要调侃是配置 | 被撤回的消息 |
| 定时提醒 | 到点发固定文案 / 让模型换语气 / 到点做事,可 @ 人 | 定时提醒 |
| 长期记忆 | 转录 → 每日摘要 → MEMORY.md / archive/ / PEOPLE.md / COGNITION.md / STICKERS.md → 检索式注入 | 长期记忆 |
| 工具与能力面 | 自带最小 qq 预设 + allowTools 白名单 | 工具与能力面 |
| 运维 | doctor / status / logs / restart,三套部署共用 | 运维 |

30 秒开始

1. 装好 DSH,在 Web UI 的 Models 页填一次模型凭据。
2. 拿代码:到 Releases 下载发布包,或者 git clone 本仓库。
Windows 上解压后双击 scripts\napcat-setup.cmd,它会把 NapCat 与插件一起配好。
3. 让 NapCat 开一个 WebSocket 服务器(不是 websocketClients),端口与 endpoint 一致(默认 3001),扫码登录。
4. 起常驻进程:dsh --profile qqbot --port 3081 --no-open(或 deploy/qqbot.service)。
5. 私聊机器人发一句话,它在 QQ 里回你就说明整条链路通了。

想让它像某个具体的人:照写人设:模板与问答走 —— 复制两份模板改四处,或者让智能体用 18 道选择题问你一遍,再跑一个自检脚本看看「模型会看到什么」。

| 你的平台 | 照着哪一页装 |
| Windows(桌面版 DSH 与 NapCat 在同一台机器上) | Windows 桌面版 |
| Linux / 容器(NapCat 跑在 docker 里) | 安装与运行 |

改了什么、这个版本有什么,见 CHANGELOG.md。

工作原理

QQ 客户端 ──▶ NapCat ──(OneBot v11 WebSocket)──▶ 本插件 │ 每个会话映射一个 DSH Session │ Agent 产出最终回复 ──▶ 发回 QQ

- 一个 QQ 会话(一个私聊对象 / 一个群)= 一个持久化 Session。Session id 由会话 key 经 SHA-256 派生,是确定性的:Harness 重启后同一个人再发消息,插件会 resume 原有会话。
/reset 不改这个算法,只是把「第几轮」也算进摘要(见会话与轮次)。
- 智能体的回复取该 turn 里最后一条有文本的 assistant 消息;中间步骤的工具调用不会发给 QQ。
- 前后脚到的消息先攒一个窗口(batchWindowMs,默认 2 秒)再投给智能体;回复会拆成几条短消息、按打字节奏发出,被叫到时按 replyStyle 引用 / @ 该指的人 —— 它自己凑上来的「搭话」不挂任何指向(见说话方式与节奏)。
- 群消息默认只在被 @ 时触发;私聊 / 群里的「没有正文」消息、复读、主动搭话、表情包那几条旁路各有自己的闸门,默认值都偏保守(见安全提醒)。

配置

全部配置项在 cordis.patch.yml 的 config: 下(schema 在 config.js,字段上的中文 .description() 就是给用户看的说明),也可以在 Web UI 的 设置 → QQ Bridge 里改。完整的字段表与设置页说明见配置项。

⚠️ 不要手写一个只有几个字段的 config: 去覆盖它。 DSH 的 patch 是整块替换、不是深合并:只写一个 resetUsers 也会把 agentPreset / allowTools / proactive 一起顶掉,QQ 会话会挂上带 shell 的默认预设。改配置走仓库 patch 或 Web UI;每台部署不同的值走环境变量。

常改的几项:

| 字段 | 默认 | 说明 |
| endpoint | ws://127.0.0.1:3001 | OneBot v11 正向 WebSocket 地址(QQBOT_ENDPOINT) |
| accessToken | '' | OneBot access_token(QQBOT_ACCESS_TOKEN) |
| cwd | 进程当前目录 | QQ 会话 Agent 的工作目录,也是媒体 / 记忆 / 人设的落点 |
| groupTrigger | mention | 群消息触发:mention / prefix / all |
| allowUsers / allowGroups | [] | 私聊 / 群白名单;空 = 不限制 |
| agentPreset | qq | QQ 会话挂的 Agent 预设(自带的最小预设,没有 shell) |
| allowTools | 18 个工具 | QQ 会话的工具白名单;默认没有 write / edit / bash |
| proactive | true | 允许它在群里主动开口(私聊不会) |
| activeFollow | true | 群里聊起来之后免 @ 接话:@ 一次之后那个人的下一条不用再 @,最多连着回 10 条、间隔超过 3 分钟算断聊(刻意放松「只在被 @ 时说话」) |
| memory | true | 长期记忆:转录 + 每日摘要 + 认知库 + 人物表 + 检索式注入 + 两个记忆工具 |
| recallMode | ignore | 被撤回的消息:清引用永远做,调侃要显式开 tease |
| reminder | true | 定时提醒;默认只能提醒自己,@ 别人 / @全体默认关 |
| apiKeyRotate | true | 每天 04:00 从 data/api-keys.txt 轮换一把探测通过的 key |

安全(先看这三条)

- QQ 消息是不可信输入:默认 approvalPolicy: never、群消息只在被 @ 时触发。activeFollow / proactive / privateAfterthought 默认开,是刻意放松了「只在被叫到时说话」,每一条都有自己的闸门与上限;不放心就关掉。
- qq_save_sticker 是唯一让 QQ 会话按自己给的字节直接写磁盘的工具:只写表情包目录、文件名洗成单层、同名不覆盖、张数受上限约束。qq_rename_sticker 也能动那个目录,但它只能给已收藏的文件换个名字(不引入新字节、失败会回滚)。qq_remind_create 也会落盘,但写的是 reminderFile 里由纯函数校验过字段的任务。除此之外 QQ 会话没有 write / edit / bash。
- 会写全局状态的两处:apiKeyRotate 改 $DSH_HOME/.credentials.yaml;linkPreview 默认关(开了等于替群里任何人访问任意 URL)。定时提醒会把「未来要说的话」写进 data/reminders.json 并在到点发出,所以默认只能提醒自己、@ 别人默认关。细节与取舍见安全提醒。

文档地图

| 文档 | 内容 |
| 安装与运行 | Linux / 容器:下载、NapCat 要求、qqbot profile、systemd、凭据 |
| Windows 桌面版 | 一键脚本、隐藏窗口、提权、装进 desktop profile、自检与排查 |
| 配置项 | 全部字段、Web UI 设置页、改配置的正确姿势 |
| 人格与表达 | PERSONA.md / STYLE.md 的格式、组合规则、三道防线 |
| 写人设:模板与问答 | 两份复制就能用的模板、一份会提问的提示词、一个不用启动机器人的自检脚本 |
| 说话方式与节奏 | 攒批、气泡条数(模型自己写)、分条 / 打字延迟、指向、[[@昵称]]、空消息 |
| 自动复读 | 文字与表情包复读、画面指纹、带宽账 |
| 主动开口 | 偶尔主动说话、活跃对话、私聊补一句 |
| 图片、表情包与感知 | 看图、发表情、存表情、base64、链接 / 视频 / 语音 / 戳一戳 |
| 被撤回的消息 | 三层处理、模式矩阵、配置与实现要点 |
| 定时提醒 | 三种模式、时间规则、权限与额度、重启/断线//reset |
| 长期记忆 | 转录、每日摘要、检索式注入、冷热分层、人物表、认知库、表情包目录、五个 skill |
| 会话与轮次 | 确定性 Session id、/reset、旧会话存档、Web UI 的「重置对话」按钮 |
| 工具与能力面 | 工具表、agentPreset、allowTools |
| 运维 | scripts/ops.mjs、doctor 的 finding、八个排查场景、key 轮换 |
| 本机开发与测试 | 依赖、重启规则、node --test、行为覆盖清单 |
| 安全提醒 | 所有扩大能力面 / 主动发消息的开关与默认值 |
| AGENTS.md | 给要改这个项目的 agent 的代码说明书(不面向用户) |

开发

node --test test/ # 全部用例
node --test test/settings.test.mjs # 只跑配置取值口径

改完源码必须重启 Harness(Loader 按 URL 缓存模块,停用 / 启用插件拿不回新代码)。
本机依赖怎么铺、测试覆盖了什么、Windows / 沙箱里的跑法,见本机开发与测试;代码结构、模块依赖与「改哪里」的索引见 AGENTS.md。

许可

MIT。
预览分享卡片长什么样 ↓flyinstar/dsh-qq-bridge
分享 · DeepSeek Harness Hub
flyinstar/dsh-qq-bridge

@qqbot/dsh-plugin-qq — QQ ↔ DSH 桥接插件

这是你的仓库?认领条目

回到顶部