koishi-plugin-chatluna-dsh-adapter

中文文档
0.3.1发布于 2026/11/04MITCommonJS

用于ChatLuna的DeepSeek线束工具,具有每个用户/每个组的工作区:用于正常模型的关键字门控线束工具,以及可选的DSH模型适配器。ChatLuna保留其预设,字符管道和QQ渲染。

中文使用文档
文档目录16 节
  1. ⚠️ 如果你同时用 chatluna-character
  2. 两种模式
  3. 工具模式(默认,推荐)
  4. 模型适配器模式(可选)
  5. 安装
  6. 配置
  7. 桌面版示例
  8. 用法
  9. 关于 chatluna-character
  10. 文件夹位置与大小限制
  11. 安全与隔离
  12. 扩展接口
  13. 已知限制
  14. 排错
  15. 验证记录
  16. License

koishi-plugin-chatluna-dsh-adapter

把 DeepSeek Harness(DSH) 接进 ChatLuna。默认是「工具模式」:普通聊天仍然走你原来的模型、原来的预设、原来的 chatluna-character;只有你在消息里带上关键词时,模型才会看到一个 harness 工具,把任务交给 Harness 执行,结果再回到原模型/角色管线,由 ChatLuna 渲染到 QQ。

也保留「模型适配器模式」:把 ChatLuna 的模型直接选成 dsh/deepseek-harness,让 Harness 当对话主脑。两种模式可以共存,但通常只需要工具模式。

从 0.3.1 起,每个会话有独立工作区:部署者(trustedUsers)使用基础 workspace 和全部工具;其他私聊使用 private/<QQ号>;群聊使用 groups/<群号>(也可按成员再分)。访客可以正常用 Harness,但越界操作不会自动批准。

⚠️ 如果你同时用 chatluna-character

请在 chatluna-character 里关闭 「是否启用 <think> 标签」(配置项 toolCallReplyThinkTag,默认是开启的)。

开启时,它的 character_reply 工具会强制要求 think 字段。deepseek-flash 这类模型有时会漏掉,随后报:

  • missing character_reply tool call
  • 或 invalid character_reply tool call ... required property "think"

这时 Harness 其实已经执行完了(日志里有 harness task done),失败的是角色插件生成最终回复。关闭该选项后不再要求 think;如果一定要保留 think 标签,就换更强的 tool-calling 模型,并在预设/作者注里明确要求每次 character_reply 都带 "think": "..."。

两种模式

工具模式(默认,推荐)

QQ / NapCat
    │
    ▼
Koishi ──► ChatLuna(原模型 / 原预设 / chatluna-character)
                │
                │  当前消息含 #harness
                ▼
          harness 工具(本插件)
                │  ACP over stdio,每次调用一个 dsh 进程
                ▼
          DeepSeek Harness
          ├─ pwsh / fs / web / skill / subagent / workflow ...
          └─ 返回任务结果文本
                │
                ▼
          原模型继续生成(需要时再调 character_reply)
                │
                ▼
          ChatLuna renderer ──► QQ

