DSH plugin 从零怎么写?最小插件目录、本地构建与装进 profile 调试的完整起步流程

插件开发发布于 2026-09-10作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSH plugin插件开发本地调试apply 函数
写第一个 DSH plugin 只需要一个导出 apply 函数的模块:先用 patch 覆盖层把本地文件插进 Web 界面验证,再做成包用 dsh plugin --profile add 装进 profile,最后用 --dump-config 与日志排错。

写第一个 DSH plugin 不需要搭一套完整工程:一个 TypeScript 模块加一个 apply 函数就是完整插件。 真正需要想清楚的是调试闭环——先让宿主加载到它,再验证它真的生效。这篇按「最小结构 → 接配置 → 装进 profile → 排错」四步走一遍。

最小 DSH plugin 长什么样:一个模块加一个 apply 函数

在 DeepSeek Harness 里,插件就是一个导出 apply 函数的 TypeScript 模块,框架加载时调用 apply 并传入 ctx,你通过 ctx 注册能力(来源)。

  1. 建一个目录 — 找一个空目录作为实验目录,例如在仓库根下建 scratch-plugin/src预期:有地方放插件文件,且不污染主工程结构。
  2. 写最小插件文件 — 文件里导出 name 用于标识身份,并导出 apply(ctx)预期:这就是一个完整插件,nameapply 两者缺一不可。
  3. 需要别的服务就声明 inject — 例如要用工具服务就写 export const inject = ['tools']预期:框架会等到该服务就绪才调用 apply,服务消失时自动卸载。
  4. 选插件形态 — 函数形式最常用;需要向其他插件提供服务时用类形式;也可以导出带 nameinjectapply 的对象。预期:三种形态等价,先用函数形式把闭环跑通。

关于清理:通过 ctx 注册的东西——事件监听、工具、定时器——在插件卸载时会自动撤销,不需要手写 removeListener。只有框架管不到的资源(比如网络连接)才用 ctx.effect() 返回一个处置函数。

ts
import type { Context } from '@deepseek-ai/cordis'

export const name = 'hello-plugin'

export function apply(ctx: Context) {
  console.log('[hello-plugin] plugin loaded!')
}

让 DSH plugin 接受配置:Config 与 apply 的第二个参数

插件要接受用户配置,就导出 Config 描述结构,并把 apply 的第二个参数当作配置对象接收(来源)。

  1. 定义配置结构 — 用 Schema.object({...}) 声明字段。预期:字段类型与默认值都被框架掌握,写错配置会被校验拦下。
  2. 在 apply 里接收配置 — 写成 export function apply(ctx: Context, config: Config)预期:函数体里能直接用 config.xxx,不必自己解析来源。
  3. 给字段留合理默认值 — 让插件在没有任何配置时也能工作。预期:本地调试阶段可以先不写配置,先验证加载。
  4. 配置来源记在 profile — 配置最终写进 profile 的配置层,而不是插件代码里。预期:同一份插件代码在不同 profile 下可以有不同行为,这也是本地调试与线上行为不一致的常见原因。

配置放在哪个文件、三层配置怎么叠加,见《配置文件在哪》。

把 DSH plugin 装进 profile 调试:patch 覆盖层与本地包两条路

本地插件有两条落地路径:单文件用 patch 覆盖层插进去,成型的包用 dsh plugin 装进 profile(来源)。

  1. 写一个 patch 覆盖层 — 建一个 YAML 文件,用 insert 列表写入条目的 idname预期name 指向你的插件文件,必须写绝对路径
  2. 带覆盖层启动 — 用 --patch 把这个 YAML 传给 dsh。预期:启动时终端打印插件里的那行日志,说明插件已被加载。
  3. 换成包装进 profile — 把插件做成带 package.json 的本地包目录,然后执行 dsh plugin --profile web add <本地路径>预期:命令把参数转发给 pnpm,pnpm 会把本地目录装进该 profile 的 node_modules。
  4. 改完重新加载验证 — 修改插件代码后重启宿主再观察日志。预期:改动生效;没有生效先确认加载的是不是你改的那份文件。
  5. 也可以走图形界面 — 本地目录或源码同样能从插件市场的自定义安装装进当前 profile。预期:省去手敲命令,装完在已安装列表里能看到条目。
自定义安装

本地目录安装的完整说明见《本地目录怎么装》,开发全流程与打包见《怎么开发 DSH plugin》。

调试 DSH plugin 与排错:--dump-config、日志与加载失败怎么查

