第 12 章 · 从零写一个插件
本篇目标:手写、加载、验证、发布一个真实插件。 原文 插件在 Harness 里就是一个导出
apply函数的 TypeScript 模块。
12.1 三种形态
原文 三种写法,按「需不需要提供元信息 / 提供服务」选:
| 形态 | 写法 | 适用场景 |
|---|---|---|
| 函数形式 | 导出独立 apply 函数 |
大多数插件,最简单直接 |
| 对象形式 | export default 一个带 name / inject / apply 的对象 |
需要同时声明元信息 |
| 类形式 | export default 一个 Service 子类 |
插件要向其他插件提供服务 |
// ① 函数形式:最小可用
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
console.log('[hello-plugin] plugin loaded!')
}
// ② 对象形式:带依赖声明与元信息
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') // 第一个参数 ctx,第二个参数是服务名
}
}
⚠️ 一个官方文档点名的坑
原文 官方事故复盘 0001:不要多写 export default。函数形式已经 export function apply,再补一个默认导出会造成加载歧义。三种形态各选其一,不要混。
类形式的核心是 super(ctx, '服务名')——这一句把服务注册进共享 context,其他插件才能通过 inject 声明依赖(第 11 章的 reactive coeffects)。
12.2 四条正规扩展路径
官方 文档站 develop/ 与 reference/cookbook/ 给出的路径,按你要加的东西选:
| 想加什么 | 文档页 | 注册的接缝 |
|---|---|---|
| 一个 Tool | /develop/basic/tool + /reference/cookbook/adding-a-tool |
ctx.tools(schema 自动进提示词组装) |
| 一个模型适配器 | /develop/practice/llm-adapter + cookbook/adding-an-llm-adapter |
ctx.llm |
| 一个设置页 / UI 卡片 | cookbook/adding-a-settings-card |
client slots / resources |
| 一个斜杠命令 | 架构表 Where new behavior goes |
ctx.commands(不经模型回合即可派发) |
| 一个 Package | cookbook/adding-a-package |
bundle / patch |
| 持久化插件 | /develop/practice/dynamic-cordis |
HMR + 配置协调 |
| 会话事件类型 | 扩展 SessionEventMap,从日志渲染与回放 |
ctx.sessions |
| 沙箱后端 | ctx.sandbox,消费者 spawn 前包装 argv |
— |
| 文件系统 provider | ctx.fs 或监听 fs/* |
— |
官方 docs/architecture.md 的 "Where new behavior goes" 是一张 20 行的完整映射表,写插件前先查这张表,别自己猜扩展点。
高频踩坑:
agent/pre-step、agent/request、llm/stream、tools/*是 waterfall,监听器必须调用next()委托;忘记next()会截断流水线,表现为「插件一加载,Agent 就什么都不做了」。agent/turn-stopping是串行事件且没有next()。
12.3 创造模式的正确工作流
原文 官方首页演示流程 + 实战四步:
描述需求 → 加载 cordis-plugin-development 技能 → 检查运行时找到可用界面层提供者
→ 编写插件 → 内存加载立即生效 → 你反馈 → 固化为预设
第一步永远是检查运行时:
先检查当前运行时有哪些插件在加载、提供了哪些服务,
告诉我哪些服务适合用来做侧边栏 UI 组件。
第二步把四件事写清楚(位置 / 功能 / 外观 / 约束):
帮我添加一个插件:
- 位置:右侧边栏(也可选左侧栏、底部)
- 功能:显示当前会话的 Token 消耗、工具调用次数、预估费用,
数据每 5 秒刷新一次
- 外观:深色卡片、圆角、体积小巧,不遮挡正文内容
- 约束:不要引入额外依赖;数据读取走会话事件日志,不要自己另开连接
后两条约束是专业与业余的分界:不引依赖控制供应链风险,走现有事件流避免制造第二个真相来源(第 03 章)。
第三步:描述现象,别下结论。「点击没反应」✅ /「你写错了」❌。第 07 章的 exact symptom 纪律在这里同样适用。
第四步:让 AI 参照现有视觉风格(官网背景/字体、macOS 窗口按钮等),避免风格漂移。
12.4 打包、安装与发布
官方 文档路径 /develop/basic/config(插件配置)与 /develop/basic/publish(打包与安装);用户侧入口 /guide/plugin-market(插件市场)。社区发现机制 官方 README:
Add the
dsh-plugintopic to your plugin repository for discoverability.
发布前 checklist:
| # | 检查 | 依据 |
|---|---|---|
| 1 | 通读自己生成的每一行代码 | 官方 SAFETY.md:插件即代码,权限可能很大 |
| 2 | 所有进程内注册走 ctx.effect() |
卸载后不留孤儿(第 11 章) |
| 3 | 所有外部副作用列出并设计审批 | 不可逆动作不能靠卸载回滚 |
| 4 | 声明 inject 依赖,不隐式假设服务存在 |
reactive coeffects |
| 5 | 在隔离工作区跑一次安装 → 加载 → 卸载 → 再加载 | 验证时间可组合性 |
| 6 | 固定 DSH 版本并在 README 标明 | 预览版有 breaking change |
| 7 | 不引额外依赖,或锁定依赖版本 | 供应链 |
| 8 | 给仓库打 dsh-plugin topic |
可发现性 |
原文 安全实话(六条,浓缩):插件就是代码 / 实验环境隔离 / 确认弹窗逐条看清 / 日志可追溯 / 预览版变动快要锁版本 / Harness 免费但模型调用按量计费,迭代轮数要控。再补一条作者自己的经验:动态插件虽然运行在沙箱里,但沙箱不是安全边界——与 官方 SAFETY.md 完全一致。
12.5 本章产出与验收
核心产出:一个发布到 GitHub、带 dsh-plugin topic 的插件仓库,含 README、副作用清单、安装/卸载验证记录。
验收点:
- 能说出三种形态各自的适用场景,并解释「不要多写
export default」 - 能用
Where new behavior goes表定位任意一个扩展需求 - 能解释 waterfall 监听器漏写
next()的表现 - 插件安装 → 加载 → 卸载 → 再加载后,工具注册表无重复项
- 陌生人按 README 能独立装上使用
延伸阅读
| 来源 | URL | 等级 |
|---|---|---|
| 官方文档 · 第一个 Harness 插件 | https://deepseek-harness.github.io/deepseek-harness/develop/basic/ | 官方 |
| 官方文档 · 开发一个 Tool / 插件配置 / 打包安装 | https://deepseek-harness.github.io/deepseek-harness/develop/basic/tool | 官方 |
| 官方文档 · 插件与生命周期 / 服务与依赖 / 事件 | https://deepseek-harness.github.io/deepseek-harness/develop/framework/ | 官方 |
| 官方文档 · 能力的三层拆分 / LLM 适配器 / 持久化插件 | https://deepseek-harness.github.io/deepseek-harness/develop/practice/ | 官方 |
| 官方文档 · Extension Cookbook | https://deepseek-harness.github.io/deepseek-harness/reference/cookbook/extension-cookbook | 官方 |
| 官方文档 · 插件市场 | https://deepseek-harness.github.io/deepseek-harness/guide/plugin-market | 官方 |
GitHub dsh-plugin topic |
https://github.com/topics/dsh-plugin | 官方 |
| DSH 架构 · Where new behavior goes | https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/architecture.md | 官方 |
| SAFETY.md | https://github.com/deepseek-ai/deepseek-harness/blob/master/SAFETY.md | 官方 |