DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
N

dsh-napcat-bot

Napcat Bot

DSH × NapCat QQ bot plugin: includes NapCat, automatic OneBot integration, persona, sessions, memory, risk control, image recognition (reusing the main model’s V4.1-Flash native vision), and four TTS voice modes (convert all messages to voice / keyword-triggered / random by personality, “send when i

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:9178159/dsh-napcat-bot#26d747f22eb4e16905b806a6bb3f23a791fed09b
READMECompatibilityVersions

Description

DSH × NapCat QQ bot plugin: includes NapCat, automatic OneBot integration, persona, sessions, memory, risk control, image recognition (reusing the main model’s V4.1-Flash native vision), and four TTS voice modes (convert all messages to voice / keyword-triggered / random by personality, “send when it feels like it,” with random soft and cute voice tones plus intelligent weighting based on the persona, configurable per session), forced voice commands (bypassing the LLM for direct reading), opportunistic proactive messaging (random mood evaluation, cooldown only with no message-count limit, pausing on farewells, context-based generation, and random TTS voice integration), segmented streaming replies, and allowlists, blocklists, and rate limiting.

Compatibility and provenance

Napcat Bot is published as dsh-napcat-bot and currently resolves to version 2.8.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
10/25/2026

Versions

2.8.0stable
10/25/2026

Related plugins

Loading related plugins…

Latest
2.8.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/25/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in integrations-communication.

Acp App@deepseek-ai/dsh-acp-appThe dsh ACP profile bundle: automation-only JSON-RPC stdio and process lifecycle over dsh-baseRemote Bridge@linxin666/dsh-remote-bridgeDSH remote bridge: the host half serves protocol v1 over one exact /ios/v1 WebSocket route — session roster, history baseline, prompting, live turn increments with tool activity, interrupt, and in-process agent approval — to a device paired by a one-shot Im@xmanrui/dsh-im把微信、飞书、企微、钉钉、QQ、Telegram、WhatsApp、Slack、Discord、Matrix接入DSH。 Connect Telegram, WhatsApp, Slack, Discord, Matrix, WeChat, Feishu, WeCom, DingTalk, and QQ to DSH.Ds Botds-botDS Bot: a team of long-lived Bots for DeepSeek Harness, with Main Bots, Bot-to-Bot messages and group chats

README

dsh-napcat-bot

DeepSeek Harness (DSH) 插件:内置 NapCat(随 tgz 一起分发),启用即自动启动、监听 6099,并且通过 NapCat 官方 WebUI API 自动开启 OneBot 正向 HTTP + 正向 WS,WS 断线自动重连、进程异常自动拉起,让 AI 通过 QQ 私聊 / 群聊与真人对话。

开箱即用:安装并启用插件 → 重启 DSH → 打开侧边【设置 → 集成 → NapCat QQ 机器人】→ 在「NapCat WebUI」标签页扫码登录 QQ → 完事。 接口地址、端口、OneBot access_token、WebUI 管理 Token 全部由插件自动生成与写入,不用手填、不用手抄、不用调试连接。 OneBot WS 固定 ws://127.0.0.1:3001;如果历史配置被写成了 6099,插件会自动纠正并落盘。

零外部 npm 依赖、可离线运行;不带 pnpm-lock.yaml,不会触发 pnpm 供应链校验。

安装

  • 推荐:从 Releases 下载 dsh-napcat-bot-x.y.z.tgz,在 DSH 插件市场「导入本地包」里选择它。
  • 源码:本仓库不含 vendor/(内置 NapCat 本体约 111MB 的第三方二进制,用 Release 分发更合适)。 clone 后可直接读改 lib/;要打包成可安装 tgz,请把 NapCat 解压到 vendor/napcat/ 再 tar -czf。

装好必须完全退出 DSH 再启动:服务端 lib/index.js 只在启动时加载一次。

2.8.0:联网搜索(手动 + 不懂自动查)

搜索后端直接用 DSH 自带的 ctx.web.search()(dsh-base 已挂 @deepseek-ai/dsh-web + dsh-web-search-deepseek,走 DeepSeek 原生搜索),所以不需要另填搜索接口和 Key;面板也支持填 SearXNG 等自定义接口。

两类触发

类型条件例子
手动(原有)命中关键词:帮我搜 / 搜一下 / 查一下 / 上网查 / 搜索搜一下今天金价
自动(新增)本地规则先判:时效信息(新闻/价格/时刻/表/发售/比分)、现实实体(地点/参数/规格/教程/怎么设置)、带疑问但拿不准;拿不准时再让模型回一个词确认今天金价多少?(没说搜,也去查)

不搜的情况:纯闲聊、情绪陪伴(想你了/抱抱/晚安)、玩梗(哈哈哈/笑死/这梗)、主观感受、人设对话(你叫什么)、 以及去掉标点后不足 4 个字的语气词。

优先级

强制语音 > 手动搜索 > 自动搜索 > 识图解读 > 普通闲聊 所以「发个语音说你好」永远直接朗读、不会去搜;发图 + 「搜一下这是啥」会先让主模型用一句短话点出图里是什么,再拿这句话去搜。

兜底与容错

  • 搜索失败 / 无结果 → 回 呜,鱼鱼的小鳍划不动搜索引擎,暂时查不到这个哦(手动、自动同一套)。
  • 没有可用搜索后端时(宿主没挂 web 且没填自定义接口)→ 直接跳过搜索、照常回答,不会突然回「查不到」。
  • 所有搜索都 try/catch,超时 20 秒、同类查询 10 分钟内走缓存,插件不崩不刷屏。

配置 / 规则 / 日志

  • 面板「联网搜索」:总开关、不懂自动搜索(默认开)、自动搜索前模型二次确认、自定义接口地址、Key、每次取几条。
  • 管理 → 规则:可对单个私聊/群单独「不联网」或「只手动搜」。
  • 日志:[SEARCH] manual:<关键词> / auto:<原因> / ok provider=… n=… ms / fail … / skip <原因> / image-hint <提词>。

2.7.0:识图默认「读梗接话」,下指令才描述画面

以前默认提示词是「简短描述这张图片内容」——本质是在让模型看图汇报,发张表情包回来一段画面说明,很出戏。 2.7.0 把两种模式分开,优先级由你这句话决定:

你说的话模式模型被要求做什么
只发图 / 「哈哈哈哈」/「你看这个」接梗模式(默认)禁止描述物体、角色、文字、构图;只判断你发图的意图,读懂梗和情绪,直接接梗互动(例:呜!你好坏,居然喊一车肥鱼来欺负我🥺)
「描述一下这张图」「说说图片里面有什么」「图里长啥样」「详细讲讲画面」描述模式客观描述画面:元素、角色、文字(有就念出来)、构图
  • 命中词表在 lib/vision.js 的 DESCRIBE_KEYWORDS,只收「明确针对图片内容」的说法,所以「你长啥样呀」不会误触发。
  • 描述模式的提示词是硬编码的 DESCRIBE_PROMPT,不受面板提示词影响;面板里的「识图提示词(默认模式)」只管接梗模式。
  • 兜底与容错:默认模式若模型仍在「图片里有…」式汇报,会自动带更硬指令重试一次;重试仍汇报就照发(不冷场、不死循环)。
  • 历史默认提示词(「简短描述这张图片内容」等)在 __schemaVersion=10 迁移时自动换成新默认,用户自己改过的提示词保留。

其余链路一律没动:图片仍走 ctx.attachments 附件引用 + V4.1-Flash 原生视觉(同一条 user 消息里 text + image),识图开关、规则面板按会话覆盖、TTS 四种模式与强制语音、随缘主动发言、记忆、NapCat、风控全部原样。

新增日志:[VISION] mode: meme(默认接梗,不报画面) / describe:<命中词> / report-retry。

2.6.0:主动发言改成「随缘」(去掉倒计时与次数上限,只留冷却)

2.5.0 是「安静满 N 秒 → 说一条 → 你必须回话才会有下一条」,本质还是个定时器,而且被「一轮一条」卡住。 2.6.0 换成随机心情判定:

维度现在的行为
触发方式安静下来后,每隔 20~45 秒(带抖动)做一次心情判定,没有固定倒计时
次数完全取消上限(没有每日/每轮封顶),冷却过完、心情到了就来找你
概率每次判定先抽「心情档位」(12% 忽然很想你 p=0.45 / 43% 一般 p=0.18 / 45% 懒得开口 p=0.07),再掷一次是否命中 —— 所以节奏天然不均匀,可能一晚上两三次,也可能一整天不吭声
冷却发出一条后强制冷却(默认 180 秒,面板滑块 60~1800),冷却期内绝不再发
对话中正在生成回复、或刚说过话(冷却内)→ 一律不插话
告别收到「晚安 / 先睡了 / 先不聊了 / 晚点再说 / 拜拜…」→ 暂停随机触发,直到你重新发消息才恢复
群聊默认关闭,只在私聊;规则面板可给某个群单独打开
内容主模型 + 面板人设 + 最近 12 条记忆生成,短句优先;方向含「想念 / 关心 / 接旧话题 / 小鱼碎碎念」,不是固定句子
语音主动那句照样走「想发就发」随机判定
失败模型空回复 / 报错 → 一个字都不发

面板

AI 配置 → 主动发言:主动找我(随缘)开关(默认开)、冷却间隔滑块(60~1800 秒,默认 180)、群聊也允许。 状态行:主动发言:开启(随缘)· 冷却 180 秒 · 待机 1 个会话 · 已主动 3 · 没心情 12 · 收尾暂停 1。

日志

日志内容
主动发言 待机冷却多少秒后开始随缘判定
主动发言 触发触发时间、空闲多久、p=命中概率 roll=骰子、进入多少秒冷却
主动发言 跳过 / 顺延 / 停表没心情、正在回复、收尾语句
[PROACTIVE]主动发出的那句话原文

2.5.0:空闲主动发言(会接话,不会刷屏)

旧版是「每 N 分钟给最近活跃私聊群发一句问候」——那套已经删掉,生硬、会打断人、还容易刷屏。 新版走空闲触发 + 上下文生成:

维度行为
触发最后一条消息之后静默满 N 秒才考虑开口(默认 120 秒,面板滑块 30~600)
说什么把「刚刚聊了什么 + 对方最后一句」交给主模型,按面板人设写成一句短话;不是固定句子
频率同一段空闲最多一条;你回话后重新计时,进入新一轮
边界正在生成回复时到点 → 顺延,绝不插话;你说「晚安 / 先不聊了 / 拜拜」→ 直接停表
群聊默认关闭,只在私聊生效;规则面板可对某个群单独打开
语音主动那句照样进「想发就发」随机判定,有心情就出声
失败模型没给出内容 / 报错 → 一个字都不发(宁可不吭声,也不发套话)

面板

AI 配置 → 主动发言:开关(默认开)、空闲等待时长(滑块 30~600 秒,默认 120)、群聊也允许。 状态行会显示:主动发言:开启 · 空闲 120 秒触发 · 计时中 1 个会话(最近 98 秒后)· 已主动 3。

管理 → 规则 新增「主动发言(本会话覆盖)」:跟随全局 / 允许 / 本会话不主动 —— 可以给某个群开、给某个私聊关。

日志

前缀内容
[napcat] 主动发言 计时中什么时候排的计时、多久后检查、最后一句是什么
[napcat] 主动发言 已发送空闲了多久才开口、之后重置计时
[napcat] 主动发言 跳过 / 顺延 / 停表为什么没说话(未开启、已说过一条、正在回复、收尾语句)
[PROACTIVE]主动发出的那句话原文(在「消息收发记录」里能看到)

2.4.0:识图改用主模型原生视觉(不再配两套模型)

为什么能这么干:DSH 的模型目录里 deepseek-flash(= DeepSeek-V4.1-Flash)本身就声明了 inputModalities: ["text","image"],视觉是主模型自带能力,没必要再挂一个独立的识图接口。

做法

旧(≤2.3.1)新(2.4.0)
面板填「识图接口地址 + 识图 API Key + 识图模型名」三个输入框全部删除,复用 DSH 里已填好的主模型与密钥
先调识图接口拿一句描述,再把描述拼进 prompt图片和文本同一次请求进主模型:[{type:'text'}, {type:'image', attachment}]
两套模型、两套密钥、两份计费一套配置,文字和看图同一个模型

技术要点:QQ 图片先下载成字节 → ctx.attachments.saveImage() 存进 DSH 附件库拿 ImageAttachmentRef → 以 {type:'image', attachment} 进 user 消息;宿主的 deepseek 适配器 会自己 readImageRequest() 转成 base64 图片块发出去。直接塞 url 是不行的(适配器会判为 不支持的块,整条请求失败),所以必须走附件引用。

保留的东西

  • 识图总开关(默认开)、识图提示词(默认「简短描述这张图片内容」,可改、持久化)。
  • 规则面板仍可按群/私聊单独关识图、单独调语音概率。
  • 识图回复照常进 TTS 判定(全部 / 关键词 / 性格随机 / 强制语音)。
  • 强制语音仍是绕过 LLM 的预处理拦截:发个语音说你好 直接抠出「你好」合成发送。
  • 识图关闭 / 图片取不到 / 类型不支持 / 附件服务不可用 / 主模型报错 → 一律走人设兜底台词。

日志

前缀内容
[FORCE]命中哪个强制语音词、抠出的朗读文本(或「交给模型起稿」)
[VISION]原生多模态 · 图 N 张 或 fallback(原因);原因含 download / unsupported-type / no-url / no-attachment-service
[MODEL]multimodal · 带图 N 张请求主模型 · 返回 M 字
[TTS]synth-ok(引擎 + 音色 + 耗时)/ fail / skip

同类报错 30 秒只写一条,插件不崩、不刷屏。

验收

  1. 发「发个语音说你好」→ 直接发 QQ 语音,不经过模型,不会出现「鱼鱼不会按按钮」。
  2. 发「一车肥鱼」表情包 → 图片随对话进 V4.1-Flash,小鱼语气回复(日志有 [VISION] 原生多模态 · 图 1 张 + [MODEL] multimodal)。
  3. 不用填任何识图地址 / 识图 Key —— 用的就是 DSH 当前选择的主模型。

2.3.1:专项修复(强制语音只回文字 / 发图不识图)

真因(看日志就能确认)

  1. 强制语音只回文字:两个原因叠加 ——
    • ttsUrl 是空的,plan() 判定「无引擎」→ 只发文字;
    • 指令走的是「先让模型说话,再决定发不发语音」,模型先回了「鱼鱼这小短鳍按不来按钮啦」,推脱话术检查里没覆盖「按不来」,于是这条推脱被当正文发出去了。
  2. 发图不识图:visionEndpoint 是空的 → 直接 no-endpoint 兜底。

修法

① 强制语音改成「消息底层预处理拦截」,绕过 LLM 消息进来先解析指令,命中 发语音 / 发句语音 / 语音说xxx / 说出来 … 就把要念的正文抠出来,直接合成语音发送,完全不调模型(从根上不可能再推脱)。

  • 「发个语音说你好」→ 朗读文本 = 你好 → 直接发语音;
  • 「语音说你今天怎么样」→ 朗读文本 = 你今天怎么样;
  • 只说「发语音」没给内容 → 才让模型起稿,但仍强制语音,并注入「禁止说不会发语音/按不了按钮」+ 回复里出现推脱就重试/清洗;
  • 带图 + 强制语音 → 不走抠文本,走识图 + 人设起稿 + 强制语音(否则会把「这是啥」念出来)。
  • 优先级最高:ttsMode=off、随机 0% 也照发。

② 内置离线语音引擎(真开箱即用) 没填 TTS 接口地址时,自动用 Windows 自带语音(SAPI)合成 WAV → 交 NapCat 发语音。零依赖、无需联网、无需 Key;本机实测 3.16 秒语音合成耗时 ~2.4 秒。填了接口则以接口为准。可在面板关闭(「接口没填时用系统内置语音」)或指定音色(Huihui / Xiaoxiao …)。

③ 识图接口自动预置 默认 visionEndpoint = zhipu(智谱,glm-4v-flash 有免费额度),模型名自动补,提示词默认「简短描述图片内容,不要冗长」,开关默认开 —— 只需要补一个 API Key 就能识图(面板会显示「缺 API Key → 补上即可识图」)。地址/提示词都能在界面改,保存即持久化。

④ 日志(面板「消息收发记录」直接看)

前缀内容
[FORCE]是否命中强制语音、命中词、抠出的朗读文本
[VISION]是否触发识图、ok/fallback、原因(no-endpoint / auth / http-500 / no-url …)、识别到的内容
[TTS]synth-ok(引擎 http/local + 音色 + 耗时)/ fail / skip(含 no-engine 原因)

同类报错 30 秒内只写一条,不刷屏;所有异常都降级为文字,插件不崩。

升级到 2.3.1 后必须完全退出 DSH 再启动。

2.3.0:强制语音指令 + 识图默认开箱即用

一、TTS 强制语音(内置关键词库,不用配)

只要这句话里命中下列任一说法,优先级最高:跳过模式(哪怕模式是「关闭」)、跳过随机概率,直接合成语音发出去。

发语音 发句语音 发条语音 发个语音 发一段语音 来句语音 来条语音 来段语音 语音说 用语音 语音回复 语音回答 语音念 语音读 说出来 念出来 读出来 念一下 读一下 说给我听 念给我听 唱一个

例:发「发个语音说你好」→ 直接发语音。

防推脱三层保险:

  1. 生成前给模型注入定向提示:你能直接发语音,禁止回答「不会发语音 / 按不了按钮 / 没法发」;
  2. 回复里仍出现推脱话术 → 带更硬指令自动重试一次;
  3. 还在推脱 → 清洗掉推脱句,语音照发(messages.log 记一行 TTS retry)。

二、识图默认配置

  • 识图开关默认开启;识图提示词默认「简短描述图片内容,不要冗长」(老配置里的旧默认值会自动迁移)。
  • 接口地址支持预设短名,只填一个词就行,模型名会自动补:
填这个实际地址自动模型
zhipuopen.bigmodel.cn/api/paas/v4/chat/completionsglm-4v-flash(有免费额度)
dashscopedashscope.aliyuncs.com/compatible-mode/v1/chat/completionsqwen-vl-max
openaiapi.openai.com/v1/chat/completionsgpt-4o-mini
siliconflowapi.siliconflow.cn/v1/chat/completionsQwen/Qwen2.5-VL-72B-Instruct
moonshotapi.moonshot.cn/v1/chat/completionsmoonshot-v1-8k-vision-preview
openrouteropenrouter.ai/api/v1/chat/completionsgoogle/gemini-2.0-flash-exp:free
ollama127.0.0.1:11434/v1/chat/completionsllava

也可以填任意完整地址(.../chat/completions)或只填 base 地址(https://api.openai.com/v1,会自动补 /chat/completions),自定义完整地址不会被乱拼。

API Key 只能你自己填(这个没法内置)。

三、联动

  • 识图产出的回复若没有命中强制语音,正常走「心情随机语音」掷骰子。
  • 强制语音与随机模式互不干扰:随机 0% 时普通消息不发语音,但「发语音」指令照样发。
  • 规则面板可对单个群/私聊单独关闭识图、单独设语音概率(规则 > 全局)。
  • 面板「人设已生效」下方能看到:语音 已发/跳过/强制/失败、识图 成功/失败 + 上一张图内容。

四、容错

TTS / 识图 超时、401、5xx、返回空 → 一律降级为文字(或人设兜底台词),只写日志,插件不崩;同类报错 30 秒内只记一条,不刷屏。所有配置保存后立即生效,重启自动加载。

升级到 2.3.0 后必须完全退出 DSH 再启动。

2.2.0:识图(看图 → 用人设说话)

面板 AI 配置 → 识图(多模态):

配置项说明
识图功能总开关默认开启。关闭后收到图片只回一句人设兜底台词
多模态模型接口地址OpenAI 兼容的 /chat/completions,如 https://api.openai.com/v1/chat/completions
识图 API Key以 Bearer 发送;留空则不带鉴权头
多模态模型名如 gpt-4o-mini / qwen-vl-max / glm-4v-flash(必须支持图片输入)
识图提示词默认「描述这张图片,简短一点」

链路:QQ 图片 → 从 NapCat 消息里拿直链(只有文件名时用 OneBot get_image 换)→ 多模态接口得到一句描述 → 描述作为上下文交给主模型 → 按面板人设的语气重新组织语言(不是冷冰冰的客观描述)。

例:识图得到「一整车肥鱼表情包」→ 大肥鱼会说「哇!一整车都是肥鱼小伙伴,浩浩荡荡的,也太热闹啦🥳」。

  • 兜底:识图关闭 / 没填接口 / 超时 / 密钥错 / 请求报错 / 返回空 → 直接回人设台词: 「呜…有点糊糊的,鱼鱼眼睛小,得凑很近才看得清一点点。要不你讲讲图里是啥?我慢慢听~」 (这条台词整句一次发出,不拆段、不刷屏;同类报错 30 秒内只写一条日志。)
  • 和随机语音联动:识图回复与兜底台词都走同一条投递管道,所以照样按 TTS 模式掷骰子,可能变成语音。
  • 按会话覆盖:管理 → 规则可对某个私聊/群聊单独「关闭识图」。
  • 纯图片消息也能收到:以前没有文字的消息会被当作空消息丢掉,现在只要带图片就放行。
  • 同一张图 10 分钟内复用识别结果(有缓存,不重复烧 token)。
  • 面板「人设已生效」下方会显示识图状态、成功/失败次数和上一张图识别到的内容。

升级到 2.2.0 后必须完全退出 DSH 再启动。

2.1.0:TTS 语音「性格随机模式(想发就发)」

面板 AI 配置 → 语音(TTS) 区域,模式四选一:

模式行为
关闭只发文字
全部消息转语音每条回复都发语音(回复超过「单条语音最长字数」时自动补发文字,信息不丢)
关键词触发用户或回复里出现触发词(默认「语音 / 发语音 / 说给我听 / 念一下」)才发语音
性格随机模式(想发就发)每轮先掷骰子,命中发语音,没命中只发文字

随机模式细节

⚠️ 语音要真的出声,必须填「TTS 接口地址」。接口只需要 POST {text, voice} 返回音频二进制或 {"audio_base64":"..."};OpenAI 兼容的 /v1/audio/speech 也能直接用(此时再填「TTS 模型名」)。没填接口时面板会显示「未填接口地址」,行为等同只发文字。

  • 概率滑动条 0~100%,默认 40%;0 = 永不发,100 = 次次发。是每轮独立掷骰,不是固定间隔,所以出现「有时出声、有时懒得开口」的随性节奏。
  • 人设智能权重(默认开):短句(≤12 字)权重 ×1.3、活泼语气再往上抬;长段解释(>120 字)×0.72、emotion 低落词(难过/累/emo/哭…)再压;人设里带「懒 / 瘫 / 佛系 / 慢悠悠」整体 ×0.9。边界仍然严格:0 还是 0,100 还是 100。
  • 随机音色(默认开):每次从音色池(默认 软萌少女,甜妹,奶音,软糯小助手,可改)里随机挑,每轮都可能不一样;关掉则固定用「固定音色」。
  • 兜底:TTS 接口超时/报错/返回空/发送失败 → 自动降级只发文字,写 messages.log,插件不崩;如果是「只发语音」模式且发送失败,会补发文字保证用户收到内容。
  • 缓存:同文本+同音色命中内存缓存(TTL 10 分钟、上限 60 条,自动淘汰)。音频全程 base64 直发 NapCat,不落盘,所以没有残留文件需要清理。
  • 按会话覆盖:管理 → 规则里可以对某个群/某个私聊单独设 语音模式 / 概率 / 随机音色(留空 = 跟随全局)。
  • 面板「人设已生效」下方会显示:语音模式、概率、已发 / 跳过 / 失败次数、上一句用的音色 —— 用来确认「确实是想发就发」。

升级到 2.1.0 后必须完全退出 DSH 再启动。旧配置里 ttsEnabled=true 会自动迁移成 ttsMode='all',行为不变。

2.0.1(紧急修复):人格不生效 / 固定输出套话

现象:面板里填了「大肥鱼」,问“你叫什么名字”却固定回一句 我觉得这个得看具体情况~你先说说细节,我再给你个靠谱的答复。

两个真实原因(都已修):

  1. 代码里有一段硬编码兜底话术(离线降级时输出)。模型调用一失败就会吐出这句, 看起来就像“人格完全没生效”。现在这句连同整套硬编码兜底已彻底删除: 模型不可用时就用人设推导一句身份回答(如「我是大肥鱼呀~…」),推导不出来就不发消息, 绝不敷衍一句模板话。
  2. system 提示词用错了传参方式。以前把人格塞在 llm.stream({ system }) 这个字段里, 而 DSH 的模型协议要求 system 作为 role:'system' 的消息进入 messages;字段被忽略, 等于人格根本没送到模型。现在 system 以标准消息发送,面板文本一字不改地成为唯一 system。
  3. 顺带修掉「模型返回空内容」→ 之前 maxTokens=800 时,模型的思维链会把预算吃光, 可见文本为空,于是又触发第 1 条的兜底话术。现在 maxTokens=2000,并且空内容会自动 以 reasoningEffort:'off' 重试一次。

现在的规则:

  • 面板填了人格 → 它就是唯一的 system(不加前缀、不追加任何“最高优先级”之类的说明文字,也不放风格模板);
  • 面板留空 → 完全不发 system,不自动补任何文字;
  • 问身份(你叫什么 / 你是谁 / 你会做什么)→ 额外给一条定向指令:直接按人设第一人称回答, 禁止“看具体情况、你先说说细节”式回避;万一模型还是回避,会自动带硬指令重试一次;
  • 上下文(历史 / 摘要 / 知识库)和排版要求全部挪到 user 消息里,不再污染 system。

排障:面板「人设已生效」下方会显示回复引擎、上次生成成功/失败以及具体报错; 明细写入 ~/.dsh/napcat-bot/engine.log,也可通过 GET /napcat-bot/api/napcat/log?source=engine 查看。

升级到 2.0.1 后必须完全退出 DSH 再启动(服务端代码只在启动时加载)。

三步验收

  1. 导入 dsh-napcat-bot-2.8.0.tgz → 完全退出并重启 DSH(服务端代码只在启动时加载)→ 启用插件 → 日志出现「内置 NapCat 已就绪,WebUI 监听 127.0.0.1:6099」。
  2. 设置页左侧【集成】里点「NapCat QQ 机器人」→ 第二个标签页「NapCat WebUI」已自动带上管理 Token,直接扫码登录。
  3. 三个状态灯全绿(NapCat 进程 ✓ / WS 已连接 ✓ / 可以收发消息 ✓)后,私聊发消息、群里 @ 机器人即可收到 AI 回复。

端口分工(1.5.0 起强制纠正,不再可能连错)

用途地址说明
NapCat WebUI(管理面)http://127.0.0.1:6099/webui只用来扫码登录 QQ、看 NapCat 自己的面板。它不是 OneBot 端口
OneBot 正向 WS(收消息)ws://127.0.0.1:3001插件主通道。连上后 NapCat 的「WS 客户端数」显示 1
OneBot HTTP(发消息)http://127.0.0.1:3000能开就用;没开也不影响,插件会自动改走 WS 通道发送

历史配置里如果 napcatWsUrl 被写成了 6099(把管理面当成了 OneBot 端口),插件启动时会 自动改回 3001 并落盘,日志里会有一行 已修正 OneBot 端点:WS ws://127.0.0.1:6099 → ws://127.0.0.1:3001。 面板顶部也会把这三个地址并排列出来,排障时一眼能确认连的是哪个口。

⚠️ 关键:QQ 登录 ≠ WS 自动连上

这是本插件踩过的最深的坑,1.4.0 修了配置生效问题,1.5.0 又补了两个:

坑 0:WS 连到 6099 上(1.5.0 修复)

6099 是 NapCat 的管理面(HTTP 页面 + WebUI API),不在上面跑 OneBot 协议。 连它只会被拒或无响应,表现就是「插件 WS 状态未知/断开、NapCat 里 WS 客户端数一直是 0」。 现在 normalizeWsUrl() 会把「空值 / 等于 6099 / 等于 HTTP 端口」的地址一律纠正成 ws://127.0.0.1:3001, 配置层、WS 客户端层、面板展示层三处都过一遍,不可能再漏。

坑 1:改配置文件不生效(1.4.0 修复)

直接改 config/onebot11_<QQ>.json 并不能保证生效。 实测 NapCat 4.18.41 经常不热加载该文件, 甚至在自身保存配置时把 websocketServers 条目丢掉——结果就是「QQ 明明登录了,3001 却没在监听」。

所以插件改用 NapCat 自己的 WebUI HTTP API 来配置 OneBot 网络:

POST /api/auth/login              { hash = sha256(webuiToken + ".napcat") }  → data.Credential
POST /api/OB11Config/SetConfig    { config: "<json 文本>" }   // NapCat 内部 save + reloadNetwork

SetConfig 会让 NapCat 真正重启网络适配器,3001 立刻开始监听,不需要重启 NapCat、不需要重新扫码。 插件在「WebUI 就绪」「QQ 登录成功」「发现 3001 未监听」三个时机自动调用它,失败则每 6 秒重试。

坑 2:OneBot HTTP 必须打到具名路径(1.4.0 修复)

NapCat 的 HTTP 适配器不按 body 里的 action 字段分发。往根路径 POST http://127.0.0.1:3000 只会得到一个桩响应:

{"status":"ok","retcode":0,"data":{},"message":"NapCat4 Is Running"}

于是 get_login_info 永远拿不到 QQ 号(面板显示「未登录」),send_private_msg / send_group_msg 变成空操作(消息永远发不出去却也不报错)。

正确写法是 POST 到 /<action>。1.5.0 更进一步:HTTP 不通时 action 会自动走正向 WS(同一连接支持 echo 应答), 所以「NapCat 只开了 WS、没开 HTTP」也能正常收发。

两处 Token(插件已全自动,这里只是说明区别)

Token用途谁生成
WebUI 管理 Token登录 http://127.0.0.1:6099/webui 这个管理页面插件启动前写入 config/webui.json,随后从 NapCat 启动日志([WebUi] WebUi Token: xxx)自动读取校验;内嵌页面自动附加,无需手输
OneBot access_token插件 ↔ NapCat 通信用(HTTP Bearer / WS query),真正收发 QQ 消息插件首次启用时随机生成,自动写进插件配置与 NapCat 的 onebot11_<QQ>.json

两者完全独立:WebUI Token 只影响能否打开管理页面;OneBot token 只影响插件能否调 NapCat 的 API。

自动写入的 NapCat 配置

插件启动内置 NapCat 前会主动写配置文件(作为兜底),并在运行期用官方 API 校正:

  • config/webui.json:host=127.0.0.1、port=6099、带 token、不禁用 WebUI。
  • config/onebot11_<QQ>.json(对历史登录过的 QQ 号全部预置):
    • 正向 HTTP(默认 3000)—— 插件用它发消息、查登录态;
    • 正向 WS(默认 3001)—— 插件用它收消息;
    • 两者使用同一个自动生成的 token(与插件配置一致,不一致会直接 403 → 全链路静默);
    • reportSelfMessage=false,避免机器人收到自己发的消息形成自问自答。

状态灯与自动重连(1.5.0)

面板顶部固定三个灯,语义与 NapCat 侧对得上:

灯含义
🟢 NapCat 进程已启动内置 NapCat 在跑(按 6099 端口实际监听判定,不是看状态文件)
🟡 WS 正在尝试连接插件正在重连 ws://127.0.0.1:3001;旁边显示第几次重试、下次重试倒计时
🔴 WS 连接失败重连次数用尽(wsMaxRetries>0 时)或环境不支持 WebSocket
🟢✓ 可以收发消息WS 已连接 且 3001 在监听 且 QQ 已登录

灯下面一行会直接显示 WS 目标:ws://127.0.0.1:3001(端口 3001),并标注 客户端数 1, 可以和 NapCat WebUI 里的「WS 客户端数」对照。

重连策略(面板可调):

  • 首次重连间隔 wsRetryInterval(默认 2000ms),之后指数退避 2→4→8→15s(上限 wsRetryMaxInterval)。
  • wsMaxRetries 默认 0 = 一直重试;填 N 则连续失败 N 次后停止(按钮可手动重连)。
  • 连接超时 8s 未建立即判失败换下一次(不依赖 onclose——实测 Node 的 WebSocket 在连接被拒时可能只触发 error)。
  • 心跳看门狗:连上后 wsHeartbeatTimeout(默认 100s)内收不到任何数据(含心跳)→ 判定半死连接,主动重连。
  • NapCat 重启 / QQ 掉线重连后,插件检测到 3001 恢复监听会立即重连,不用手动操作。
  • 进程守护:NapCat 进程异常退出(6099 不再监听)→ 状态如实回落成「未运行」,并在 12s 后自动重新拉起; 10 分钟内最多自动拉起 3 次,超过则停在「反复退出」提示,避免把 QQ 拉成重启风暴。

消息应答逻辑(默认即正确)

  • 私聊自动回复;群聊默认仅在被 @ 时回复(面板可关)。
  • 只处理真人聊天消息:post_type=message 且 message_type=private|group; 自动丢弃点赞 / 群成员变动等 notice、心跳 meta_event、加好友请求、机器人自己发的消息(含 sub_type=self)、以及纯图片语音等无文字消息。
  • 回复时把人设 Prompt + 最近 10 条对话记忆一起喂给模型,输出限制为口语化短句(不用 Markdown、不自称 AI)。
  • 回复引擎默认 dsh:走 ctx.get('llm') + ctx.get('agentDefaultModel').currentSelection(),用你在 DSH 里选中的模型与凭据,不需要另填 API Key。
  • 发送失败会被捕获并显示在面板(发送失败:...),同时计入「失败」计数。
  • 面板顶部有连接指示灯:未连接 / 连接中 / 已就绪,并显示 QQ 号、收发计数、最近收到时间、错误信息。

面板结构(固定两个标签页)

  1. AI 配置:AI 配置 内含内置 NapCat 状态卡与启停、连接(全部自动维护,一般不用改)、人格与回复、行为与风控(记忆开关、群内仅 @ 回复、主动发言、冷却与每分钟上限)。
  2. NapCat WebUI:内嵌 WebUI(自动免 Token 登录,这里扫码登录 QQ)、两类 Token 卡片、NapCat 控制台日志预览(实时刷新 / 暂停 / 只看 Token 行 / 复制日志)。

插件详情页里的配置表单同样保留,两个入口共存。

进程管理

  • 启动前先检测:自己的 pid 文件 + 日志里的 Main Process ID + 6099 端口探测 + 短期互斥锁,绝不重复多开 NapCat / QQ。
  • 关闭插件或退出 DSH 时自动停掉由本插件拉起的 NapCat 进程树(面板可关 stopNapCatOnDisable)。
  • 面板提供「启动内置 NapCat / 重新启动 / 停止」。

关于 QQ(唯一的外部前提)

NapCat 的工作原理是注入已安装的官方 QQ NT 客户端(NapCatWinBootMain.exe + NapCatWinBootHook.dll)。 系统上有官方 QQ 即可,不需要再单独安装或启动 NapCat。插件按下列顺序探测 QQ:

  1. 面板里填写的 qqPath;
  2. %ProgramFiles% / %ProgramFiles(x86)% / %LOCALAPPDATA%\Programs 下的 Tencent\QQNT\QQ.exe;
  3. C: – F: 盘下的 Program Files\Tencent\QQNT\QQ.exe、Tencent\QQNT\QQ.exe。

探测不到时面板会明确提示「未检测到 QQ NT」并给出填写入口。

HTTP 面板接口

注意:宿主 webServer 的 prefix 匹配是 pathname === prefix || pathname.startsWith(prefix + '/'), 因此 prefix 路由的 path 结尾不能带斜杠(早期版本 /napcat-bot/api/napcat/ 就是因为这个永远 404)。

方法路径说明
GET/napcat-bot/api/status连接三态、OneBot 登录态、内置进程态、WebUI Token、运行计数、当前回复引擎
GET/POST/napcat-bot/api/config读取 / 保存配置(保存即热重载)
GET/napcat-bot/api/webuiWebUI 地址 + 自动读取的管理 Token + OneBot token
POST/napcat-bot/api/webui/token重新生成 / 指定 WebUI 管理 Token(并重启生效)
POST/napcat-bot/api/napcat/{start|stop|restart}内置 NapCat 启停
POST/napcat-bot/api/napcat/reconnect只重连插件侧 WS(不动 NapCat、不踢 QQ)
POST/napcat-bot/api/napcat/apply-onebot立即通过 WebUI API 重新应用 OneBot 配置
GET/napcat-bot/api/napcat/log?tail=N控制台日志尾部(含 Token 行)
POST/napcat-bot/api/client-report客户端 UI 注册自检回执(排障用)

排障

现象处理
面板还是旧样子(没有三个灯 / 没有端点行)服务端代码只在 DSH 启动时加载。装完新版必须完全退出 DSH 再启动,否则跑的还是内存里的旧版本
侧边【集成】没有入口看 ~/.dsh/napcat-bot/client-report.json,其中 registered 应含 settings.section(1.5.0 已验证会出现)
WS 状态未知 / 断开,NapCat 里客户端数 01.5.0 已自动纠正到 3001;确认面板「WS 目标」这一行显示的是 ws://127.0.0.1:3001
状态灯一直「WS 正在尝试连接」点「重新应用 OneBot 配置」;若仍不行看日志里有没有 WebSocket服务: ... 已启动
显示「未登录」但 QQ 确实在线1.4.0 已修:OneBot HTTP 必须 POST 到 /<action>,打到根路径只会拿到桩响应
日志面板 4041.3.0 起已修(路由 path 去掉尾斜杠),确认版本 ≥ 1.5.0
收到消息但发不出去1.5.0 会自动改走 WS 通道发送,不再依赖 3000;若仍失败看面板 发送失败:... 的具体报错
NapCat 进程显示「未运行」1.5.0 按端口真实存活判定,会 12s 后自动拉起(10 分钟内最多 3 次);也可点「启动内置 NapCat」
回复走离线兜底面板连接卡显示「回复引擎:离线兜底应答」→ DSH 未配置模型,或 llm 服务不可用
内嵌 WebUI 空白个别版本禁止 iframe 嵌套,点「在浏览器打开」,链接已带 Token

v2.0.0:AstrBot 风格消息管道

三个标签页

标签内容
AI 配置三个状态灯、端点明细、人设生效提示、消息收发记录、全部开关与字段
NapCat WebUI内嵌管理页(自动带 token),扫码登录 QQ
管理人格 / 会话 / 规则 / 知识库 / 任务 五个子页

消息处理顺序

  1. 组件解析(文本/图片/@/语音/文件/卡片)→ 过滤(自身、系统、进退群、红包闪照、空消息、纯表情)
  2. 黑白名单(用户 + 群)→ message_id 去重(跨实例共享,2 分钟窗口;另加 1.5s 内容指纹兜底)
  3. 私聊直达;群聊「@ 唤醒 → 免@ 超时(默认 120s,滑动续期)→ 超时静默」
  4. 会话等待器(多轮流程接管,例如 /idiom 成语接龙,接管期间不过模型)
  5. 指令层(见下)→ 上下文(历史 + 摘要压缩 + 知识库检索)→ 模型流式 → 分段发送

会话隔离

  • 私聊:private:${uid},强制独立,不可关闭。
  • 群聊:开关 groupUniqueSession(面板「会话策略」里)
    • 开:group:${gid}:${uid},每人独立上下文
    • 关:group:${gid},全群共用一套

指令

基础:/help /reset /new /stop /stats /sid /history /ls /rename /del /switch /idiom 管理员:/op /deop /ban /unban /model /provider /groupnew

人格优先级

规则里指定的人格(按会话) > 全局人格(人格库) > 面板单人格字段。 全部走 system prompt 最前面,插件内不再内置任何固定人设(旧版的“小深”会在升级时自动清除)。 人格文本支持变量:{{bot_name}} {{group_id}} {{user_id}} {{user_name}} {{time}}。

知识库

本地 BM25 + 字符 bigram 哈希向量余弦的混合检索(0.65 / 0.35 加权),中文优化; 按规则把知识库绑定到会话,命中后自动加进 system 并在回复末尾标注来源。 支持粘贴文本片段(PDF/DOCX 请先转成文本)。

定时任务

target 形如 group:123456 / private:10001,prompt 以 gen: 开头表示先用模型生成文案再发。 任务持久化在 state.json,支持立即执行/删除,重启后继续按间隔触发。

目录结构

lib/index.js           服务端主入口(配置 schema、路由、生命周期、单例守卫)
lib/client.js          面板 UI(AI 配置 / NapCat WebUI / 管理 三个标签)
lib/pipeline.js        消息流水线:解析 → 过滤 → 去重 → 指令 → 识图 → 搜索 → 推理 → 分段/语音
lib/responder.js       DSH 模型调用(system 只来自面板人格,三级重试,绝不输出套话)
lib/napcat.js          OneBot 连接:HTTP 动作 + 正向 WS + 重连/心跳
lib/napcat-embedded.js 内置 NapCat 进程管理(启动/停止/探活/自动拉起)
lib/vision.js          原生多模态:图片 → 附件引用;两种识图模式
lib/search.js          联网搜索:手动指令 + 自动查证 + 断路器
lib/tts.js             TTS 四种模式 + 强制语音 + 音色池 + 缓存
lib/tts-local.js       内置离线语音(Windows SAPI)
lib/proactive.js       主动发言调度(随缘随机、仅冷却)
lib/state.js           人格/规则/定时任务持久化
lib/sessions.js        会话与上下文
lib/kb.js              知识库混合检索
lib/risk.js            限流 / 黑白名单
tools/                 开发期自测脚本(Node 原生跑,无第三方依赖)

License

MIT