插件没生效时先分两层判断:它到底有没有进配置树,以及 apply 有没有抛错(来源)。

  1. 先干跑一次配置检查 — 用 --dump-default-config--dump-config 在不启动的情况下打印合成后的配置树。预期:配置树里能看到你的插件条目,说明加载路径对;看不到就先修 patch 或依赖声明,别急着改代码。
  2. 再看启动输出 — 宿主启动时会在终端打印插件加载信息。预期:能区分「没被加载」与「加载了但报错」两种情况。
  3. 加载失败按 apply 报错处理apply 抛出异常会让插件进入失败状态。预期:读终端里的异常栈,定位到具体代码行,而不是反复重启。
  4. 按类别看系统日志 — 在日志里按类别与级别筛选。预期:能看出失败发生在加载阶段还是运行阶段,避免只看到一句「没生效」。
  5. 顺带确认 profile 没搞错 — 插件装在哪个 profile,就只在该 profile 生效。预期:换 profile 启动却没装过插件,表现就是「明明装了却不起作用」。

调试环境怎么搭、源码构建怎么跑,见《源码构建与调试环境》。

开发 DSH plugin 的注意事项与局限

  1. apply 是唯一硬要求:没有 apply 的模块不会被当作插件加载,name 用于标识身份,二者别漏。
  2. 插入本地文件必须用绝对路径:patch 覆盖层只贡献配置,不会改变模块解析目录,相对路径会找不到文件。
  3. 依赖要声明不要假设:需要 toolsllm 等服务就写进 inject,让框架处理加载时序,别自己在 apply 里等待。
  4. 注意自动清理的边界ctx 注册的资源会自动撤销,自己创建的资源必须用 ctx.effect() 返回处置函数,否则热重载会留下残留。
  5. 开发者预览阶段接口会变:官方明确未来会有破坏兼容性的变更,插件代码要保持可调整,别把实现绑死在某一版内部行为上。

跑通本地闭环之后再考虑发布:把仓库加上官方约定的 dsh-plugin 话题,然后走插件市场上架流程,步骤见《怎么发布到插件市场》。开发期间想找现成插件参考实现,可以在 DSH Plugin Hub 里按分类浏览。

来源:DeepSeek Harness 开发指南 - 第一个插件DeepSeek Harness 开发指南 - 插件配置dsh CLI README(官方仓库)

常见问题

写一个最小的 DSH plugin 需要哪些文件,一定要建完整工程吗?

最小的 DSH plugin 只是一个导出 apply 函数的 TypeScript 模块,name 用于标识插件身份,需要别的服务时再加 inject。官方入门教程就是建一个目录放一个 .ts 文件、不建完整工程,用 patch 覆盖层把它插进 Web 界面验证加载。

DeepSeek Harness 的插件怎么读取用户配置并生效?

DeepSeek Harness 插件通过导出 Config 描述配置结构,并把 apply 的第二个参数作为配置对象接收,框架会按 Config 校验并传入。写法是 export const Config: Schema<Config> = Schema.object({...}) 配合 export function apply(ctx: Context, config: Config)

本地写的 DSH plugin 怎么装进 profile 调试,不用发布也能装吗?

DSH plugin 不用发布也能装。两条路:把本地文件用 patch 覆盖层直接插进运行中的配置树,适合单文件快速验证;或者把本地包目录用 dsh plugin --profile web add <本地路径> 装进 profile,因为它转发给 pnpm,pnpm 支持装本地路径。

DSH plugin 加载失败怎么排查,插件没生效该看哪里?

DSH plugin 加载失败先分两层看:配置层用 dsh --dump-config 确认插件是否真的进了合成后的配置树,运行层看宿主启动时的终端输出与系统日志里的加载报错。apply 抛出异常会让插件进入失败状态,需要按报错改代码而不是反复重启。

本地调试没问题了,把 DSH plugin 发布到市场的流程是什么?

DSH plugin 本地跑通后再考虑发布:把插件做成独立的 npm 包或公开仓库,仓库加上官方约定的 dsh-plugin 话题便于被发现,然后走插件市场上架流程。发布与上架的完整步骤与本地调试不是一回事,可参考站内的发布教程。

相关术语

apply 函数
apply 函数是 DSH plugin 的入口,框架加载插件时调用它并传入 `ctx` 上下文对象,插件通过 ctx 注册事件监听、工具与服务。它是判断一个模块是不是插件的核心标志,没有 apply 的模块不会被当作插件加载。DeepSeek Harness 开发指南 - 第一个插件
inject 声明
inject 声明是插件用来说明自己依赖哪些服务的字符串数组,例如 tools 或 llm。声明后框架会等这些服务就绪再调用 apply,服务消失时插件自动卸载、恢复后重新加载,因此插件不必自己处理依赖时序。DeepSeek Harness 开发指南 - 第一个插件
patch 覆盖层
patch 覆盖层是一份只贡献配置的 YAML 文件,可通过 `--patch` 传给 dsh,用于把本地插件文件插入运行中的配置树。它不会改变 loader 解析模块路径时使用的 profile 目录,所以插入本地文件时路径必须写绝对路径。DeepSeek Harness 开发指南 - 第一个插件
--dump-config
--dump-config 是 DeepSeek Harness 在不启动应用的情况下打印合成后配置树的参数,用来确认本地插件是否真的被加载进配置。调试插件时它先于日志给出答案:配置树里没有这个插件,问题就不在插件代码本身。dsh CLI README

来源