这次我们来看一个很实操的话题:从零手写一个正式的 DeepSeek Harness 插件,跑通“写代码 -> 构建文件 -> 装进插件目录 -> 发布到 GitHub”的完整闭环。DeepSeek Harness(下文简称 DSH)是一款面向大模型任务编排的桌面端工具,很多人在里面管理提示词、配置模型、跑批处理任务,但内置能力终究是有限的。想给 DSH 加上自定义命令、外部 API 调用或者专属工作流,最直接的方式就是写一个插件。
这篇文章不打算讲虚的。我会从项目初始化开始,带你把插件清单、入口代码、构建产物、本地安装、调试验证全部走一遍,最后把插件以开源项目的形式发布到 GitHub。这套流程走完,你的插件就已经具备被 DSH 插件市场收录的雏形。需要提前说明的是,DSH 不同版本的插件 API 可能有差异,文中的字段名和函数名是通用插件设计范式,实际落地时请以你安装版本的官方文档为准。
如果你已经在用 DSH,但觉得它不够“顺手”;或者你正想给团队内部工具链做一个能统一调用大模型能力的插件,这篇文章可以直接收藏。
1. DeepSeek Harness 插件核心能力速览
| 能力项 | 说明 |
|---|---|
| 插件形态 | 一个标准 Node.js 项目,提供插件清单和入口文件,DSH 启动时扫描并加载 |
| 开发语言 | JavaScript / TypeScript 均可,推荐 TypeScript 便于维护 |
| 运行环境 | Node.js 18+,包管理器建议使用 pnpm |
| 插件目录 | 通常位于用户配置目录下的plugins子目录,例如~/.deepseek-harness/plugins,具体路径以官方文档为准 |
| 主要功能 | 注册自定义命令、调用外部 API、封装本地模型调用、扩展工作流节点、监听任务事件 |
| 发布方式 | GitHub 仓库 + Release 产物,后续可提交到 DSH 插件市场 |
| 适合场景 | 本地工具链集成、团队内部技能沉淀、API 能力封装、批量任务编排 |
DSH 插件本质上是一个“被 DSH 宿主环境托管的小型 Node.js 模块”。它不需要独立启动服务,而是由 DSH 在进程内加载,通过注册函数把能力暴露给用户。这个模型和 VS Code 插件、JetBrains 插件的思路是类似的,只不过 DSH 的职责更聚焦在大模型工作流上。
2. 适用场景与使用边界
先想清楚你要用插件解决什么问题,再动手写代码。
DSH 插件适合做这些事情:
- 给 DSH 加自定义命令,把重复操作收敛成一条指令。
- 封装 DeepSeek API 或其他模型 API,让不熟悉接口的人也能直接调用。
- 结合 Harness 的任务编排能力,做批量文本处理、批量翻译、批量摘要。
- 把团队内部的提示词模板、工具调用封装成插件,统一对外提供服务。
同样,DSH 插件有些事不适合做:
- 不适合在插件里做重型数据处理,DSH 的定位是编排和调度,不是数据清洗引擎。
- 不适合绕过 DSH 的鉴权机制去直接读取宿主敏感配置。
- 不适合把插件做成后台常驻服务,插件生命周期应该由 DSH 管理。
合规边界是必须提前说清楚的。插件如果调用大模型接口,API Key 一定不能硬编码在源码里,必须通过环境变量或配置项注入,并且不要把.env文件提交到 GitHub。插件在处理文本、图片、音频时,要考虑数据隐私,不能把用户未经授权的数据上送到公开服务。涉及人脸、声音、版权素材的,必须先确认授权。发布到 GitHub 时,选一个明确的 LICENSE,不要默认“代码公开了就是随便用”。
3. 环境准备与前置条件
在写代码之前,先把环境检查一遍。下面这份清单是通用要求,具体版本以你本机为准。
| 检查项 | 要求 | 验证命令 |
|---|---|---|
| Node.js | 18 或更高版本 | node -v |
| 包管理器 | pnpm 8 或更高版本 | pnpm -v |
| TypeScript | 5.x,编译用 | npx tsc -v |
| Git | 最新稳定版 | git --version |
| DSH 桌面端 | 已安装,能正常启动 | 从应用界面查看版本号 |
如果node -v报错,说明 Node.js 没安装或者没加入 PATH,先去官网安装 LTS 版本。pnpm 的安装方式比较简单:
npm install -g pnpmDSH 插件目录的位置非常关键。不同操作系统的路径不太一样,我先给一个常见约定,你可以在 DSH 设置页或者官方文档里确认本机路径:
# Windows 通常是 C:\Users\<你的用户名>\.deepseek-harness\plugins # macOS / Linux 通常是 ~/.deepseek-harness/plugins这个目录就是插件的“安装目的地”。DSH 在启动时扫描该目录,读取每个子目录里的插件清单,然后把插件加载到进程中。
另外,需要确认 DSH 是否提供了 CLI 工具,比如dsh命令。如果提供,可以在终端快速执行dsh --version,后续调试会更方便。不提供也没关系,我们后面主要通过界面日志来排查问题。
4. 初始化插件项目
先创建一个项目目录,并初始化package.json。
mkdir dsh-plugin-demo cd dsh-plugin-demo pnpm initpnpm init会交互式生成package.json。这里给一份更完整的示例,你直接替换掉生成的文件内容即可:
{ "name": "dsh-plugin-demo", "version": "0.1.0", "description": "A demo plugin for DeepSeek Harness", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "tsc", "dev": "tsc --watch", "clean": "rm -rf dist" }, "keywords": [ "deepseek-harness", "dsh-plugin" ], "license": "MIT", "devDependencies": { "typescript": "^5.4.0" } }这里的核心字段是main,它指向构建产物的入口文件。DSH 加载插件时,会先看插件清单文件,再根据main字段找到真正的执行代码。
接着创建 TypeScript 配置文件tsconfig.json:
{ "compilerOptions": { "target": "ES2022", "module": "CommonJS", "moduleResolution": "Node", "outDir": "dist", "rootDir": "src", "declaration": true, "strict": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src"] }这里采用 CommonJS 模块规范,因为 Node.js 环境下 CommonJS 兼容性最好,DSH 作为宿主进程加载插件时不容易踩模块规范冲突的坑。
如果 DSH 官方提供了插件类型声明包,例如@deepseek-harness/plugin-types,可以安装它以获得代码提示:
pnpm add -D @deepseek-harness/plugin-types没有找到类型包也没关系,暂时用any声明上下文对象,跑通流程后再根据官方文档补类型。
5. 编写插件清单文件
插件清单是 DSH 识别插件的关键文件。它告诉宿主:插件叫什么、入口在哪、激活时机是什么、提供了哪些命令。下面用一个通用示例说明结构,字段名以你本机 DSH 版本为准。
创建plugin.json:
{ "name": "dsh-plugin-demo", "displayName": "DSH Demo Plugin", "version": "0.1.0", "description": "A demo plugin for DeepSeek Harness", "main": "dist/index.js", "activationEvents": [ "onCommand:dsh-demo.sayHello" ], "commands": [ { "command": "dsh-demo.sayHello", "title": "Say Hello" } ] }字段说明:
name:插件的唯一名称,建议用dsh-plugin-前缀,避免和其他插件冲突。displayName:插件市场中显示的名称,可以更友好。main:入口文件,和package.json里的main保持一致。activationEvents:激活事件列表。DSH 不需要在启动时立即加载所有插件,而是等到某个命令被触发时才激活,这样启动更快,资源占用更低。commands:插件对外暴露的命令列表。用户可以在 DSH 命令面板或界面上看到这些命令。
这段配置解决的就是“插件如何被发现”的问题。没有清单文件,DSH 无法知道这个目录是普通文件夹还是插件。
6. 实现插件核心逻辑
创建src目录,写入口文件:
mkdir src touch src/index.ts先实现一个最简单的命令注册逻辑:
export function activate(ctx: any) { ctx.registerCommand("dsh-demo.sayHello", async (params: any) => { const name = params?.name ?? "DeepSeek Harness"; return { message: `Hello, ${name}!` }; }); } export function deactivate() { // 释放资源 console.log("dsh-plugin-demo deactivated"); }这里的关键函数是activate和deactivate。activate在插件被激活时调用,ctx是 DSH 注入的上下文对象,里面提供了registerCommand这样的注册 API。deactivate在插件被卸载或 DSH 退出时调用,适合清理定时器、关闭连接。
ctx.registerCommand是通用插件设计范式,如果你的 DSH 版本里叫registerAction或者别的名字,替换一下即可,整体思路不变。
接下来,我们再写一个稍微“正式”一点的插件命令,让插件真正调用 DeepSeek API。这里给出通用请求示例,接口地址和模型名以 DeepSeek 开放平台文档为准:
export function activate(ctx: any) { ctx.registerCommand("dsh-demo.translate", async (params: any) => { const apiKey = process.env.DEEPSEEK_API_KEY; if (!apiKey) { throw new Error("DEEPSEEK_API_KEY is not set"); } const response = await fetch("https://api.deepseek.com/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` }, body: JSON.stringify({ model: "deepseek-chat", messages: [ { role: "system", content: "You are a translation engine. Translate the user input to English." }, { role: "user", content: params.text } ] }) }); if (!response.ok) { throw new Error(`API request failed: ${response.status}`); } const data = await response.json(); return data.choices?.[0]?.message?.content ?? ""; }); }这段代码演示了三个关键点:
- 通过
process.env读取环境变量,而不是把 API Key 写死在代码里。 - 使用 Node.js 18+ 内置的
fetch,不需要额外安装请求库。 - 命令函数可以是异步的,返回结果会交给 DSH 界面展示。
在开发阶段,可以通过.env文件配置环境变量,但.env必须放进.gitignore,绝对不能提交到 GitHub。
7. 构建插件并安装到插件目录
代码写好后,先编译成可发布的文件,再把文件“落”到 DSH 插件目录。这一步就是标题里说的“落成文件、装进插件目录”。
先安装依赖并构建:
pnpm install pnpm build构建完成后,dist目录下会出现index.js。检查一下产物是否存在:
ls dist然后把插件文件复制到 DSH 插件目录。以 macOS / Linux 为例:
mkdir -p ~/.deepseek-harness/plugins/dsh-plugin-demo cp -r dist package.json plugin.json ~/.deepseek-harness/plugins/dsh-plugin-demo/Windows PowerShell 下可以这样:
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.deepseek-harness\plugins\dsh-plugin-demo" Copy-Item -Recurse dist, package.json, plugin.json "$env:USERPROFILE\.deepseek-harness\plugins\dsh-plugin-demo\"复制完成后,重启 DSH。启动后打开插件管理面板,正常情况下dsh-plugin-demo会出现在插件列表里,状态为“已加载”或“已启用”。
这里有一个常见误区:很多人只复制了dist,漏掉了plugin.json,结果 DSH 找不到插件清单,加载失败。所以复制时要确保plugin.json和package.json都在插件目录下。
如果 DSH 界面看不到插件列表,可以检查插件目录的目录名是否和plugin.json里的name一致,部分版本的 DSH 会要求目录名等于插件名。
8. 功能测试与效果验证
插件装好后,按下面这张表逐项验证。
| 测试项 | 输入 | 预期结果 | 通过标准 |
|---|---|---|---|
| 插件加载 | 在 DSH 插件管理界面查看列表 | 插件名称和版本号正常显示 | 没有加载失败提示 |
| 命令调用 | 执行dsh-demo.sayHello | 返回Hello, DeepSeek Harness! | 命令面板能看到输出 |
| 参数传递 | 执行dsh-demo.sayHello,传入{ "name": "CSDN" } | 返回Hello, CSDN! | 参数能被正确解析 |
| 环境变量缺失 | 不设置 API Key,执行dsh-demo.translate | 抛出明确错误信息 | 提示DEEPSEEK_API_KEY is not set |
| API 调用 | 设置 API Key,执行dsh-demo.translate,文本传一段中文 | 返回英文翻译结果 | 接口连通,结果正确 |
执行命令的方式取决于 DSH 的交互设计。如果 DSH 有命令面板,直接搜索命令名;如果插件命令可以绑定到界面按钮,也可以从界面上触发。
测试时如果命令一直不出现,优先检查activationEvents。很多插件系统要求命令必须先在事件列表里声明,才能被触发。示例里的onCommand:dsh-demo.sayHello就承担这个职责。
9. 日志与问题排查
插件运行中出现问题,先看日志。DSH 通常会把日志写到用户配置目录下的logs文件夹:
# macOS / Linux tail -f ~/.deepseek-harness/logs/dsh.log # Windows PowerShell Get-Content -Path "$env:USERPROFILE\.deepseek-harness\logs\dsh.log" -Tail 50 -Wait在插件代码里,可以用console.log输出运行时信息,DSH 的日志面板一般会捕获stdout。如果你的 DSH 版本不显示console.log,可以改成往日志文件追加写入:
import fs from "fs"; import path from "path"; function log(message: string) { const logPath = path.join(process.env.DSH_LOG_DIR ?? ".", "dsh-plugin-demo.log"); fs.appendFileSync(logPath, `${new Date().toISOString()} ${message}\n`); }调试时保持简单:先确认插件有没有被加载,再确认命令有没有被注册,最后才查网络请求和数据处理逻辑。不要一上来就怀疑 DSH 本身有问题。
10. 发布到 GitHub
插件在本地验证通过后,就可以正式归档并发布到 GitHub。发布不等于简单传一下代码,一个正式的插件项目至少包含三样东西:完整的代码仓库、清晰的 README、明确的 LICENSE。
先在项目根目录创建.gitignore:
node_modules/ dist/ .env *.log然后初始化 Git 仓库并提交代码:
git init git add . git commit -m "feat: init dsh plugin demo" git branch -M main git remote add origin https://github.com/<your-name>/dsh-plugin-demo.git git push -u origin main推送代码后,打一个版本标签,创建 Release:
git tag v0.1.0 git push origin v0.1.0在 GitHub 仓库页面的 Releases 区域创建一个新 Release,关联到v0.1.0标签,然后把构建产物dist打包上传。为了便于用户直接下载安装,可以在 Release 里附带dsh-plugin-demo.zip,里面包含dist、plugin.json、package.json、README.md。
README 是容易被忽略但极其重要的部分。一份合格的插件 README 至少包含:
- 插件是干什么的。
- 环境要求:Node.js 版本、DSH 版本。
- 安装方式:手动复制到插件目录,或通过 DSH 插件市场安装。
- 使用方式:命令名称、参数说明、示例。
- 配置项:需要设置哪些环境变量。
- LICENSE 声明。
例如:
# dsh-plugin-demo A demo plugin for DeepSeek Harness. ## Features - `dsh-demo.sayHello`: Say hello to DeepSeek Harness. - `dsh-demo.translate`: Translate text using DeepSeek API. ## Install Copy `dist`, `package.json`, `plugin.json` to your DSH plugins directory. ## Usage Set environment variable `DEEPSEEK_API_KEY`, then run command `dsh-demo.translate`.如果 DSH 插件市场支持通过 GitHub 仓库收录插件,按官方指引提交仓库地址即可。如果暂时不支持,GitHub Release 本身就是最直接的分发路径,用户下载压缩包后手动安装。
11. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 插件没有出现在 DSH 插件列表 | 插件目录位置不对 | 检查 DSH 配置里的插件路径 | 把插件目录复制到正确位置 |
| 插件列表有名称,但命令无法触发 | plugin.json里activationEvents缺失 | 检查命令事件是否声明 | 补上onCommand:<命令名> |
| 命令触发后提示找不到入口 | main字段路径错误 | 检查dist/index.js是否存在 | 重新执行pnpm build |
| 构建报 TS 类型错误 | 类型声明缺失 | 查看报错信息 | 先注释或改为any,后续补类型 |
| API 调用超时 | 网络环境不通或接口地址错误 | 用 curl 单独测试接口连通性 | 确认网络和接口地址 |
| API 返回 401 | API Key 无效或未配置 | 检查环境变量是否传入 DSH 进程 | 在 DSH 启动前设置环境变量 |
| 修改代码后不生效 | 插件未重载 | 重启 DSH | 确认构建成功后再复制文件 |
| 插件加载时进程崩溃 | 入口文件抛错 | 查看 DSH 日志 | 定位activate里的异常逻辑 |
这里单独说一下 API Key 的传递问题。如果你在终端启动 DSH,process.env会继承终端的变量;如果是双击应用图标启动,环境变量可能不会自动继承,这时候需要在 DSH 的设置界面里配置环境变量,或者使用官方文档推荐的方式注入。
12. 最佳实践与合规提醒
插件做得越久,越应该注意工程化细节。下面这几条是我建议你在发布插件前检查的:
使用dsh-plugin-命名前缀,避免与 npm 包名冲突。插件发布到 GitHub 后,如果后续上架 DSH 插件市场,好的命名习惯能减少很多麻烦。构建产物和源码分离管理,dist目录可以提交到仓库,方便用户直接下载使用,但不建议把node_modules提交进去。插件要提供最小测试用例,至少在 README 里写清楚输入输出,让别人能快速验证。如果插件支持批量任务,要在代码里做好失败重试和日志记录,避免批处理中途卡死。
合规方面再强调一次:不在代码中硬编码密钥,不把.env提交到仓库,不采集用户数据,不处理未授权的图片、音频、视频素材。插件调用第三方 API 时,要遵守目标服务的条款,避免用批量接口做超出权限的事情。想发布到公开平台时,检查 LICENSE 兼容性,如果不确定就用 MIT 这种宽松协议。
13. 总结与下一步
这次我们走完了一个 DSH 插件的完整生命周期:初始化项目、写plugin.json清单、实现activate注册命令、构建产物、复制进插件目录、本地测试、发布 GitHub Release。
最值得先验证的是插件能不能被 DSH 正常加载。只有加载成功,后面的事件监听、API 调用、批量任务才有意义。最容易踩的坑是插件目录路径错误和main字段指向不存在的文件,这两个问题排查起来并不复杂,但比较耽误时间。
下一步建议你去看安装版本对应的 DSH 官方插件开发文档,把命令注册、上下文对象、事件监听这些 API 替换成真实字段。如果官方提供了示例仓库,直接 clone 下来对照修改,比对着这篇文章硬套更准确。跑通一个最小插件之后,再去扩展你真正需要的能力,效率会高很多。
这篇教程覆盖的是插件开发的基础链路,适合作为你入职 DSH 插件生态的起点。可以先收藏备用。