DeepSeek Harness 插件开发实战:从设计理念到 npm 发布
📝 本文首发于 栏轩·阁
欢迎访问阅读原文,获取更好的阅读体验。
引言:为什么插件是 dsh 的灵魂
上一篇文章介绍了 DeepSeek Harness 的安装与上手。如果说 dsh 是一台可组装的机器,那么插件就是它的每一个零件——界面、模型接入、工具调用,乃至官方 UI 本身,全都是插件。
这篇文章将带你完整走一遍插件开发的实战路径:从理解设计理念和架构组成,到安装别人的插件、自己动手写两个 demo,最后发布到 npm 让全世界都能安装。
本文是实战向教程,代码会尽量精简,重点讲清"为什么这么做"以及我踩过的坑。
一、设计理念:一切皆插件
dsh 的整个架构建立在一条简单的信念上:
Everything is a Plugin(一切皆插件)。
这意味着框架本身只提供"组装"能力(由 Cordis 驱动),具体功能全部由插件以模块化的方式提供。对开发者来说,这个理念带来三个直接好处:
- 可插拔:想要什么功能,装一个插件;不想要了,卸掉即可
- 可替换:同一个能力有多个实现?换一个插件就行,互不干扰
- 可学习:官方功能也是插件实现的——源码就摆在仓库里,是最好的教材
理解这一点,是进入插件开发的第一把钥匙。
二、插件的架构组成
一个 dsh 插件本质上是一个 npm 包,通过 package.json 里的声明"激活"成插件。它由两大部分组成:
1. 声明(让 dsh 认识这个包)
在 package.json 中声明两件事:
dsh.bundle.patch:声明本包是 bundle,并指向cordis.patch.yml——安装后该 patch 会自动挂进配置层栈dsh.client:声明浏览器半侧的注入依赖与平台(web)
2. 两个半侧(插件实际运行的代码)
| 半侧 | 位置 | 职责 | 形态 |
|---|---|---|---|
| 宿主半侧(服务端) | lib/index.js |
注册路由、服务、权限等 | 标准 Cordis 插件:{ name, inject, apply(ctx, config) } |
| 浏览器半侧(前端) | lib/client.js |
渲染界面、交互逻辑 | window.__ModuleLoader__.load({ id, factory }) |
浏览器半侧有几个硬性规则,是新手最容易踩的坑:
- 不能自己打包 React:factory 接收同步
require,React 等运行时依赖必须从 DSH 外壳的平台模块表获取 - CSS 内联注入:以字符串形式插入
<style>标签,而不是引外部样式文件 - 插件 ID 唯一:
id必须与 package.json 声明一致
三、插件是什么:一个生活化的类比
如果还是觉得抽象,可以把插件想象成 App Store 里的应用:
- dsh 是操作系统,提供运行环境和接口
- 插件是应用,各自提供一项能力
dsh plugin命令就是应用商店/包管理器
装一个插件 = 往商店里加一个应用;写一个插件 = 开发一个新应用上架。
四、安装别人的插件
安装插件非常简单,本质上是 pnpm add 到 $DSH_HOME/profiles/web/node_modules:
# 安装
dsh plugin --profile web add <包名>
# 卸载
dsh plugin --profile web remove <包名>
# 更新
dsh plugin --profile web update
# 查看已安装
dsh plugin --profile web list
前置条件:需要
pnpm环境;--profile web指定安装到 Web profile。
实战踩坑提醒:如果你用本地路径(file:)安装自己正在开发的插件,要特别注意——pnpm 的 file: 依赖是复制而不是链接。也就是说,你改了源码,已安装的那份不会自动更新,必须 remove 再 add 一次(或重启服务),否则跑的还是旧代码。这个坑在开发期会反复遇到。
五、自己写插件:整体流程
自己写一个插件,大致分四步:
- 建包:初始化 npm 包,写好
package.json的声明(bundle patch + client) - 写宿主半侧:用 Cordis 三件套注册插件主体
- 写浏览器半侧(如果要界面或前端逻辑):按
__ModuleLoader__形态注册客户端 - 本地验证:
dsh plugin --profile web add .装上,重启看效果
从 hello world 开始
我的第一个插件是 dsh-hello——一个工具类插件:它注册了一个"打招呼"工具,你在聊天里和 AI 说"你好",AI 识别到这个意图后,就会自动调用插件提供的问候工具。
这个 demo 虽然简单,但它的意义不小:
- 验证整条链路是通的:声明能被 dsh 识别、安装后能挂进配置层栈、宿主半侧能正常激活、工具能被 AI 自动调用
- 跑通"AI 调用工具"的核心机制:模型判断意图 → 触发工具 → 拿到结果 → 继续对话,这整个闭环在 hello 里就完整走了一遍
- 工具描述怎么写,直接影响 AI 会不会正确调用:hello 阶段就开始体会"给模型写说明书"这件事
不要小看这一步。插件开发的绝大多数挫败感都来自"链路没通"——装上了但没生效、激活了但看不到、改了代码但跑的还是旧的。先用 hello world 把链路跑通,后面所有功能都是在这条已验证的链路上叠加。
而且 dsh-hello 就是下面 Demo 01(AI 可调用工具)的最初原型——工具类插件从 hello 一路演化成了更复杂的能力。
下面用两个 demo 展示最常见的两种插件能力。
六、Demo 01:AI 可以调用的工具
目标:让模型在对话时能自动调用插件提供的工具(类似其他 Agent 软件的 Skill)。
这正是 dsh-hello 走过的路——只是把"打招呼"换成真正的能力。
思路:插件向运行时注册一个工具——定义一个名字、一段描述(让模型知道何时用)、和一个执行函数。模型在对话中判断"这个任务需要调用工具"时,会自动触发它并拿到结果,继续推理。
关键点:
- 工具的描述要写清楚:模型靠它决定是否调用
- 执行函数要返回结构化结果:模型靠它继续推理
- 工具可以是任何能力:读文件、查网页、执行命令、访问你的私有 API……
这个 demo 的价值在于:它把"让 AI 干活"从对话扩展到了真实世界——模型不再是只聊天,而是能真正动手。
七、Demo 02:自定义 Web UI
目标:往 dsh 界面里注入自己的 UI 组件(比如一个桌面宠物、一个侧边栏、一个浮窗)。
思路:dsh 的界面是"槽位 + 注入"的架构。官方定义了一些插槽(如 shell.overlay 浮动层),插件可以把自己的组件注入到这些槽位里,与官方 UI 共存而不互相覆盖。
关键点:
- 找到合适的槽位(如浮动层、侧边栏、状态栏)
- 组件在浏览器半侧渲染,用 DSH 提供的 React
- 注意竞态与生命周期:界面组件经常异步加载,要做好防重入、防过期回调
我实战做的"桌面宠物"就是挂在浮动层上的自定义 UI:动画链式播放、屏幕漫游、点击/拖拽交互、窗口缩放跟随——整个就是一个通过槽位注入的独立应用。
八、发布插件:让全世界都能安装
开发完成后,发布到 npm 即可让任何人 dsh plugin --profile web add <包名> 安装。
1. 登录 npm(官方源)
npm login --registry=https://registry.npmjs.org/
注意用官方源,而不是镜像源。如果账号开了两步验证(2FA),登录/发布时可能需要 OTP 验证码,或使用 npm tokens 页面 创建的访问令牌。
2. 发布前自查
- 健康检查脚本:在
package.json里配置prepack,发布前自动校验必需文件、bundle 形态、包体积 - 收窄
files:只发布运行时需要的文件(代码 + 播放资源),文档/预览图等不需要进包 - 版本号:语义化版本,发新版记得
npm version patch/minor/major
3. 发布
npm publish --registry=https://registry.npmjs.org/
发布成功后,任何人都可以一条命令安装你的插件了。
九、总结
从"一切皆插件"的理念,到写出第一个能跑的插件、再到发布到 npm,这条路径比想象中顺滑:
- 理念:插件 = npm 包 + 声明,宿主半侧管能力、浏览器半侧管界面
- 安装:
dsh plugin一条命令 - 开发:hello world 跑通链路 → 工具 demo 让 AI 动手 → UI demo 让界面长出自己的样子
- 发布:npm login + publish,全球可装
插件开发最迷人的地方在于:官方功能也是插件。遇到任何不懂的实现,直接读官方插件源码就是最好的学习路径。
如果你也在写 dsh 插件,欢迎分享你的作品——记得在 GitHub 仓库打上 dsh-plugin 话题,让更多人发现它。🚀
更多推荐


所有评论(0)