夜雨聆风学习资料网

ARTICLE · 997053

DeepSeek Harness 插件开发完整教程

DeepSeek Harness 插件开发完整教程

一、核心理念:一切皆插件

DeepSeek Harness(简称 dsh)是 DeepSeek 开源的 Agent 框架,底层基于Cordis插件系统。它的设计哲学只有一句话:Everything is a Plugin。

框架本身只提供"组装"能力,模型接入、工具调用、会话管理、沙箱、存储、调度、甚至 Web UI 本身,全都是插件。这意味着:

  • 可插拔:要什么功能装什么插件,不想要就卸

  • 可替换:同一能力多个实现,换插件即可

  • 可学习:官方功能也是插件,源码就是最好的教材


二、环境准备

2.1 环境要求

依赖
版本要求
Node.js
22.19+ 或 24+(版本不对会报各种玄学错误)
包管理器
pnpm(别用 npm,速度差一个数量级)
API Key
DeepSeek API Key(sk-xxx)

2.2 从源码启动

# 克隆仓库git clone https://github.com/deepseek-ai/deepseek-harness.gitcd deepseek-harness# 安装依赖pnpm install# 配置 API Keyecho ”DEEPSEEK_API_KEY=sk-your-key” > .env# 启动 Web UI 验证环境pnpm dsh web

浏览器打开http://127.0.0.1:3080,能看到界面就说明环境 OK。

也可以用 npx @deepseek-ai/dsh web 一键启动,无需克隆源码。


三、插件核心概念

一个插件本质上就是一个导出了apply函数的 TypeScript 模块:

import type { Context } from '@deepseek-ai/cordis'export const name = 'my-plugin'export function apply(ctx: Context) {  // 通过 ctx 注册能力}

三个关键要素:

要素
作用
name
插件唯一标识
apply(ctx, config)
框架加载时自动调用,ctx 是上下文对象
inject
声明依赖的服务(如 ['tools']),框架会等依赖就绪再加载

自动清理:通过 ctx 注册的事件监听、工具、定时器,插件卸载时全部自动清理,无需手动销毁。


四、第一步:Hello World 最小插件

4.1 创建插件文件

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

mkdir -p scratch-plugin/src

创建 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] 插件加载成功!')}

4.2 注册到 cordis.yml

创建 scratch-plugin/cordis.yml(路径必须是绝对路径):

- insert:    - id: hello      name: '/你的绝对路径/deepseek-harness/scratch-plugin/src/my-plugin.ts'

4.3 启动验证

pnpm dsh web --patch ./scratch-plugin/cordis.yml

终端打印 [hello-plugin] 插件加载成功! 就说明跑通了。


五、第二步:开发可被模型调用的 Tool

这是最常见的插件类型——让 AI 在对话中自动调用你的工具。

5.1 完整代码

import type { Context } from '@deepseek-ai/cordis'import { defineTool } from '@deepseek-ai/dsh-tools'export const name = 'greet-tool'export const inject = ['tools']  // 声明依赖 tools 服务export functionapply(ctx: Context) {  ctx.tools.register(defineTool({    name: 'greet',    description: '根据名字向人问好。',    parameters: {      name: {        type: 'string',        required: true,        description: '要问候的名字'      },    },    output: {      schema: { type: 'string' },      render: (_args, value) => [{ type: 'text', text: value }],    },    async execute(args) {      return `Hello, ${args.name}!`    },  }))}

5.2 字段详解

字段
说明
name
工具名,只能用字母/数字/下划线/横杠
description
模型靠它判断要不要调用,务必写清楚
parameters
参数 JSON Schema,框架自动做类型校验
output.render
把执行结果转成模型能理解的消息格式
execute
真正的业务逻辑,写你想干的事

5.3 验证

启动后在 Web UI 输入:"用 greet 工具向 Ada 问好",模型会自动调用工具并返回 Hello, Ada!。

你写的工具和官方原生工具、MCP 桥接工具走完全相同的执行管道——权限校验、执行审批、超时取消、日志记录全由框架处理,你只写业务逻辑。


六、第三步:插件配置与热更新

6.1 用 Schema 定义配置

import type { Context } from '@deepseek-ai/cordis'import Schema from '@deepseek-ai/schemastery'import { defineTool } from '@deepseek-ai/dsh-tools'export const name = 'greet-tool'export const inject = ['tools']export interfaceConfig{  greeting: string  emoji: boolean}export const Config: Schema = Schema.object({  greeting: Schema.string().default('Hello'),  emoji: Schema.boolean().default(true),})export functionapply(ctx: Context, config: Config) {  ctx.tools.register(defineTool({    name: 'greet',    description: '根据名字向人问好。',    parameters: {      name: { type: 'string', required: true, description: '要问候的名字' },    },    output: {      schema: { type: 'string' },      render: (_args, value) => [{ type: 'text', text: value }],    },    async execute(args) {      const suffix = config.emoji ? ' 👋' : ''      return `${config.greeting}, ${args.name}!${suffix}`    },  }))}

