ARTICLE · 997053
DeepSeek Harness 插件开发完整教程
一、核心理念:一切皆插件
DeepSeek Harness(简称 dsh)是 DeepSeek 开源的 Agent 框架,底层基于Cordis插件系统。它的设计哲学只有一句话:Everything is a Plugin。
框架本身只提供"组装"能力,模型接入、工具调用、会话管理、沙箱、存储、调度、甚至 Web UI 本身,全都是插件。这意味着:
可插拔:要什么功能装什么插件,不想要就卸
可替换:同一能力多个实现,换插件即可
可学习:官方功能也是插件,源码就是最好的教材
二、环境准备
2.1 环境要求
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: helloname: '/你的绝对路径/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 | |
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: stringemoji: 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: helloname: '/绝对路径/scratch-plugin/src/my-plugin.ts'config:greeting: 'Hey'emoji: false
改完保存即生效,框架自动卸载旧插件、用新配置重新加载,无需重启。
七、第四步:用 ctx.effect 管理外部资源
连数据库、开长连接等需要手动清理的资源,用 ctx.effect:
export function apply(ctx: Context) {let pool: ConnectionPool | undefinedctx.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: helloname: 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 | |
file: 依赖是复制不是链接,需 remove 再 add | |
description 是否写清楚了调用时机 | |
apply 里 console.log(Object.keys(ctx.root)) | |
十三、学习资源
官方仓库: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注册能力,剩下的框架全包了。