关键点:

  • 不改模型。ChatLuna 和 chatluna-character 继续用你原来的模型;character_reply 仍由原模型生成。
  • 默认不经过 Harness。只有最后一条用户消息包含 triggerKeywords(默认 #harness、harness、用harness、调用harness)时,harness 工具才会被授权给这一轮。
  • 关键词门禁不依赖工具 selector。chatluna-character 传给 selector(history) 的历史不含当前消息,所以本插件用一个前置 Koishi middleware 按会话“武装”工具,再由 authorization(session) 检查。这样角色插件也能正确触发。
  • 工具由 DSH 执行。模型只负责决定“要不要调用”和“任务描述是什么”;文件、命令、网页、子代理都在 DSH 内完成。
  • 工作区按会话隔离。DSH 进程的 cwd 和 sandbox-policy.workspaceRoot 都指向该会话的文件夹;trustedUsers 永远用基础 workspace,所以即使人在群里,也按“部署者”处理。
  • 访客能干活,但不能越界。访客仍可使用 shell/fs/web 等工具,但 DSH 的“离开工作区”审批会被拒绝;只有 owner 的审批会放行。

模型适配器模式(可选)

ChatLuna 预设(已渲染的 SystemMessage)
        │
        ▼
本适配器(平台 dsh / 模型 deepseek-harness)
        │  ACP stdio + 临时 cordis.patch.yml
        ▼
DeepSeek Harness(persona = ChatLuna 预设)
        │
        ▼
ChatLuna renderer ──► QQ

适合“整个机器人的人格就是 Harness”的场景。代价是 ChatLuna 的工具不会自动变成 DSH 工具,且每轮要启动一个 DSH 进程。工具模式没有这些问题。

安装

发布到 npm 后,在 Koishi 实例目录(例如 C:\Users\<你>\AppData\Roaming\Koishi\Desktop\data\instances\default)直接安装:

npm install koishi-plugin-chatluna-dsh-adapter

Yarn 4(Berry):

corepack yarn add koishi-plugin-chatluna-dsh-adapter

也可以在 Koishi 控制台的「插件市场」里搜索 chatluna-dsh-adapter 安装。

开发阶段或离线安装可以用 tgz。Yarn 4 必须写成 包名@file:路径:

corepack yarn add "koishi-plugin-chatluna-dsh-adapter@file:./koishi-plugin-chatluna-dsh-adapter-0.3.1.tgz"

如果 Yarn 报 YN0027 / YN0035,或者把路径当成 npm 包名去 registry 找,就是这个格式问题。也可以直接用 npm:

npm install "./koishi-plugin-chatluna-dsh-adapter-0.3.1.tgz"

然后在 Koishi 控制台启用 chatluna-dsh-adapter。不需要去 ChatLuna 或 chatluna-character 里改模型。

配置

配置项默认值说明
executabledshDSH 可执行文件。桌面版填 F:\kunfox\deepseek\DeepSeek Harness.exe。
cliPath空桌面版的 cli.js 路径;使用 PATH 里的 dsh 时留空。
profileacpDSH profile。
dshHome空DSH_HOME。留空继承 Koishi 进程环境;Windows 默认是 C:\Users\<你>\.dsh。
workspace空基础工作区;留空用 <koishi baseDir>/data/chatluna-dsh。owner 直接用这里,访客用它的子目录。
groupWorkspaceModesharedshared = 每个群一个共享文件夹;per-user = 每个群成员在群文件夹下再分自己的子目录。
maxWorkspaceSizeMB0访客私聊/群文件夹的软上限(MB),0 = 不限。超过后会中止当前 Harness 任务。建议 256–512。
ownerWorkspaceSizeMB0owner 基础工作区的软上限(MB),0 = 不限。
workspaceQuotaCheckIntervalMs1500大小检查间隔(毫秒)。调小更及时,但大目录会更耗 I/O。
model空DSH 模型,可填 deepseek-flash、deepseek-account/deepseek-flash 或 ["deepseek-account","deepseek-flash"]。适配器会按 DSH 会话暴露的模型选项自动解析;留空用默认路由(缺凭据时会失败)。
toolPermissiontrustedallow = 所有人可用工具;trusted = owner 用基础工作区+全部工具,访客按 guestToolAccess;reject = 所有人禁用工具。
guestToolAccesstrue非 owner 是否也能使用工具;他们只能在自己的私聊/群文件夹里操作。
trustedUsers[]完全信任的 Koishi userId:基础工作区 + 全部工具;在群里也按 owner 处理。
trustedGuilds[]允许使用 Harness 的群 guildId;不授予基础工作区,成员仍用群文件夹。
requestTimeout180000单次 DSH 调用超时(毫秒)。
contextSize128000仅模型适配器模式使用:向 ChatLuna 声明的上下文长度。
toolEnabledtrue是否注册 harness ChatLuna 工具。
toolNameharness注册给 ChatLuna 的工具名。
triggerKeywords["#harness","harness","用harness","调用harness"]只有最后一条用户消息包含其中之一,才授权工具。
toolSystemPrompt空Harness 任务执行器的系统提示词;留空用内置的简洁执行器提示。
characterThinkTagRemindertrue仅用于在配置页显示 chatluna-character 的 <think> 兼容提醒,不影响运行。
debugfalse输出关键词匹配、授权、任务耗时等日志。

桌面版示例

executable: F:\kunfox\deepseek\DeepSeek Harness.exe
cliPath: F:\kunfox\deepseek\resources\app.asar\dsh\node_modules\@deepseek-ai\dsh-desktop-host\lib\cli.js
profile: acp
dshHome: C:\Users\MECHREV\.dsh
workspace: D:\koishi-dsh-workspace
model: deepseek-flash
toolPermission: trusted
guestToolAccess: true
groupWorkspaceMode: shared
trustedUsers:
  - '你的QQ号'
trustedGuilds: []
requestTimeout: 300000
debug: true

executable 和 cliPath 必须成对:

  • 桌面版:executable 指 DeepSeek Harness.exe,cliPath 指 ...\dsh-desktop-host\lib\cli.js。
  • 命令行版:executable 指 ...\runtime\cli\bin\dsh.cmd,cliPath 留空。

Koishi 进程的 PATH 通常没有 dsh,所以不要只填 executable: dsh 就指望它能找到。

用法

在 QQ 里正常聊天即可。需要 Harness 时,在消息里带关键词:

#harness 看一下 D:\koishi-dsh-workspace 里有哪些文件
harness 帮我查一下今天的日期,用 pwsh
用harness 把 https://httpbin.org/uuid 的内容抓下来

模型会把这个任务写成 harness 工具调用;插件启动 DSH 执行,把结果作为工具输出交回模型。chatluna-character 随后照常生成 character_reply,所以角色人格、分段、图片/语音渲染都不变。

没有关键词的消息不会看到 harness 工具,正常走原模型。

关于 chatluna-character

chatluna-character 的 experimentalToolCallReply 要求模型最终返回 character_reply 工具调用。工具模式下,这个调用仍由原模型生成,Harness 只是一个额外的普通工具,因此不会再出现 missing character_reply tool call。

前提:

  • chatluna-character 的 toolCalling 保持开启;
  • 原模型支持 tool calling;
  • 不要把 chatluna-character 的模型改成 dsh/deepseek-harness(那是模型适配器模式,适配器只声明 TextInput,不会产生 character_reply)。

如果仍报错,把 debug 打开,确认日志里出现了 harness authorization allowed=true,并且 chatluna-character 自己没有把模型切到 dsh。

文件夹位置与大小限制

以 workspace: D:\koishi-dsh-workspace 为例:

会话实际目录
owner(trustedUsers)D:\koishi-dsh-workspace 本身
私聊访客D:\koishi-dsh-workspace\private\<QQ号>
群聊(shared,默认)D:\koishi-dsh-workspace\groups\<群号>
群聊(per-user)D:\koishi-dsh-workspace\groups\<群号>\<QQ号>

private / groups 都是第一次有对应会话调用 Harness 时才创建;所以现在只看到 private、没有 groups 是正常的。

大小限制在配置里:

maxWorkspaceSizeMB: 512          # 访客私聊/群文件夹上限,0 = 不限
ownerWorkspaceSizeMB: 0          # 你自己的基础工作区上限,0 = 不限
workspaceQuotaCheckIntervalMs: 1500

实现方式:任务开始前先量一次目录;任务运行中每隔 workspaceQuotaCheckIntervalMs 递归统计文件大小;超过上限就中止 DSH 进程并报 harness workspace quota exceeded。该限制只作用于工具模式的 runTask;模型适配器模式不经过这里。

注意这是软保护,不是 NTFS 硬配额:

  • 单个超大文件可能在两次检查之间短暂超限;任务会被中止,但已经写下的部分文件不会自动删除,需要你手动清理。
  • 它只统计当前会话文件夹,不统计 DSH 进程在文件夹外创建的临时文件。
  • 需要真正的硬上限,应该给 Koishi 用独立 Windows 账户并配 NTFS 配额/FSRM,或用固定大小的 VHD;插件本身做不到硬隔离。

查看当前占用:

Get-ChildItem -Recurse D:\koishi-dsh-workspace |
  Measure-Object Length -Sum |
  Select-Object Count,Sum

安全与隔离

  • owner(trustedUsers):使用基础 workspace,拥有全部工具;在群里触发也按 owner 处理。只把自己和完全信任的人放进去。
  • 私聊访客:工作区是 <workspace>/private/<QQ号>。第一次调用时自动创建。
  • 群聊访客:工作区是 <workspace>/groups/<群号>;同一群成员共用这个文件夹(groupWorkspaceMode: shared)。如果不想让群友互相看到文件,改成 per-user。
  • 访客工具:默认 guestToolAccess: true,所以访客也能用 shell/fs/web 等工具。DSH 会把写入/删除限制在各自文件夹,进程 cwd 也在那里;但读取不受 DSH sandbox 限制(见下面的“读隔离”)。
  • toolPermission: reject 会禁用所有工具,只保留聊天;allow 对访客仍只给文件夹,不会给基础工作区。
  • 读隔离(重要):DSH 当前只围栏写/删除与 cwd,不围栏读。访客进程与 Koishi 使用同一个 Windows 账户,因此能读取该账户可读的任何文件,包括基础 workspace、用户目录和 DSH 凭据。不要把密钥、.env、个人资料放在同一账户可读的位置;公开机器人应先设 guestToolAccess: false,或把 Koishi 放进独立 Windows 账户/虚拟机。真正的读隔离需要受限 MCP 文件工具或 AppContainer,当前版本尚未实现。
  • 不要把基础 workspace 指向含密钥、.env、个人资料的目录。owner 能访问整个基础工作区;访客的写入被限制,但读取仍受同一账户权限支配。
  • 群共享文件夹的副作用:群友可以读写别人留下的文件;需要隐私时用 per-user,或只让 owner 使用。
  • 访客可以发起耗时任务,目前没有每用户限流;公开群建议配合 Koishi 的频率限制或只开 trustedGuilds。
  • 插件不接触 API Key;DSH 使用 dshHome 下已保存的凭据。

扩展接口

插件在 Koishi 上暴露 ctx.dshHarness,给以后单独的 Harness 配置插件使用:

ctx.dshHarness.version         // 2
ctx.dshHarness.toolPluginIds   // DSH profile 里可被策略开关的工具插件 id
ctx.dshHarness.config          // 当前配置
ctx.dshHarness.isOwner(session)
ctx.dshHarness.isTrusted(session) // 兼容别名,语义同 isOwner

ctx.dshHarness.resolveScope(session)
// { kind: 'owner'|'private'|'group', workspace, allowTools,
//   approvePermissions, fullAccess, label, ... }

await ctx.dshHarness.runTask(task, { session, signal })

const off = ctx.dshHarness.registerPermissionProvider(async (session, task) => {
  // 返回 false 拒绝;true/undefined 放行
})

const off2 = ctx.dshHarness.registerPostProcessor(async (text, context) => {
  // context.scope 含本次工作区;可以改写 Harness 返回的文本
  return text
})

const off3 = ctx.dshHarness.registerScopeResolver((session, base) => {
  // 返回 { workspace, allowTools };访客的 workspace 不允许逃出 base
  return null
})

const off4 = ctx.dshHarness.registerToolPolicy((session, scope) => {
  // 未来 DSH 插件可在这里按私聊/群限制可用工具
  return { enabledToolIds: ['tool-fs', 'tool-web'] }
  // 或 { disabledToolIds: ['tool-pwsh'] }
})

ctx.dshHarness.registerTool('my_tool', myChatLunaTool)
  • registerScopeResolver 在默认工作区计算之后执行,可覆盖 workspace/allowTools;访客返回 base 之外的绝对路径会抛错,owner 不受限。
  • registerToolPolicy 可返回 enabledToolIds(白名单)或 disabledToolIds(黑名单);它影响的是 DSH profile 里的工具插件,不是 ChatLuna 工具。
  • registerPermissionProvider 在每次任务前执行,任一返回 false 就抛错;registerPostProcessor 在结果返回前执行;registerTool 直接转给 ChatLunaPlugin.registerTool。
  • 这些接口是 v2,后续尽量只增不改。

已知限制

  • 不是逐 token 流式:DSH 的 ACP 只在消息提交时发 agent_message_chunk,所以 ChatLuna 会先显示“正在输入”,然后一次性收到整段工具结果。
  • 每次调用启动一个 DSH 进程:实测一次简单任务约 5–17 秒(取决于工具和模型);首次运行 profile 可能触发依赖安装,会更慢。
  • 关键词只看用户消息:由前置 middleware 判断 session.content;引用、转发里出现关键词也可能触发。
  • 工具模式需要原模型支持 tool calling。如果原模型不支持,harness 工具不会被调用。
  • ChatLuna 的工具不会自动变成 DSH 工具,反之亦然;两边工具是分开的。
  • 群文件夹默认共享:同群成员会看到同一个 groups/<群号> 下的文件;需要隔离时设 groupWorkspaceMode: per-user。
  • 隔离依赖 DSH sandbox:它只限制写入/删除与 cwd,不限制读取,也不是完整容器;对恶意用户仍建议独立账户/虚拟机。
  • 目前没有每用户并发/频率限制:ChatLuna 的全局并发限制仍生效,但单个用户连续触发会连续启动 DSH 进程;公开机器人建议在 Koishi 侧再加限流。
  • {{char}} 不会自动映射(仅模型适配器模式相关):ChatLuna 变量表里是 {{name}} 和 {{user}},未识别的 {{char}} 会渲染成空串。
  • 目前只在 Windows + DSH 0.2.1-rc.5 + ChatLuna 1.4.4 + chatluna-character 0.0.235 上验证。

排错

现象处理
missing character_reply tool call先确认 chatluna-character 的模型不是 dsh/deepseek-harness;工具模式下保持原模型,toolCalling 开启。若日志里已经有 harness task done,多半是下面的 think 问题。
invalid character_reply tool call ... required property "think"在 chatluna-character 关闭「是否启用 <think> 标签」(toolCallReplyThinkTag: false),或换更强模型并在预设中强制带 "think": ""。
dsh exited with code 1,stderr 是 'dsh' 不是内部或外部命令填桌面版 executable + cliPath,或 dsh.cmd 的完整路径。
no API key for provider route "deepseek-official"设 model 为有凭据的模型,如 deepseek-flash 或 deepseek-account/deepseek-flash。
unknown model option: deepseek-flash0.2.1 已支持裸模型名;若仍出现,说明 DSH 的模型列表里没有该模型,填 deepseek-account/deepseek-flash 或先跑 dsh --profile acp --dump-config 确认。
模型完全不知道有 harness 工具打开 debug,看日志有没有 harness authorization allowed=true;确认消息里关键词、toolEnabled、toolPermission、trusted 列表。
每次普通聊天也都调用 Harness检查是否把 triggerKeywords 设得太宽(例如只写 h),或 toolPermission: allow 且模型过于主动;把关键词改成更明确的 #harness。
Yarn 安装报 YN0027/YN0035用 包名@file:./xxx.tgz,或改用 npm。
模型列表里没有 dsh只影响模型适配器模式;工具模式不需要选 dsh 模型。确认插件已启用、ChatLuna 已加载。

验证记录

  • 工具模式真实 DSH:消息 #harness 现在几点?,Harness 执行 Get-Date -Format o,返回 2026-11-03T18:42:57.0117758+08:00,耗时约 5.9 秒;无关键词时授权为 false。
  • 模型适配器模式:注入 persona 后模型回答 I am TestPersona, and my color is teal.,stopReason: end_turn。
  • 非可信用户写文件被禁用工具插件阻止;可信用户可正常创建文件。
  • 0.3.0 隔离测试:访客私聊 Get-Location 返回 D:\koishi-dsh-workspace\private\guest-1;尝试写 D:\koishi-dsh-workspace\escape-guest.txt 被 sandbox/approval 拒绝,文件未创建。
  • 0.3.0 owner 测试:trustedUsers 用户在群里仍使用基础 D:\koishi-dsh-workspace,Get-Date 正常返回。
  • 0.3.0 读侧测试:访客能读取基础 workspace 里的测试文件;这不是 bug,而是 DSH sandbox 只围栏写/删除的已知限制(见“读隔离”)。
  • 0.3.1 配额测试:1 MB 上限下让 Harness 写 2 MB 文件,任务返回 harness workspace quota exceeded;文件已写入 2 MB,说明轮询式配额会拦截任务但不能阻止瞬时大文件,需要手动清理。

License

MIT

版本与发布记录

koishi-plugin-chatluna-dsh-adapter 共发布 4 个版本,首次发布于 2026/11/03;过去 12 个月发布了 4 个版本。

版本发布日期距今
0.3.1latest2026/11/041 天前
0.3.02026/11/041 天前
0.2.12026/11/031 天前
0.0.0-stage2026/11/031 天前

关于 koishi-plugin-chatluna-dsh-adapter 的常见问题

koishi-plugin-chatluna-dsh-adapter 是什么?

用于ChatLuna的DeepSeek线束工具,具有每个用户/每个组的工作区:用于正常模型的关键字门控线束工具,以及可选的DSH模型适配器。ChatLuna保留其预设,字符管道和QQ渲染。

如何安装 koishi-plugin-chatluna-dsh-adapter?

在项目目录运行 npm install koishi-plugin-chatluna-dsh-adapter,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:koishi(^4.18.9)、koishi-plugin-chatluna(^1.4.4)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

koishi-plugin-chatluna-dsh-adapter 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/koishi-plugin-chatluna-dsh-adapter 是否存在。

koishi-plugin-chatluna-dsh-adapter 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

koishi-plugin-chatluna-dsh-adapter 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

koishi-plugin-chatluna-dsh-adapter 可以商用吗?

koishi-plugin-chatluna-dsh-adapter 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

koishi-plugin-chatluna-dsh-adapter 还在维护吗?

最新版本 0.3.1 发布于 2026/11/04(1 天前);至今共发布 4 个版本,其中过去 12 个月发布了 4 个;首次发布于 2026/11/03。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。