00 · 开始之前
开始之前
官方教程假设你已经可以从源码运行 DeepSeek Harness。请在仓库根目录操作,确保命令和 Patch 路径与示例一致。
- 已检出 deepseek-ai/deepseek-harness 源码
- 已使用仓库指定的包管理器安装依赖
- 终端当前位于仓库根目录
- Node.js 与 pnpm 版本符合当前检出版本要求
DeepSeek Harness 及插件协议仍处于开发者预览阶段,请固定开发使用的 revision。
步骤 1
创建本地插件项目
在 Harness 仓库内创建临时项目。第一个实验保持本地化,加载路径更明确,也更容易完整移除。
mkdir -p scratch-plugin/src步骤 2
编写插件模块
Harness 插件是导出 apply 函数的 TypeScript 模块。框架使用 Cordis Context 调用 apply,你可以通过这个上下文注册能力。
创建 scratch-plugin/src/my-plugin.ts。示例中的日志将作为插件成功加载的可观察信号。
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
// Required dependencies are ready before apply runs.
console.log('[hello-plugin] plugin loaded!')
}步骤 3
注册到 cordis.yml
先在仓库根目录执行 pwd,再创建 scratch-plugin/cordis.yml 作为 Web 配置覆盖层。请把示例路径替换为 pwd 输出的绝对路径。
- insert:
- id: hello
name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'步骤 4
使用覆盖层启动 Web UI
在仓库根目录使用 Patch 文件启动 Web UI,然后访问 http://127.0.0.1:3080。
pnpm dsh web --patch ./scratch-plugin/cordis.yml05 · Cordis
生命周期与服务依赖
Cordis 会把注册内容限定在插件上下文内。在插件持有定时器、连接、工具或共享能力前,应先理解下面两个机制。
使用 ctx.effect() 清理副作用
通过 Context 注册的内容会随插件卸载而移除。对于定时器、网络连接等需要显式释放的资源,应从 ctx.effect() 返回清理函数。
import type { Context } from '@deepseek-ai/cordis'
export function apply(ctx: Context) {
ctx.effect(() => {
const timer = setInterval(() => {
console.log('heartbeat')
}, 5000)
// Runs automatically when the plugin unloads.
return () => clearInterval(timer)
})
}使用 inject 声明服务依赖
如果插件依赖 tools、llm 或其他服务,请在 inject 中声明。框架会等待这些服务就绪后再调用 apply。
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-tool-plugin'
export const inject = ['tools']
export function apply(ctx: Context) {
// ctx.tools is ready here.
ctx.tools.register(/* ... */)
}06 · API
选择最简单的插件形态
Cordis 支持函数、对象和类三种形态。优先使用函数;只有插件需要向其他插件提供服务时,再考虑 Service 类。
函数形式
适合能力单一的插件,易于阅读、测试和卸载。
对象形式
适合把 name、inject、apply 和相关元数据组织在一起。
Service 类
适合对外提供具名 Cordis 服务并管理服务生命周期。
对象形式
export default {
name: 'my-plugin',
inject: ['tools'],
apply(ctx: Context) {
// Register capabilities here.
},
}Service 类
import { Service, type Context } from '@deepseek-ai/cordis'
export default class MyService extends Service {
static inject = ['tools']
constructor(ctx: Context) {
super(ctx, 'myService')
// Perform synchronous initialization here.
}
}07 · Verify
验证清单
进程启动并不等于开发完成,还要检查加载路径、生命周期和移除行为。
- Web UI 可以在 127.0.0.1:3080 打开。
- 终端只输出一次 hello-plugin 加载日志。
- 将绝对路径改为无效文件时,会得到可理解的加载错误。
- 停止或卸载插件后,定时器等副作用被正确清理。
- 移除 Patch 后,Web Profile 恢复原始行为。
常见问题
无法解析模块+
确认 cordis.yml 中是绝对路径、指向 .ts 文件,并且属于当前源码检出。
没有加载日志+
确认命令在仓库根目录运行,且 --patch 指向 ./scratch-plugin/cordis.yml。
服务为 undefined+
将服务名加入 inject,并只在 apply 被调用后访问。
3080 端口不可用+
停止占用该端口的进程,或按照当前上游 Web UI 参数调整。