第 1 课:插件到底是什么?
一句话版:DSH 插件就是一个导出
apply函数的文件——框架启动时把一个叫ctx的「万能插座」递给你,你往上挂东西(工具、界面、策略),挂上去的东西在插件卸载时会自动全部撤掉。就这么简单。
1. 先从你已经见过的插件说起
你大概率用过这些:
| 你见过的 | 它干的事 |
|---|---|
| 浏览器扩展(广告拦截器) | 给已经做好的浏览器加一个功能 |
| VSCode 插件(主题、语言支持) | 给已经做好的编辑器加一个功能 |
| 手机 App | 装在已经做好的手机系统上 |
它们有个共同点:主体是现成的,插件是贴在旁边的补丁。浏览器的地址栏、标签页、渲染引擎,扩展碰不到——那是「内核」,是写死的。
DSH 不一样。DSH 里没有那个碰不到的内核。
2. DSH 的不同之处:整个软件本身就是插件拼的
打开 DSH 的架构文档,第一行写着:
一切皆插件,循环也不例外。
「循环」指的是智能体的主循环——「想一下 → 干一件事 → 再想一下」那个转圈的东西。在别的框架里,这是内核,改不了。在 DSH 里,它也是一个插件,可以被换掉。
所以这些全都是插件,地位完全平等:
- 你用的哪个模型 → 一个插件
- 模型能调用的每个工具 → 一个插件
- 命令在哪儿执行、能不能碰你的文件 → 一个插件
- 聊天记录存在哪 → 一个插件
- 你看到的这个网页界面 → 几十个插件
- 上面提到的主循环 → 还是一个插件
🎁 打个比方:别的框架像一栋盖好的楼——想改户型得拆承重墙。DSH 像一盒乐高——任何一块都能单独抽出来换掉,包括你以为是地基的那块。
这就是为什么 DSH 的插件能干的事情远比「浏览器扩展」大:你不是在给一个成品加装饰,你是在替换这个成品的零件。
3. 一个插件长什么样
真的就这么点东西:
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
console.log('[hello-plugin] 我被装上了!')
}
三行有效代码,逐行拆开:
| 这一行 | 在说什么 |
|---|---|
export const name = ... | 给插件起个名字,出问题时日志里能认出你 |
export function apply(ctx) | 入口。框架装载你的时候会调用它,只调一次 |
ctx 参数 | 你和整个系统之间的唯一通道——所有能力都从这儿拿,所有贡献都往这儿挂 |
(来源:docs/user/develop/basic/index.zh.md)
4. ctx:一个万能插座
ctx 是这套体系里唯一需要你记住的概念。可以把它想成一块插线板,上面有很多插孔,每个插孔管一类能力:
ctx.xxx 就是 DSH 的 API 面:所有能力都挂在 ctx 这个入口上
| 插孔 | 管什么 |
|---|---|
ctx.tools | 模型能调用的工具 |
ctx.llm | 模型适配器(换模型从这儿换) |
ctx.shell | 命令执行 |
ctx.fs | 文件读写 |
ctx.sessions | 会话记录 |
ctx.skills | 技能 |
ctx.sandbox | 沙箱限制 |
两个方向都走 ctx:
- 想用别人的能力 → 从
ctx上取,比如ctx.llm.stream(...)调模型 - 想提供新能力 → 往
ctx上挂,比如ctx.tools.register(...)注册一个工具
所以「学会写插件」这件事,本质上就是「知道你要的东西挂在 ctx 的哪个插孔上」。第三章第 2 课专门讲 ctx,第三章第 10 课教你怎么按 ctx 键反查代码在哪个包里。
5. 最关键的一条规矩:装得上,就得卸得掉
这是 DSH 插件和普通插件最大的区别,也是它背后那篇论文的核心。
普通软件的插件,卸载往往是「半卸」:监听器还挂着、定时器还在跑、注册的菜单项还留着。时间一长,系统就脏了。
DSH 要求注册即可撤销——你通过 ctx 挂上去的一切,插件卸载时框架自动全部撤掉:
通过
ctx注册的任何东西——事件监听、工具、定时器——在插件卸载时都会被自动清理。你不需要手动 removeListener 或 clearInterval。——
docs/user/develop/basic/index.zh.md
如果你自己开了个框架不知道的资源(比如一条网络连接),就用 ctx.effect() 顺手告诉它怎么关:
export function apply(ctx: Context) {
ctx.effect(() => {
const timer = setInterval(() => console.log('心跳'), 5000)
// 返回的这个函数,会在插件卸载时被调用
return () => clearInterval(timer)
})
}
为什么这条这么重要? 因为它让「运行中改造自己」变成可能——不用重启,装一个插件试试,不合适就卸掉,系统干干净净回到原样。DSH 的智能体甚至能自己给自己装插件(第三章第 8 课讲这个)。
💡 记住这句话就够了:
ctx上的每一次注册,都会返回一张「后悔药」,框架替你收好,卸载时统一吃掉。
6. 别搞混:插件 / 技能 / 组合包
新手最容易在这三个词上打转,一张表说清:
| 名字 | 是什么 | 谁在读它 | 例子 |
|---|---|---|---|
| 插件(plugin) | 一段代码,往 ctx 上挂能力 | 框架 | 加一个 csv 工具 |
| 技能(skill) | 一份说明书(Markdown),教模型怎么做某件事 | 模型 | 「怎么写好一个 commit message」 |
| 组合包(bundle) | 一张清单,规定装哪些插件、什么顺序 | 启动器 | dsh-base 定义了默认那一大坨 |
一句话区分:插件给系统加零件,技能给模型加知识,组合包决定这次开机装哪些零件。
有些仓库同时是插件和技能(比如 dsh-genui 既有代码也捆了技能),这很常见,不冲突。
关键点回顾
- 插件 = 一个导出
apply的文件,框架调用它一次,把ctx递给你。 - DSH 没有碰不到的内核——模型、工具、界面、连主循环本身都是插件,地位平等。
ctx是唯一通道:用别人的能力从它上面取,提供新能力往它上面挂。- 注册即可撤销:
ctx上挂的东西会在卸载时被框架自动清干净;自己开的资源用ctx.effect()交代后事。 - 插件、技能、组合包是三样东西:加零件 / 加知识 / 定清单。
🚀 下一课:知道了「是什么」,来看「能干什么」——用生态里 275 个真实插件,看看这套机制的边界在哪。
自测题 · 插件是什么
完成作答后点击「提交答案」,可以查看对错与解析。
