DSH plugin 开发示例:最小插件、工具插件、事件插件、带配置插件与服务插件的完整代码示例

插件开发发布于 2026-09-12作者: DeepSeek Plugin 插件市场
DSH pluginDeepSeek Harness插件开发示例示例代码Cordis
DeepSeek Harness(DSH)插件开发示例合集:最小插件、模型工具、事件监听、带 Config 配置与服务提供者五个可直接抄的示例,每个含目录结构、完整代码与运行方式。

DSH plugin 开发示例比规范更好上手:五个示例(最小插件、模型工具、事件监听、带配置、提供服务)覆盖了插件开发的所有常见形态,每个都可以直接抄进 scratch-plugin/src/,用一个 --patch 覆盖层跑起来。 无论叫 DSH插件 还是 DeepSeek插件,跑的步骤完全一样。

五个示例共用同一套目录与运行方式,差别只在源码里注册了什么。先按三步把骨架跑通(来源):

  1. 建目录 —— 在检出根创建 scratch-plugin/src/预期:目录结构如下。
deepseek-harness/            # 检出根(已完成 run-from-source)
└── scratch-plugin/
    ├── src/my-plugin.ts     # 下面五个示例都写在这里
    └── cordis.yml           # 覆盖层配置
  1. 写覆盖层配置 —— 创建 scratch-plugin/cordis.ymlname 填插件源码的绝对路径:
yaml
# scratch-plugin/cordis.yml
- insert:
    - id: demo
      name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'
  1. 启动 —— 执行 pnpm dsh web --patch ./scratch-plugin/cordis.yml预期:Web UI 起来,并把 my-plugin.ts 挂进插件树。

路径必须写绝对路径,patch 只贡献配置、不改变 loader 解析模块路径的 profile 目录。环境没搭好的先看 开发环境搭建

DSH plugin 示例一:最小插件

用途:验证环境与加载链路。 只有一个会打日志的 apply

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

export const name = 'hello-plugin'

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

预期结果:启动时终端打印 [hello-plugin] plugin loaded!。看不到这行就别往下走,先排查路径与构建。

DSH plugin 示例二:模型工具

用途:让模型能调用你的能力。 注意 injectdefineTool 三件套:

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

export const name = 'greet-tool'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'greet',
    description: 'Greet someone by name.',
    parameters: {
      name: { type: 'string', required: true, description: 'The name to greet' },
    },
    output: {
      schema: { type: 'string' },
      render: (_args, value) => [{ type: 'text', text: value }],
    },
    async execute(args) {
      return `Hello, ${args.name}!`
    },
  }))
}

预期结果:向模型输入「Use the greet tool to greet Ada.」,模型调用 greet 并拿到 Hello, Ada!execute 契约与卡片渲染的完整规则见 怎么写工具插件

DSH plugin 示例三:事件监听与自动清理

用途:在框架时机插入逻辑,并正确释放手动资源。 通过 ctx.on 注册监听、通过 ctx.effect 交出处置器:

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

export const name = 'heartbeat-plugin'

export function apply(ctx: Context) {
  ctx.effect(() => {
    const timer = setInterval(() => console.log('heartbeat'), 5000)
    // 返回的函数在插件卸载时执行。
    return () => clearInterval(timer)
  })
}

预期结果:插件运行后每 5 秒打印一次 heartbeat;卸载插件后定时器停止。把定时器直接写在 apply 里而不包 ctx.effect,插件卸载后仍会继续跑——这是最常见的资源泄漏来源。

DSH plugin 示例四:带配置的插件

用途:让用户能改你的行为。 声明 Config 类型与同名 schema,apply 接收第二个参数:

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

export interface Config {
  greeting: string
  maxRetries: number
}

export const Config: Schema<Config> = Schema.object({
  greeting: Schema.string().default('Hello'),
  maxRetries: Schema.number().default(3),
})

export const name = 'configured-plugin'

export function apply(ctx: Context, config: Config) {
  console.log(`${config.greeting} (retries: ${config.maxRetries})`)
}

