DeepSeek Harness101 快速开始 返回首页 官方教程 ↗

从源码运行路径开始

写下第一个 Harness 插件。

创建一个 TypeScript 模块,通过配置叠加加载它,再验证卸载时的自动清理。这里的代码和行为均来自官方开发教程。

开始之前先完成官方仓库的从源码运行流程,并从仓库根目录执行本文命令。
scratch-plugin/src/my-plugin.ts
import type { Context } from '@deepseek-ai/cordis'

export const name = 'hello-plugin'

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

创建模块

一个 apply 函数就是完整插件

Harness 加载模块时调用 apply,并传入 Cordis Context。插件通过 ctx 注册工具、事件和其他能力。name 用于提供清晰的插件标识。

在仓库根目录创建临时项目:

shell
mkdir -p scratch-plugin/src

然后把上方完整代码保存到 scratch-plugin/src/my-plugin.ts。

加载配置

用 Web overlay 插入本地模块

先运行 pwd,复制仓库绝对路径。patch 文件贡献配置,但不会改变 loader 解析模块时采用的 profile 目录,所以本地插件路径必须是绝对路径。

创建 scratch-plugin/cordis.yml,并替换示例路径:

cordis.yml
- insert:
    - id: hello
      name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'
shell
pnpm dsh web --patch ./scratch-plugin/cordis.yml

打开 http://127.0.0.1:3080。启动期间,终端应打印 [hello-plugin] plugin loaded!。

管理清理

让副作用随插件一起卸载

通过 ctx 注册的事件监听、工具和定时器会自动清理。网络连接等外部资源需要显式释放时,用 ctx.effect() 返回 disposer。

TypeScript
export function apply(ctx: Context) {
  ctx.effect(() => {
    const timer = setInterval(() => {
      console.log('heartbeat')
    }, 5000)

    return () => clearInterval(timer)
  })
}

disposer 在插件卸载时运行。这样重载配置或移除插件时,不会留下孤立资源。

声明依赖

需要服务时,先写进 inject

插件消费 tools 或 llm 等服务时,用 inject 声明。框架会等待全部必需服务就绪,再调用 apply。

TypeScript
export const name = 'my-tool-plugin'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register(/* ... */)
}

函数形式适合大多数插件。插件需要向其他插件提供服务时,再考虑继承 Service 的类形式。

继续开发

从最小模块走向真实能力