6.2 在 cordis.yml 中传配置

- insert:    - id: hello      name: '/绝对路径/scratch-plugin/src/my-plugin.ts'      config:        greeting: 'Hey'        emoji: false

改完保存即生效,框架自动卸载旧插件、用新配置重新加载,无需重启。


七、第四步:用 ctx.effect 管理外部资源

连数据库、开长连接等需要手动清理的资源,用 ctx.effect:

export function apply(ctx: Context) {  let pool: ConnectionPool | undefined  ctx.effect(() => {    pool = createConnectionPool({ host: 'localhost', port: 5432 })    // 返回的函数在插件卸载/配置变更/应用关闭时自动执行    return () => {      pool?.close()      pool = undefined    }  })  // 注册工具...}

八、第五步:打包成可安装 Bundle

开发时挂源码没问题,分享给别人就得打包。

8.1 Bundle 目录结构

hello-plugin/├── package.json# 声明这是 dsh 插件包├── cordis.patch.yml# 配置补丁└── index.js# 插件入口(编译后的 JS)

8.2 package.json

{  ”name”: ”dsh-hello-plugin”,  ”version”: ”0.1.0”,  ”type”: ”module”,  ”main”: ”index.js”,  ”files”: [”index.js”, ”cordis.patch.yml”],  ”dsh”: {    ”bundle”: { ”patch”: ”./cordis.patch.yml” }  }}

8.3 cordis.patch.yml

- insert:    - id: hello      name: dsh-hello-plugin

8.4 安装验证

# 安装到本地 profiledsh plugin --profile demo add ./hello-plugin# 查看最终配置树(调试神器)dsh --profile demo --dump-config# 启动dsh --profile demo

配置加载顺序:bundle 列表 → profile 补丁 → 全局配置 → 命令行 --patch,后面的覆盖前面的。


九、第六步:发布到 npm

# 登录官方源(别用镜像源)npm login --registry=https://registry.npmjs.org/# 发布npm publish --registry=https://registry.npmjs.org/

发布后任何人都能一条命令安装:

dsh plugin --profile web add dsh-hello-plugin

发布前建议:

  • 在 package.json 配 prepack 脚本做健康检查

  • 收窄 files 字段,只发运行时必需文件

  • 语义化版本号


十、插件的三种写法

函数形式(最常用)

export const name = 'my-plugin'export const inject = ['tools']export function apply(ctx: Context) { /* ... */ }

对象形式

export default {  name: 'my-plugin',  inject: ['tools'],  apply(ctx: Context) { /* ... */ },}

类形式(提供服务给其他插件时用)

import { Service, type Context } from '@deepseek-ai/cordis'export default class MyService extends Service {  static inject = ['tools']  constructor(ctx: Context) {    super(ctx, 'myService')  }}

十一、进阶能力

11.1 事件系统

插件间松耦合通信,三种事件类型:

类型
用途
emit
广播通知,不关心返回值
serial
按顺序执行监听器
waterfall
可拦截、传参(如工具执行前权限校验)
// 工具执行后打日志ctx.on('tools/post-execute', ({ tool, result }) => {  console.log(`工具 ${tool} 执行完成`)})// 工具执行前拦截(waterfall)ctx.on('tools/pre-execute', async (session) => {  if (!checkPermission(session)) {    throw new Error('无权限')  }})

11.2 服务隔离

同一服务可以有多个实例,不同插件组互不影响。比如两个 Agent 各用各的 shell 实例,超时设置不同。

11.3 自定义 Web UI

插件可以往 dsh 界面注入 UI 组件(桌面宠物、侧边栏、浮窗等)。界面是"槽位 + 注入"架构,找到合适的槽位(如 shell.overlay 浮动层),在浏览器半侧渲染即可。


十二、常见坑点与调试技巧

问题
解决方案
插件加载不上
dsh --dump-config
 看插件有没有进配置树
改了代码不生效
pnpm 的 file: 依赖是复制不是链接,需 remove 再 add
路径找不到
cordis.yml 里插件路径必须是绝对路径
模型不调用工具
检查 description 是否写清楚了调用时机
想知道有哪些服务
在 apply 里 console.log(Object.keys(ctx.root))
Node 版本报错
确认 22.19+ 或 24+,别用低版本

十三、学习资源

  • 官方仓库:github.com/deepseek-ai/deepseek-harness

  • 官网:deepseek.com/harness

  • 官方插件开发文档:仓库 docs/user/develop/ 目录

  • 社区插件集合:搜 GitHub Topic dsh-plugin

  • 遇到不懂的实现:直接读官方插件源码,它们就是最好的参考


    总结开发流程:环境准备 → Hello World 跑通链路 → 注册 Tool 让 AI 动手 → 加配置支持热更 → ctx.effect 管资源 → 打包 Bundle → 发布 npm。核心就一句话:写一个apply(ctx) 函数,通过ctx 注册能力,剩下的框架全包了。

相关学习资料