预期结果:不提供配置时打印默认值 Hello (retries: 3);提供部分配置时,未提供的字段被补上默认值。配置在界面上的展示见 插件配置怎么用

DSH plugin 示例五:提供服务

用途:让其他插件调用你。 这时才需要类形态——构造函数里注册服务名,消费方用 inject 声明:

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

export default class MetricsService extends Service {
  static inject = ['tools']

  constructor(ctx: Context) {
    super(ctx, 'metrics')
    // 在这里做同步初始化。
  }

  count(name: string) {
    console.log(`[metrics] ${name}`)
  }
}

预期结果:插件加载后,其他插件用 export const inject = ['metrics'] 即可在 apply 里拿到 ctx.metrics只有对外提供服务时才用类形态,普通插件用函数形态更简单(来源)。

从 DSH plugin 示例到可安装的包

示例只在检出里跑通,还不能分发。 要变成可安装的包,需要补三样:package.json 里声明 main(指向入口)、type: modulefiles(包含入口与 cordis.patch.yml)与 dsh.bundle.patch(指向该 patch 文件),并把它放进一个带 cordis.patch.yml 的工程目录。

发布路径:先照 打包成 bundle 生成可安装产物,再用 发布到插件中心 提交收录;装好后可在 DSH Plugin Hub 的已安装列表核对插件与配置项。写代码时的硬性自检项见 开发规范

常见问题

DSH plugin 开发示例里,哪个最适合先照着跑一遍?

**DSH plugin 开发示例里先跑最小插件**:只有 name 与一个会打日志的 apply,用 --patch 覆盖层挂进 Web UI,看到日志就说明环境与加载链路都通了。**官方也把最小插件放在教程第一步**,因为后面所有示例都只是往这个骨架里加注册代码(来源:官方「你的第一个插件」)。

DSH plugin 示例里的目录结构应该怎么摆?

**DSH plugin 示例的目录结构分两阶段**:本地调试阶段官方从仓库根创建 scratch-plugin/src/,用绝对路径挂载;准备分发时再把工程独立出来,带上 package.jsonmaintype: modulefilesdsh.bundle.patch)与 cordis.patch.yml。**两者不是二选一**:先在检出里调通,再把它抽成可安装的包(来源:官方「你的第一个插件」与「打包与安装插件」)。

有没有一段示例能同时展示工具与配置?

**想在一个 DSH plugin 里同时展示工具与配置,把工具示例与配置示例叠起来就是**:先声明 inject = ['tools']Config schema,再在 apply(ctx, config) 里用 config 的值构造 defineTooldescription 或行为。**注意 apply 的第二个参数来自框架按 schema 补齐后的配置对象**,可直接使用(来源:官方「构建一个工具」与「插件配置」)。

DSH plugin 服务示例里的类写法和普通插件有什么区别?

**DSH plugin 的服务示例用类形态**:export default class ... extends Service,在构造函数里 super(ctx, 'myService') 把服务名注册进上下文,其他插件通过 inject: ['myService'] 消费。**普通插件注册能力就结束,服务插件还对外提供实例**——所以只有「别的插件要调用你」时才用类形态(来源:官方「服务与依赖」)。

相关术语

示例工程(scratch-plugin)
scratch-plugin 是 DSH plugin 官方教程里用于本地调试的示例目录,位于 Harness 检出根下,通过 --patch 覆盖层以绝对路径挂载,不参与分发。https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/index.md
defineTool
defineTool 是 DSH plugin 里声明模型可调用工具的函数,接收 name、description、parameters、output 与 execute,并从 parameters 推导 execute 的入参类型。https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/tool.md
Config schema
Config 是 DSH plugin 用 Schemastery 声明配置类型与默认值的方式;框架加载插件时校验配置并补齐默认值,再把结果作为 apply 的第二个参数传入。https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/config.md
Service
Service 是 DSH plugin 类形态插件的基类,构造函数里 super(ctx, name) 会把该服务注册到上下文,其他插件通过 inject 声明依赖后即可使用。https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/framework/service.md

来源