赞助商LobeHubLobeHub了解更多
ddshfind
登录

第 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一切的入口ctx.llm模型调用ctx.tools工具注册表ctx.sessions会话ctx.skills技能ctx.shell命令执行ctx.sandbox沙箱

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 既有代码也捆了技能),这很常见,不冲突。


关键点回顾

  1. 插件 = 一个导出 apply 的文件,框架调用它一次,把 ctx 递给你。
  2. DSH 没有碰不到的内核——模型、工具、界面、连主循环本身都是插件,地位平等。
  3. ctx 是唯一通道:用别人的能力从它上面取,提供新能力往它上面挂。
  4. 注册即可撤销ctx 上挂的东西会在卸载时被框架自动清干净;自己开的资源用 ctx.effect() 交代后事。
  5. 插件、技能、组合包是三样东西:加零件 / 加知识 / 定清单。

🚀 下一课:知道了「是什么」,来看「能干什么」——用生态里 275 个真实插件,看看这套机制的边界在哪。

自测题 · 插件是什么

完成作答后点击「提交答案」,可以查看对错与解析。

1. DSH 插件和浏览器扩展最本质的区别是什么?
2. `apply(ctx)` 里的 ctx 是干什么的?
3. 插件卸载时,之前通过 ctx 注册的事件监听和工具会怎样?
4. 「技能(skill)」和「插件(plugin)」的区别是?