
准备源码环境。开发 TypeScript 插件需要进入 Harness 源码仓库,不能只用 npx。执行 git clone、corepack enable、pnpm install、pnpm run build。注意 Node.js 版本要求 ^22.19.0 || >=24.0.0,建议直接用 Node 24。pnpm run build 不能省,否则 Web 页面缺少构建产物。
创建插件文件。在仓库根目录建 scratch-plugin/src/,新建 greet-tool.ts。插件只有四个部分:name(插件名)、inject(声明依赖 tools 服务)、apply(ctx)(加载入口)、ctx.tools.register()(注册工具)。parameters 告诉模型传什么参数,execute 真正执行代码,output 约定结果格式。
写 cordis.yml 配置。新建 scratch-plugin/cordis.yml,用 insert 把插件挂进配置树。name 字段必须填插件文件的绝对路径(用 pwd 确认)。插件最好放在 Harness 源码仓库内,否则可能出现 Cannot find module 错误。
启动并检查。执行 pnpm dsh web --patch ./scratch-plugin/cordis.yml。看到 [greet-tool] loaded 和 dsh web: http://127.0.0.1:3080 两行就说明成功了。进入"设置→插件→插件列表",搜索 greet-tool,状态应为"已启用"。
让 Agent 调用它。选择工作区,新建标准模式会话,输入"请调用 greet 工具问候 Datawhale"。展开工具调用,可以看到输入 {"name":"Datawhale"} 和输出"你好,Datawhale!你的第一个 Harness 插件已经运行。"至此最小闭环跑通。
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 `你好,${args.name}!你的第一个 Harness 插件已经运行。`
},
}))
console.log('[greet-tool] loaded; tool name: greet')
}
# scratch-plugin/cordis.yml(把路径换成你自己的绝对路径)
- insert:
- id: greet-tool
name: '/Users/yourname/deepseek-harness/scratch-plugin/src/greet-tool.ts'
# 启动(带补丁)
pnpm dsh web --patch ./scratch-plugin/cordis.yml
# 端口被占用时换端口
pnpm dsh web --patch ./scratch-plugin/cordis.yml --port 3082
安装插件:dsh plugin --profile web add @dsh-external/dsh-vision-toolkit。安装后重启 Web 服务(插件在启动时加载,只刷新页面不够)。
配置凭据:很多插件需要 API Key,用 dsh credentials set KEY_NAME 写入凭据系统,然后在设置页面配置对应引用。
加载 Skill 并调用:插件通常附带 Skill,在会话中用 /skill-name 加载,然后直接描述任务,Agent 会按需调用插件暴露的工具。